./0000700000175000017500000000000012262740441007671 5ustar olesoles./ast-7.3.3/0000755000175000017500000000000012262740442011141 5ustar olesoles./ast-7.3.3/pointset.h0000644000175000017500000005134012262533650013163 0ustar olesoles#if !defined( POINTSET_INCLUDED ) /* Include this file only once */ #define POINTSET_INCLUDED /* *+ * Name: * pointset.h * Type: * C include file. * Purpose: * Define the interface to the PointSet class. * Invocation: * #include "pointset.h" * Description: * This include file defines the interface to the PointSet class * and provides the type definitions, function prototypes and * macros, etc. needed to use this class. * * The PointSet class encapsulates sets of coordinate values * representing points in an N-dimensional space, to which * coordinate transformations may be applied. It also provides * memory allocation facilities for coordinate values. * Inheritance: * The PointSet class inherits from the Object class. * Attributes Over-Ridden: * None. * New Attributes Defined: * Ncoord (integer) * A read-only attribute that gives the number of coordinates * for each point in a PointSet (i.e. the number of dimensions * of the space in which the points reside). This value is * determined when the PointSet is created. * Npoint (integer) * A read-only attribute that gives the number of points that * can be stored in the PointSet. This value is determined when * the PointSet is created. * PointAccuracy (floating point) * This stores the absolute accuracies for each axis in the PointSet. * Methods Over-Ridden: * Public: * None. * * Protected: * ClearAttrib * Clear an attribute value for a PointSet. * GetAttrib * Get an attribute value for a PointSet. * SetAttrib * Set an attribute value for a PointSet. * TestAttrib * Test if an attribute value has been set for a PointSet. * New Methods Defined: * Public: * astAppendPoints * Append one PointSet to another. * astBndPoints * Find the axis bounds of the points in a PointSet. * astGetPoints * Get a pointer to the coordinate values associated with a PointSet. * astPermPoints * Permute coordinates within a PointSet. * astSetPoints * Associate coordinate values with a PointSet. * astSetNpoint * Reduce the size of a PointSet. * astSetSubPoints * Associate one PointSet with a subset of another. * * Protected: * astGetNpoint * Get the number of points in a PointSet. * astGetNcoord * Get the number of coordinate values per point from a PointSet. * astGetPointAccuracy * Get the curent value of the PointAcuracy attribute for an axis. * astSetPointAccuracy * Set a new value for the PointAcuracy attribute for an axis. * astTestPointAccuracy * Test the value of the PointAcuracy attribute for an axis. * astClearPointAccuracy * Clear the value of the PointAcuracy attribute for an axis. * Other Class Functions: * Public: * astIsAPointSet * Test class membership. * astPointSet * Create a PointSet. * * Protected: * astCheckPointSet * Validate class membership. * astInitPointSet * Initialise a PointSet. * astInitPointSetVtab * Initialise the virtual function table for the PointSet class. * astLoadPointSet * Load a PointSet. * Macros: * Public: * AST__BAD * Bad value flag for coordinate data. * * Protected: * astISBAD * Check if a value is AST__BAD or NaN. * astISGOOD * Check if a value is not AST__BAD or NaN. * astISNAN * Check if a value is NaN. * Type Definitions: * Public: * AstPointSet * PointSet object type. * * Protected: * AstPointSetVtab * PointSet virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 30-JAN-1996 (RFWS): * Original version. * 27-SEP-1996 (RFWS): * Added external interface and I/O facilities. * 8-JAN-2003 (DSB): * Added protected astInitPointSetVtab method. * 2-NOV-2004 (DSB): * Added PointAccuracy attribute. *- */ /* Include files. */ /* ============== */ /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ /* C header files. */ /* --------------- */ #include #if defined(astCLASS) /* Protected */ #include #include #if !HAVE_DECL_ISNAN # if HAVE_ISNAN /* Seems that math.h does not include a prototype for isnan etc */ int isnan( double ); # else /* isnan is not available prior to C99 so define alternative macros Note multiple evaluations of "x" in these macros!!! */ # define isnan(x) ((x) != (x)) # endif #endif #if !HAVE_DECL_ISFINITE # if HAVE_ISFINITE /* Seems that math.h does not include a prototype for isfinite */ int isfinite( double ); # else /* isfinite is not available prior to C99 so define alternative macros. Note multiple evaluations of "x" in these macros!!! */ # define isfinite(x) (!isnan(x) && ((x) != (1.0/0.0)) && ((x) != (-1.0/0.0))) # endif #endif #endif /* Macros. */ /* ======= */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif /* *+ * Name: * AST__BAD * Type: * Public macro. * Purpose: * Bad value flag for coordinate data. * Synopsis: * #include "pointset.h" * const double AST__BAD * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a const double value that is used to flag * coordinate values that are "bad" (i.e. undefined or * meaningless). Classes that implement coordinate transformations * should test coordinate values against this value, and * appropriately propagate bad values to their output. *- */ /* Define AST__BAD to be the most negative (normalised) double value. */ #define AST__BAD (-(DBL_MAX)) /* *+ * Name: * AST__NAN * Type: * Public macro. * Purpose: * A value representing the double precision IEEE NaN value. * Synopsis: * #include "pointset.h" * const double AST__NAN * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a const double value that is used to indicate * that a IEEE NaN value should be used. Note, AST__NAN itself is a finite * double precision floating point value a little below the maximum * allowed value for a double. This value can be used as flag to * indicate that the corresponding IEEE NaN value should be used in its * place. *- */ #define AST__NAN (-(0.95*DBL_MAX)) /* *+ * Name: * AST__NANF * Type: * Public macro. * Purpose: * A value representing the single precision IEEE NaN value. * Synopsis: * #include "pointset.h" * const double AST__NANF * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a const float value that is used to indicate * that a IEEE NaN value should be used. Note, AST__NANF itself is a finite * single precision floating point value a little below the maximum * allowed value for a float. This value can be used as flag to * indicate that the corresponding IEEE NaN value should be used in its * place. *- */ #define AST__NANF ((float)-(0.95*FLT_MAX)) #if defined(astCLASS) /* Protected */ /* *+ * Name: * astISNAN * Type: * Protected macro. * Purpose: * Test if a double is NaN. * Synopsis: * #include "pointset.h" * astISNAN(value) * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a integer valued expression which is zero * if and only if the supplied value equals NaN ("Not a Number"). * Parameters: * value * The value to be tested. This should be a double. * Examples: * if( astISNAN(x) ) x = AST__BAD; * If "x" is NaN replace it with AST__BAD. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. * - On some system it is possible that the supplied macro argument * "x" may be evaluated multiple times. Therefore the evaluation of "x" * should have no side effects. *- */ #define astISNAN(value) isnan(value) /* *+ * Name: * astISFINITE * Type: * Protected macro. * Purpose: * Test if a double is neither NaN nor Inf. * Synopsis: * #include "pointset.h" * astISFINITE(value) * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a integer valued expression which is zero * if and only if the supplied value equals NaN ("Not a Number") or Inf. * Parameters: * value * The value to be tested. This should be a double. * Examples: * if( !astISFINITE(x) ) x = AST__BAD; * If "x" is NaN or Inf replace it with AST__BAD. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. * - On some system it is possible that the supplied macro argument * "x" may be evaluated multiple times. Therefore the evaluation of "x" * should have no side effects. *- */ #define astISFINITE(value) isfinite(value) /* *+ * Name: * astISGOOD * Type: * Protected macro. * Purpose: * Test if a double is neither AST__BAD, NaN or Inf. * Synopsis: * #include "pointset.h" * astISGOOD(value) * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a integer valued expression which is zero * if and only if the supplied value equals AST__BAD or is NaN ("Not a * Number") or "Inf". * Parameters: * value * The value to be tested. This should be a double. * Examples: * if( astISGOOD(x) ) y = x; * Checks that "x" is usable before assigning it to y. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. * - On some system it is possible that the supplied macro argument * "x" may be evaluated multiple times. Therefore the evaluation of "x" * should have no side effects. *- */ #define astISGOOD(value) ( (value) != AST__BAD && astISFINITE(value) ) /* *+ * Name: * astISBAD * Type: * Protected macro. * Purpose: * Test if a double is either AST__BAD, NaN, or Inf. * Synopsis: * #include "pointset.h" * astISBAD(value) * Class Membership: * Defined by the PointSet class. * Description: * This macro expands to a integer valued expression which is non-zero * if and only if the supplied value equals AST__BAD or is NaN ("Not a * Number"), or is Inf. * Parameters: * value * The value to be tested. This should be a double. * Examples: * if( astISBAD(x) ) astError( ... ); * Reports an error if "x" is bad. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. * - On some system it is possible that the supplied macro argument * "x" may be evaluated multiple times. Therefore the evaluation of "x" * should have no side effects. *- */ #define astISBAD(value) ( (value) == AST__BAD || !astISFINITE(value)) #endif /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* PointSet structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstPointSet { /* Attributes inherited from the parent class. */ AstObject object; /* Parent class structure */ /* Attributes specific to objects in this class. */ double **ptr; /* Pointer to array of pointers to values */ double *values; /* Pointer to array of coordinate values */ int ncoord; /* Number of coordinate values per point */ int npoint; /* Number of points */ double *acc; /* Axis accuracies */ } AstPointSet; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstPointSetVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstObjectVtab object_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ AstPointSet *(* AppendPoints)( AstPointSet *, AstPointSet *, int * ); double **(* GetPoints)( AstPointSet *, int * ); int (* GetNcoord)( const AstPointSet *, int * ); int (* GetNpoint)( const AstPointSet *, int * ); void (* BndPoints)( AstPointSet *, double *, double *, int * ); void (* PermPoints)( AstPointSet *, int, const int[], int * ); void (* SetNpoint)( AstPointSet *, int, int * ); void (* SetPoints)( AstPointSet *, double **, int * ); void (* SetSubPoints)( AstPointSet *, int, int, AstPointSet *, int * ); int (* ReplaceNaN)( AstPointSet *, int * ); double (* GetPointAccuracy)( AstPointSet *, int, int * ); int (* TestPointAccuracy)( AstPointSet *, int, int * ); void (* ClearPointAccuracy)( AstPointSet *, int, int * ); void (* SetPointAccuracy)( AstPointSet *, int, double, int * ); } AstPointSetVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstPointSetGlobals { AstPointSetVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstPointSetGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(PointSet) /* Check class membership */ astPROTO_ISA(PointSet) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstPointSet *astPointSet_( int, int, const char *, int *, ...); #else AstPointSet *astPointSetId_( int, int, const char *, ... )__attribute__((format(printf,3,4))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstPointSet *astInitPointSet_( void *, size_t, int, AstPointSetVtab *, const char *, int, int, int * ); /* Vtab initialiser. */ void astInitPointSetVtab_( AstPointSetVtab *, const char *, int * ); /* Loader. */ AstPointSet *astLoadPointSet_( void *, size_t, AstPointSetVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitPointSetGlobals_( AstPointSetGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ double **astGetPoints_( AstPointSet *, int * ); void astPermPoints_( AstPointSet *, int, const int[], int * ); void astSetPoints_( AstPointSet *, double **, int * ); void astSetNpoint_( AstPointSet *, int, int * ); void astSetSubPoints_( AstPointSet *, int, int, AstPointSet *, int * ); AstPointSet *astAppendPoints_( AstPointSet *, AstPointSet *, int * ); void astBndPoints_( AstPointSet *, double *, double *, int * ); int astReplaceNaN_( AstPointSet *, int * ); # if defined(astCLASS) /* Protected */ int astGetNcoord_( const AstPointSet *, int * ); int astGetNpoint_( const AstPointSet *, int * ); double astGetPointAccuracy_( AstPointSet *, int, int * ); int astTestPointAccuracy_( AstPointSet *, int, int * ); void astClearPointAccuracy_( AstPointSet *, int, int * ); void astSetPointAccuracy_( AstPointSet *, int, double, int * ); double astCheckNaN_( double ); float astCheckNaNF_( float ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckPointSet(this) astINVOKE_CHECK(PointSet,this,0) #define astVerifyPointSet(this) astINVOKE_CHECK(PointSet,this,1) /* Test class membership. */ #define astIsAPointSet(this) astINVOKE_ISA(PointSet,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astPointSet astINVOKE(F,astPointSet_) #else #define astPointSet astINVOKE(F,astPointSetId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitPointSet(mem,size,init,vtab,name,npoint,ncoord) \ astINVOKE(O,astInitPointSet_(mem,size,init,vtab,name,npoint,ncoord,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitPointSetVtab(vtab,name) astINVOKE(V,astInitPointSetVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadPointSet(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadPointSet_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckPointSet to validate PointSet pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astGetPoints(this) \ astINVOKE(V,astGetPoints_(astCheckPointSet(this),STATUS_PTR)) #define astPermPoints(this,forward,perm) \ astINVOKE(V,astPermPoints_(astCheckPointSet(this),forward,perm,STATUS_PTR)) #define astSetPoints(this,ptr) \ astINVOKE(V,astSetPoints_(astCheckPointSet(this),ptr,STATUS_PTR)) #define astSetNpoint(this,np) \ astINVOKE(V,astSetNpoint_(astCheckPointSet(this),np,STATUS_PTR)) #define astSetSubPoints(point1,point,coord,point2) \ astINVOKE(V,astSetSubPoints_(astCheckPointSet(point1),point,coord,astCheckPointSet(point2),STATUS_PTR)) #define astAppendPoints(this,that) \ astINVOKE(O,astAppendPoints_(astCheckPointSet(this),astCheckPointSet(that),STATUS_PTR)) #define astBndPoints(this,lbnd,ubnd) \ astINVOKE(V,astBndPoints_(astCheckPointSet(this),lbnd,ubnd,STATUS_PTR)) #define astReplaceNaN(this) \ astINVOKE(V,astReplaceNaN_(astCheckPointSet(this),STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astGetNpoint(this) \ astINVOKE(V,astGetNpoint_(astCheckPointSet(this),STATUS_PTR)) #define astGetNcoord(this) \ astINVOKE(V,astGetNcoord_(astCheckPointSet(this),STATUS_PTR)) #define astClearPointAccuracy(this,axis) \ astINVOKE(V,astClearPointAccuracy_(astCheckPointSet(this),axis,STATUS_PTR)) #define astGetPointAccuracy(this,axis) \ astINVOKE(V,astGetPointAccuracy_(astCheckPointSet(this),axis,STATUS_PTR)) #define astSetPointAccuracy(this,axis,value) \ astINVOKE(V,astSetPointAccuracy_(astCheckPointSet(this),axis,value,STATUS_PTR)) #define astTestPointAccuracy(this,axis) \ astINVOKE(V,astTestPointAccuracy_(astCheckPointSet(this),axis,STATUS_PTR)) #define astCheckNaNF(value) astCheckNaNF_(value) #define astCheckNaN(value) astCheckNaN_(value) #endif #endif ./ast-7.3.3/specmap.h0000644000175000017500000002066112262533650012750 0ustar olesoles#if !defined( SPECMAP_INCLUDED ) /* Include this file only once */ #define SPECMAP_INCLUDED /* *+ * Name: * specmap.h * Type: * C include file. * Purpose: * Define the interface to the SpecMap class. * Invocation: * #include "specmap.h" * Description: * This include file defines the interface to the SpecMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The SpecMap class encapsulates various ecptral coordinate * conversions. Since, typically, a sequence of these conversions is * required, a SpecMap can be used to accumulate a series of conversions * which it then applies in sequence. * Inheritance: * The SpecMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * astTransform * Use an SpecMap to transform a set of points. * Protected: * astMapMerge * Simplify a sequence of Mappings containing an SpecMap. * New Methods Defined: * Public: * astSpecAdd * Add a coordinate conversion step to an SpecMap. * Private: * None. * Other Class Functions: * Public: * astIsASpecMap * Test class membership. * astSpecMap * Create an SpecMap. * Protected: * astCheckSpecMap * Validate class membership. * astInitSpecMap * Initialise an SpecMap. * astLoadSpecMap * Load an SpecMap. * Macros: * None. * Type Definitions: * Public: * AstSpecMap * SpecMap object type. * Protected: * AstSpecMapVtab * SpecMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 8-NOV-2002 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ------ */ /* Physical constants taken from Chapter 15 of the "Explanatory Supplement to the Astronomical Ephemeris". */ #define AST__C 2.99792458E8 /* Speed of light (metres per second) */ #define AST__H 6.6260755E-34 /* Plank constant (Joule.seconds) */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* SpecMap structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstSpecMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ int *cvttype; /* Pointer to array of conversion types */ double **cvtargs; /* Pointer to argument list pointer array */ int ncvt; /* Number of conversions to perform */ } AstSpecMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstSpecMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* SpecAdd)( AstSpecMap *, const char *, const double[], int * ); } AstSpecMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstSpecMapGlobals { AstSpecMapVtab Class_Vtab; int Class_Init; } AstSpecMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitSpecMapGlobals_( AstSpecMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(SpecMap) /* Check class membership */ astPROTO_ISA(SpecMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstSpecMap *astSpecMap_( int, int, const char *, int *, ...); #else AstSpecMap *astSpecMapId_( int, int, const char *, ... )__attribute__((format(printf,3,4))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstSpecMap *astInitSpecMap_( void *, size_t, int, AstSpecMapVtab *, const char *, int, int, int * ); /* Vtab initialiser. */ void astInitSpecMapVtab_( AstSpecMapVtab *, const char *, int * ); /* Loader. */ AstSpecMap *astLoadSpecMap_( void *, size_t, AstSpecMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astSpecAdd_( AstSpecMap *, const char *, const double[], int * ); /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckSpecMap(this) astINVOKE_CHECK(SpecMap,this,0) #define astVerifySpecMap(this) astINVOKE_CHECK(SpecMap,this,1) /* Test class membership. */ #define astIsASpecMap(this) astINVOKE_ISA(SpecMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astSpecMap astINVOKE(F,astSpecMap_) #else #define astSpecMap astINVOKE(F,astSpecMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitSpecMap(mem,size,init,vtab,name,nin,flags) \ astINVOKE(O,astInitSpecMap_(mem,size,init,vtab,name,nin,flags,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitSpecMapVtab(vtab,name) astINVOKE(V,astInitSpecMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadSpecMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadSpecMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckSpecMap to validate SpecMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astSpecAdd(this,cvt,args) \ astINVOKE(V,astSpecAdd_(astCheckSpecMap(this),cvt,args,STATUS_PTR)) #endif ./ast-7.3.3/ast.news0000644000175000017500000011441112262533650012631 0ustar olesolesAST Library ----------- A new release (V7.3.3) of the Starlink AST (astrometry) library is now available. AST provides a comprehensive range of facilities for attaching world coordinate systems (such as RA/Dec, frequency, etc) to astronomical data, for retrieving and interpreting that information and for generating graphical output based on it. The library should be of interest to anyone writing astronomical software which needs to manipulate coordinate system data, especially celestial coordinate systems. AST is portable and environment-independent. Main Changes in this Version ---------------------------- - The FitsChan class has new attributes CardName and CardComm, which hold the keyword name and comment of the current card. - When reading FITS-WCS headers that include polynomial distortion in the SIP format, any inverse transformation specified in the header is now ignored and a new inverse is created to replace it based on the supplied forward transformation. Previously, an inverse was created only if the header did not include an inverse. The accuracy of the inverse transformation has also been improved, although it may now be slower to evaluate in some circumstances. - A bug has been fixed that could over-write the FitsChan CarLin attribute with a non-zero value if the header contains a spectral axis. - The default options for each newly created FitsChan can now be specified via the environment variable FITSCHAN_OPTIONS. Main Changes in V7.3.2 ---------------------- - Fix support for reading GLS projections from FITS headers. - The KeyMap class has new sorting options "KeyAgeUp" and "KeyAgeDown" that retain the position of an existing entry if its value is changed. See the SortBy attribute. - A bug has been fixed in FitsChan that caused CDELT keywords for sky axes to be treated as radians rather than degrees when reading a FITS header, if the corresponding CTYPE values included no projection code. Main Changes in V7.3.1 ---------------------- - Fix bug that could cause a segmenatation fault when reading a FITS TNX header. Main Changes in V7.3.0 ---------------------- - IMPORTANT! The interface for the astRebinSeq (AST_REBINSEQ) family of functions has been changed in order to allow a greater number of pixels to be pasted into the output array. In C, the "nused" parameter is now a pointer to a "int64_t" variable, instead of a simple "int". In Fortran, the NUSED argument for AST_REBINSEQ is now an INTEGER*8. APPLICATION CODE SHOULD BE CHANGED ACCORDINGLY TO AVOID SEGMENTATION FAULTS AND OTHER ERRATIC BEHAVIOUR. - Added a new facility to the FrameSet class to allow each Frame to be associated with multiple Mappings, any one of which can be used to connect the Frame to the other Frames in the FrameSet. The choice of which Mapping to use is controlled by the new "Variant" attribute of the FrameSet class. - Mappings (but not Frames) that have a value set for their Ident attribute are now left unchanged by the astSimplify (AST_SIMPLIFY) function. Main Changes in V7.2.0 ---------------------- - A new method call astMapDefined has been added to the KeyMap class. It checks if a gtiven key name has a defined value in a given KeyMap. Main Changes in V7.1.1 ---------------------- - A bug has been fixed in FitsChan that caused inappropriate CTYPE values to be generated when writing a FrameSet to FITS-WCS headers if the current Frame describes generalised spherical coordinates (i.e. a SkyFrame with System=Unknown). - When a FitsChan is used to write an "offset" SkyFrame (see attribute SkyRefIs) to a FITS-WCS encoded header, two alternate axis descriptions are now created - one for the offset coordinates and one for the absolute coordinates. If such a header is subsequently read back into AST, the original offset SkyFrame is recreated. Main Changes in V7.1.0 ---------------------- - IMPORTANT! The default behaviour of astRebinSeq is now NOT to conserve flux. To conserve flux, the AST__CONSERVEFLUX flag should be supplied when calling astRebinSeq. Without this flag, each output value is a weighted mean of the neighbouring input values. - A new flag AST__NONORM can be used with astRebinSeq to indicate that normalisation of the output arrays is not required. In this case no weights array need be supplied. - A bug has been fixed in astAddFrame (AST_ADDFRAME) method that could result in the incorrect inversion of Mappings within the FrameSet when the AST__ALLFRAMES flag is supplied for the "iframe" parameter. - The astRate method has been re-written to make it faster and more reliable. Main Changes in V7.0.6 ---------------------- - A bug has been fixed in astRebinSeq which could result in incorrect normalisation of the final binned data and variance values. - When reading a FrameSet from a FITS-DSS header, the keywords CNPIX1 and CNPIX2 now default to zero if absent. Previously an error was reported. Main Changes in V7.0.5 ---------------------- - The FitsChan class can now read FITS headers that use the SAO convention for representing distorted TAN projections, based on the use of "COi_j" keywords to hold the coefficients of the distortion polynomial. Main Changes in V7.0.4 ---------------------- - The previously private grf3d.h header file is now installed into prefix/include. Main Changes in V7.0.3 ---------------------- - A bug has been fixed which could cause an incorrect axis to be used when accessing axis attributes within CmpFrames. This could happen if axes within the CmpFrame have been permuted. - A bug has been fixed in the SkyFrame class that could cause the two values of the SkyRef and/or SkyRefP attributes to be reversed. - Bugs have been fixed in the CmpRegion class that should allow the border around a compound Region to be plotted more quickly, and more accurately. Previously, component Regions nested deeply inside a CmpRegion may have been completely or partially ignored. - A bug has been fixed in the Plot3D class that caused a segmentation violation if the MinTick attribute was set to zero. - The astResampleX set of methods now includes astResampleK and astResampleUK that handles 64 bit integer data. Main Changes in V7.0.2 ---------------------- - The libast_pal library is no longer built if the "--with-external_pal" option is used when AST is configured. Main Changes in V7.0.1 ---------------------- - The levmar and wcslib code distributed within AST is now stored in the main AST library (libast.so) rather than in separate libraries. Main Changes in V7.0.0 ---------------------- - Fundamental positional astronomy calculations are now performed using the IAU SOFA library where possible, and the Starlink PAL library otherwise (the PAL library contains a subset of the Fortran Starlink SLALIB library re-written in C). Copies of these libraries are bundled with AST and so do not need to be obtained or built separately, although external copies of SOFA and PAL can be used if necessary by including the "--with-external_pal" option when configuring AST. Main Changes in V6.0-1 ----------------------- - The Spitzer "-SIP" distortion code is now recognised within FITS headers that describe non-celestial axes, as well as celestial axes. - A bug has been fixed that could cause inappropriate equinox values to be used when aligning SkyFrames if the AlignSystem attribute is set. - The format of the version string for AST has changed from ".-" to "..". Main Changes in V6.0 ----------------------- - This version of AST is the first that can be used with the Python AST wrapper module, starlink.Ast, available at http://github.com/timj/starlink-pyast. - When reading a FITS-WCS header, the FitsChan class now recognises the non-standard "TPV" projection code within a CTYPE keyword value. This code is used by SCAMP (see www.astromatic.net/software/scamp) to represent a distorted TAN projection. - The Plot class has been changed to remove visual anomalies (such as incorrectly rotated numerical axis labels) if the graphics coordinates have unequal scales on the X and Y axes. - The graphics escape sequences used to produce graphical sky axis labels can now be changed using the new function astTuneC (AST_TUNEC). Main Changes in V5.7-2 ----------------------- - The PolyMap class can now use an iterative Newton-Raphson method to evaluate the inverse the inverse transformation if no inverse transformation is defined when the PolyMap is created. - The FitsChan class has a new method astWriteFits (AST_WRITEFITS) which writes out all cards currently in the FitsChan to the associated external data sink (specified either by the SinkFile attribute or the sink function supplied when the FitsChan was created), and then empties the FitsChan. - The FitsChan class has a new method astReadFits (AST_READFITS) which forces the FitsChan to reads cards from the associated external source and appends them to the end of the FitsChan. - The FitsChan class has a new read-only attribute called "Nkey", which holds the number of keywords for which values are held in a FitsChan. - The FitsChan class has a new read-only attribute called "CardType", which holds the data type of the keyword value for the current card. - The FitsChan astGetFits (AST_GETFITS) methods can now be used to returned the value of the current card. - If the FitsChan astRead method reads a FITS header that uses the -SIP (Spitzer) distortion code within the CTYPE values, but which does not provide an inverse polynomial correction, and for which the PolyTran method of the PolyMap class fails to create an accurate estimate of the inverse polynomial correction, then an iterative method will be used to evaluate the inverse correction for each point transformed. - The Object class has a new function astToString (C only), which creates an in-memory textual serialisation of a given AST Object. A corresponding new function called astFromString re-creates the Object from its serialisation. Main Changes in V5.7-1 ----------------------- - All classes of Channel can now read to and write from specified text files, without the need to provide source and sink functions when the Channel is created. The files to use are specified by the new attributes SourceFile and SinkFile. - The FitsChan class now ignores trailing spaces in character-valued WCS keywords when reading a FrameSet from a FITS header. - If the FitsChan astRead method reads a FITS header that uses the -SIP (Spitzer) distortion code within the CTYPE values, but which does not provide an inverse polynomial correction, the FitsChan class will now use the PolyTran method of the PolyMap class to create an estimate of the inverse polynomial correction. Main Changes in V5.7-0 ----------------------- - The FitsChan class support for the IRAF-specific "TNX" projection has been extended to include reading TNX headers that use a Chebyshev representation for the distortion polynomial. - The FitsChan class support for the IRAF-specific "ZPX" projection has been extended to include reading ZPX headers that use simple or Chebyshev representation for the distortion polynomial. - A bug has been fixed in the FitsChan class that caused headers including the Spitzer "-SIP" distortion code to be read incorrectly if no inverse polynomial was specified in the header. - A new attribute called PolyTan has been added to the FitsChan class. It can be used to indicate that FITS headers that specify a TAN projection should be interpreted according to the "distorted TAN" convention included in an early draft of FITS-WCS paper II. Such headers are created by (for instance) the SCAMP tool (http://www.astromatic.net/software/scamp). - The PolyMap class now provides a method called astPolyTran (AST_POLYTRAN) that adds an inverse transformation to a PolyMap by sampling the forward transformation on a regular grid, and then fitting a polynomial function from the resulting output values to the grid of input values. Main Changes in V5.6-1 ----------------------- - Tables can now have any number of parameters describing the global properties of the Table. - Frames now interpret the unit string "A" as meaning "Ampere" rather than "Angstrom", as specified by FITS-WCS paper I. - A bug has been fixed in the astFindFrame (AST_FINDFRAME) method that allowed a template Frame of a more specialised class to match a target frame of a less specialised class. For example, this bug would allow a template SkyFrame to match a target Frame. This no longer happens. Main Changes in V5.6-0 ----------------------- - New functions astBBuf (AST_BBUF) and astEBuf (AST_EBUF) have been added to the Plot class. These control the buffering of graphical output produced by other Plot methods. - New functions astGBBuf and astGEBuf have been added to the interface defined by file grf.h. The ast_link command has been modified so that the -grf_v3.2 switch loads dummy versions of the new grf functions. This means that applications that use the -grf_v3.2 switch should continue to build without any change. However, the new public functions astBBuf and astEBuf described in the previous item will report an error unless the new grf functions are implemented. If you choose to implement them, you should modify your linking procedure to use the -grf (or -grf_v5.6) switch in place of the older -grf_v3.2 switch. See the description of the ast_link command for details of these switches. - New method astGetRegionMesh (AST_GETREGIONMESH) returns a set of positions covering the boundary, or volume, of a supplied Region. Main Changes in V5.5-0 ----------------------- - The FitsChan "TabOK" attribute is now an integer value rather than a boolean value. As in previous versions, it is used to indicate whether the "-TAB" algorithm should be supported by the astRead (AST_READ) and astWrite (AST_WRITE) methods, but in addition it is now also used to give the version number to assign to any table gebnerated as a consequence of calling astWrite (AST_WRITE). A negative or zero value (the default) indicates that support for the -TAB algorithm is not available, where as a positive non-zero value indicates that support is available and also gives the table version number to use when creating subsequent -TAB headers. Main Changes in V5.4-0 ----------------------- - The FitsChan class now has an option to support reading and writing of FITS-WCS headers that use the -TAB algorithm described in FITS-WCS paper III. This option is controlled by a new FitsChan attribute called TabOK. See the documentation for TabOK for more information. - A new class called "Table" has been added. A Table is a KeyMap in which each entry represents a cell in a two-dimensional table. - A new class called "FitsTable" has been added. A FitsTable is a Table that has an associated FitsChan holding headers appropriate to a FITS binary table. - KeyMaps can now hold byte (i.e. "unsigned char" or BYTE) values. - A new method called astMapRename (AST_MAPRENAME) has been added to rename an existing entry in a KeyMap. - KeyMaps have a new attribute called KeyCase that can be set to zero to make the handling of keys case insensitive. Main Changes in V5.3-2 ----------------------- - A bug has been fixed in the FitsChan class that could cause wavelength axes to be assigned the units "m/s" when reading WCS information from a FITS header. - The astSet function (AST_SET) now allows literal commas to be included in string attribute values. String attribute values that include a literal comma should be enclosed in quotation marks. - A bug in FitsChan has been fixed that caused "-SIN" projection codes within FITS-WCS headers to be mis-interpreted, resulting in no FrameSet being read by astRead. - The KeyMap class has a new attribute called "SortBy". It controls the order in which keys are returned by the astMapKey (AST_MAPKEY) function. Keys can be sorted alphabetically or by age, or left unsorted. - Access to KeyMaps holding thousands of entries is now significantly faster. - KeyMaps can now hold word (i.e. "short int" or INTEGER*2) values. Main Changes in V5.3-1 ----------------------- - The KeyMap class has a new method called astMapCopy/AST_MAPCOPY that copies entries from one KeyMap to another KeyMap. - The KeyMap class now supports entries that have undefined values. A new method called astMapPutU/AST_MAPPUTU will store an entry with undefined value in a keymap. - The KeyMap class has a new boolean attribute called MapLocked. If true (non-zero), an error is reported if an attempt is made to add any new entries to a KeyMap (the value associated with any old entry may still be changed # without error). The default is false (zero). - The Object class has a new method called astHasAttribute/AST_HASATTRIBUTE that returns a boolean value indicating if a specified Object has a named attribute. - The SkyFrame class has two new read-only boolean attributes called IsLatAxis and IsLonAxis that can be used to determine the nature of a specified SkyFrame axis. - A bug has been fixed in the astRebin(Seq)/AST_REBIN(SEQ) methods that could cause flux to be lost from the edges of the supplied array. - A bug has been fixed in the astRebin(Seq)/AST_REBIN(SEQ) methods that caused the first user supplied parameter to be interpreted as the full width of the spreading kernel, rather than the half-width. - The StcsChan class now ignores case when reading STC-S phrases (except that units strings are still case sensitive). - The Channel class now has an Indent attribute that controls indentation in the text created by astWrite/AST_WRITE. The StcsIndent and XmlIndent attributes have been removed. - All classes of Channel now use the string "" to represent the floating point value AST__BAD, rather than the literal formatted value (typically "-1.79769313486232e+308" ). - The KeyMap class now uses the string "" to represent the floating point value AST__BAD, rather than the literal formatted value (typically "-1.79769313486232e+308" ). - The KeyMap class has a new method called astMapPutElem/AST_MAPPUTELEM that allows a value to be put into a single element of a vector entry in a KeyMap. The vector entry is extended automatically to hold the new element if required. - The DSBSpecFrame class now reports an error if the local oscillator frequency is less than the absoliute value of the intermediate frequency. - A new method astQuadApprox produces a quadratic fit to a 2D Mapping. - A new method astSkyOffsetMap produces a Mapping from absolute SkyFrame coordinates to offset SkyFrame coordinates. Main Changes in Version 5.3 --------------------------- - The details of how a Frame is aligned with another Frame by the astFindFrame and astConvert (AST_FINDFRAME and AST_CONVERT) functions have been changed. The changes mean that a Frame can now be aligned with an instance of a sub-class of Frame, so long as the number of axes and the Domain values are consistent. For instance, a basic 2-dimensional Frame with Domain "SKY" will now align succesfully with a SkyFrame, conversion between the two Frames being achieved using a UnitMap. - The arrays that supply input values to astMapPut1 are now declared "const". - Added method astMatchAxes (AST_MATCHAXES) to the Frame class. This allows corresponding axes in two Frames to be identified. - The astAddFrame (AST_ADDFRAME) method can now be used to append one or more axes to all Frames in a FrameSet. Main Changes in Version 5.1 --------------------------- - A new method called astSetFitsCM (AST_SETFITSCM) has been added to the FitsChan class. It stores a pure comment card in a FitsChan (that is, a card with no keyword name or equals sign). - A new attribute called ObsAlt has been added to the Frame class. It records the geodetic altitude of the observer, in metres. It defaults to zero. It is used when converting times to or from the TDB timescale, or converting spectral positions to or from the topocentric rest frame, or converting sky positions to or from horizon coordinates. The FitsChan class will include its effect when creating a set of values for the OBSGEO-X/Y/Z keywords, and will also assign a value to it when reading a set of OBSGEO-X/Y/Z keyword values from a FITS header. - The TimeMap conversions "TTTOTDB" and "TDBTOTT", and the SpecMap conversions "TPF2HL" and "HLF2TP", now have an additional argument - the observer's geodetic altitude. - The Polygon class has been modified to make it consistent with the IVOA STC definition of a Polygon. Specifically, the inside of a polygon is now the area to the left of each edge as the vertices are traversed in an anti-clockwise manner, as seen from the inside of the celestial sphere. Previously, AST used the anti-clockwise convention, but viewed from the outside of the celestial sphere instead of the inside. Any Polygon saved using previous versions of AST will be identified and negated automatically when read by AST V5.2. - A new class of Channel, called StcsChan, has been added that allows conversion of suitable AST Objects to and from IVOA STC-S format. - A new method called astDownsize (AST_DOWNSIZE) has been added to the Polygon class. It produces a new Polygon that contains a subset of the vertices in the supplied Polygon. The subset is chosen to retain the main features of the supplied Polygion, in so far as that is possible, within specified constraints. - A new constructor called astOutline (AST_OUTLINE) has been added to the Polygon class. Given a 2D data array, it identifies the boundary of a region within the array that holds pixels with specified values. It then creates a new Polygon to describe this boundary to a specified accuracy. - A new method called astRemoveRegions (AST_REMOVEREGIONS) has been added to the Mapping class. It removes the masking effects of any Regions found within a (possibly compound) Mapping or Frame. In effect, it replaces each Region found within the Mapping or Frame with a UnitMap or equivalent Frame. - A new set of methods, called astMapGetElem (AST_MAPGETELEM) has been added to the KeyMap class. They allow a single element of a vector valued entry to be returned. - A new attribute called KeyError has been added to the KeyMap Class. It controls whether the astMapGet... (AST_MAPGET...) family of functions report an error if an entry with the requested key does not exist in the KeyMap. Main Changes in Version 5.1 --------------------------- - The astUnlock function now has an extra parameter that controls whether or not an error is reported if the Object is currently locked by another thread. - The values of the AST__THREADSAFE macro (defined in ast.h) have been changed from "yes" and "no" to "1" and "0". - The PointList class has a new method, astPoints, that copies the axis values from the PointList into a supplied array. - The PointList class has a new (read-only) attribute, ListSize, that gives the number of points stored in the PointList. - A new method (astIntersect) has been added to the Frame class. It determines the position at which two geodesic curves intersect. - The XmlStrict attribute and astXmlWarnings function have been removed. The same functionality is now available via the existing Strict attribute, a new attribute called ReportLevel, and a new function called astWarnings. - A bug in the type-checking of Objects passed as arguments to constructor functions has been fixed. This bug could lead to applications crashing or showing strange behaviour if an inappropriate class of Object was supplied as an argument to a constructor. - The astPickAxes function will now return a Region, if possible, when applied to a Region. If this is not possible, a Frame will be returned as before. - The default gap size between the ISO date/time labels used by the Plot class when displaying an annotated axis described by a TimeFrame has been changed. The changes are meant to improve the labelling of calendar time axes that span intervals from a day to a few years. Main Changes in Version 5.0 --------------------------- - AST is now thread-safe. Many of the macro definitions in the "ast.h" header file have changed, and so all source code that include "ast.h" should be re-compiled. - The TimeFrame class now support Local Time as a time scale. The offset from UTC to Local Time is specified by a new TimeFrame attribute called LTOffset. - Addition of a new class called Plot3D that provides facilities for producing 3-dimensional annotated coordinate grids. - A correction for diurnal aberration is now included when converting between AZEL and other celestial coordinate systems. The correction is based on the value of the ObsLat Frame attribute (the geodetic latitude of the observer). - A bug has been fixed which caused the DUT1 attribute to be ignored by the SkyFrame class when finding conversions between AZEL and other celestial coordinate systems. - The Channel class has a new attribute called Strict which controls whether or not to report an error if unexpected data items are found within an AST Object description read from an external data source. Note, the default behaviour is now not to report such errors. This differs from previous versions of AST which always reported an error is unexpected input items were encountered. Main Changes in Version 4.5 --------------------------- - All FITS-CLASS headers are now created with a frequency axis. If the FrameSet supplied to astWrite contains a velocity axis (or any other form of spectral axis) it will be converted to an equivalent frequency axis before being used to create the FITS-CLASS header. - The value stored in the FITS-CLASS keyword "VELO-LSR" has been changed from the velocity of the source to the velocity of the reference channel. - Addition of a new method call astPurgeWCS (AST_PURGEWCS) to the FitsChan class. This method removes all WCS-related header cards from a FitsChan. - The astRebinSeq functions now have an extra parameter that is used to record the total number of input data val;ues added into the output array. This is necessary to correct a flaw in the calculation of output variances based on the spread of input values. NOTE, THIS CHANGE WILL REQUIRE EXISTING CODE THAT USES ASTREBINSEQ TO BE MODIFIED TO INCLUDE THE NEW PARAMETER (CALLED "NUSED"). - The Plot class now honours the value of the LabelUp attribute even if numerical labels are placed around the edge of the Plot. Previously LabelUp was only used if the labels were drawn within the interior of the plot. The LabelUp attribute controls whether numerical labels are drawn horizontally or parallel to the axis they describe. - The Plot class has a new attribute called GrfContext that can be used to comminicate context information between an application and any graphics functions registered with the Plot class via the astGrfSet (AST_GRFSET) function. - Functions registered with the Plot class using astGrfSet (AST_GRFSET) now take a new additional integer parameter, "grfcon". The Plot class sets this parameter to value of the Plot's GrfContext attribute before calling the graphics function. NOTE, THIS CHANGE WILL REQUIRE EXISTING CODE THAT USES astGrfSet (AST_GRFSET) TO BE MODIFIED TO INCLUDE THE NEW PARAMETER. - Support has been added for the FITS-WCS "HPX" projection (HEALPix). - A new flag "AST__VARWGT" can be supplied to astRebinSeq. This causes the input data values to be weighted using the reciprocals of the input variances (if supplied). - The Frame class has a new read-only attribute called NormUnit that returns the normalised value of the Unit attribute for an axis. Here, "normalisation" means cancelling redundant units, etc. So for instance, a Unit value of "s*(m/s)" would result in a NormUnit value of "m". - A new method astShowMesh has been added to the Region class. It displays a mesh of points covering the surface of a Region by writing out a table of axis values to standard output. - A bug has been fixed that could segmentation violations when setting attribute values. Main Changes in Version 4.4 --------------------------- - The astFindFrame (AST_FINDFRAME) method can now be used to search a CmpFrame for an instance of a more specialised class of Frame (SkyFrame, TimeFrame, SpecFrame, DSBSpecFrame or FluxFrame). That is, if an instance of one of these classes is used as the "template" when calling astFindFrame, and the "target" being searched is a CmpFrame (or a FrameSet in which the current Frame is a CmpFrame), then the component Frames within the CmpFrame will be searched for an instance of the supplied template Frame, and, if found, a suitable Mapping (which will include a PermMap to select the required axes from the CmpFrame) will be returned by astFindFrame. Note, for this to work, the MaxAxes and MinAxes attributes of the template Frame must be set so that they cover a range that includes the number of axes in the target CmpFrame. - The DSBSpecFrame class has a new attribute called AlignSB that specifies whether or not to take account of the SideBand attributes when aligning two DSBSpecFrames using astConvert (AST_CONVERT). - The Frame class has a new attribute called Dut1 that can be used to store a value for the difference between the UT1 and UTC timescales at the epoch referred to by the Frame. - The number of digits used to format the Frame attributes ObsLat and ObsLon has been increased. - The use of the SkyFrame attribute AlignOffset has been changed. This attribute is used to control how two SkyFrames are aligned by astConvert. If the template and target SkyFrames both have a non-zero value for AlignOffset, then alignment occurs within the offset coordinate systems (that is, a UnitMap will always be used to align the two SkyFrames). - The Plot class has a new attribute called ForceExterior that can be used to force exterior (rather than interior) tick marks to be produced, even if this would result in less than 3 tick marks being produced. - The TimeFrame class now supports conversion between angle based timescales such as UT1 and atomic based timescales such as UTC. Main Changes in Version 4.3 --------------------------- - The SpecFrame class has a new attribute called SourceSys that specified whether the SourceVel attribute (which specifies the rest frame of the source) should be accessed as an apparent radial velocity or a redshift. Note, any existing software that assumes that SourceVel always represents a velocity in km/s should be changed to allow for the possibility of SourceVel representing a redshift value. - The astGetFitsS (AST_GETFITSS) function now strips trailing white space from the returned string, if the original string contains 8 or fewer characters. Main Changes in Version 4.2 --------------------------- - The SideBand attribute of the DSBSpecFrame class can now take the option "LO" in addition to "USB" and "LSB". The new option causes the DSBSpecFrame to represent the offset from the local oscillator frequency, rather than either of the two sidebands. - The FitsChan class has been changed so that it writes out a VELOSYS keyword when creating a FITS-WCS encoding (VELOSYS indicates the topocentric apparent velocity of the standard of rest). FitsChan also strips out VELOSYS keywords when reading a FrameSet from a FITS-WCS encoding. - The FitsChan class has a new method called astRetainFits (AST_RETAINFITS) that indicates that the current card in the FitsChan should not be stripped out of the FitsChan when an AST Object is read from the FitsChan. Unless this method is used, all cards that were involved in the creation of the AST Object will be stripped from the FitsChan afte a read operation. - The ast_link_adam and ast_link scripts now ignore the -fsla and -csla options, and always link against the minimal cut-down version of SLALIB distributed as part of AST. - A problem with unaligned memory access that could cause bus errors on Solaris has been fixed. - A new function called astTune (or AST_TUNE) has been added which can be used to get and set global AST tuning parameters. At the moment there are only two such parameter, both of which are concerned with memory management within AST. - A new method called astTranGrid (AST_TRANGRID in Fortran) has been added to the Mapping class. This method creates a regular grid of points covering a rectangular region within the input space of a Mapping, and then transforms this set of points into the output space of the Mapping, using a piecewise-continuous linear approximation to the Mapping if appropriate in order to achive higher speed. - A new subclass of Mapping has been added called SwitchMap. A SwitchMap represents several alternate Mappings, each of which is used to transforms input positions within a different region of the input coordinate space. - A new subclass of Mapping has been added called SelectorMap. A SelectorMap tests each input position to see if it falls within one of several Regions. If it does, the index of the Region containing the input position is returned as the Mapping output. - The behaviour of the astConvert (AST_CONVERT) method when trying to align a CmpFrame with another Frame has been modified. If no conversion between positions in the Frame and CmpFrame can be found, an attempt is now made to find a conversion between the Frame and one of two component Frames contained within the CmpFrame. Thus is should now be possible to align a SkyFrame with a CmpFrame containing a SkyFrame and a SpecFrame (for instance). The returned Mapping produces bad values for the extra axes (i.e. for the SpecFrame axis in the above example). Main Changes in Version 4.1 --------------------------- - A new control flag has been added to the AST_RESAMPLE/astResample functions which produces approximate flux conservation. - The SkyFrame class now supports a System value of "AZEL" corresponding to horizon (azimuth/elevation) coordinates. - The FitsChan class allows the non-standard strings "AZ--" and "EL--" to be used as axis types in FITS-WCS CTYPE keyword values. - The Frame class now has attributes ObsLon and ObsLat to specify the geodetic longitude and latitude of the observer. - The ClockLon and ClockLat attributes have been removed from the TimeFrame class. Likewise, the GeoLon and GeoLat attributes have been removed from the SpecFrame class. Both classes now use the ObsLon and ObsLat attributes of the parent Frame class instead. However, the old attribute names can be used as synonyms for ObsLat and ObsLon. Also, dumps created using the old scheme can be read succesfully by AST V4.1 and converted to the new form. - A new function astMapSplit has been added to the Mapping class. This splits a Mapping into two component Mappings which, when combined in parallel, are equivalent to the original Mapping. - The default value for the SkyRefIs attribute has been changed from "Origin" to "Ignored". This means that if you want to use a SkyFrame to represent offsets from some origin position, you must now set the SkyRefIs attribute explicitly to either "Pole" or "Origin", in addition to assigning the required origin position to the SkyRef attribute. Main Changes in Version 4.0 --------------------------- - Experimental support for reading IVOA Space-Time-Coordinates (STC) descriptions using the XmlChan class has been added. Support is included for a subset of V1.20 of the draft STC specification. - A new set of methods (AST_REBIN/astRebin) has been added to the Mapping class. These are accurately flux-conserving alternatives to the existing AST_RESAMPLE/astResample methods. Main Changes in Version 3.7 --------------------------- - Support for time coordinate systems has been introduced throught the addition of two new classes, TimeFrame and TimeMap. The TimeFrame is a 1-dimensional Frame which can be used to describe moments in time (either absolute or relative) in various systems (MJD, Julian Epoch, etc.) and referred to various time scales (TAI, UTC, UT1, GMST, etc). The TimeMap is a Mapping which can transform time values between these various systems and time scales. Main Changes in Version 3.6 --------------------------- - If the Format attribute associated with an axis of a SkyFrame starts with a percent character (%), then axis values are now formatted and unformatted as a decimal radians value, using the Format syntax of a simple Frame. - The Plot class has a new attribute called Clip which controls the clipping performed by AST at the plot boundary. - The PolyMap class has been modified to allow a PolyMap to be written succesfully to a FitsChan using Native encoding. - A mimimal cut down subset of the C version of SLALIB is now included with the AST distribution and built as part of building AST. This means that it is no longer necessary to have SLALIB installed separately at your site. The SLALIB code included with AST is distrubuted under the GPL. The default behaviour of the ast_link script is now to link with this internal slalib subset. However, the ``-csla'' option can still be used to force linking with an external full C SLALIB library. A new option ``-fsla'' has been introduced which forces linking with the external full Fortran SLALIB library. Main Changes in Version 3.5 --------------------------- - AST now provides facilities for representing regions of various shapes within a coordinate system. The Region class provides general facilities which are independent of the specific shape of region being used. Various sub-classes of Region are also now available which provide means of creating Regions of specific shape. Facilities provided by the Region class include testing points to see if they are inside the Region, testing two Regions for overlap, transforming Regions from one coordinate system to another, etc. - A new class of 1-dimensional Frame called FluxFrame has been added which can be used to describe various systems for describing ovserved value at a single fixed spectral position. - A new class of 2-dimensional Frame called SpecFluxFrame has been added which can be used to describe a 2-d frame spanned by a spectral position axis and and an observed value axis. - A new class of Mapping called RateMap has been added. A RateMap encapsulates a previously created Mapping. The inputs of the RateMap correspond to the inputs of the encapsulated Mapping. All RateMaps have just a single output which correspond to the rate of change of a specified output of the encapsulated Mapping with respect to a specified input. - The SkyFrame class now supports a value of "J2000" for System. This system is an equatorial system based on the mean dynamical equator and equinox at J2000, and differs slightly from an FK5(J2000) system. - Methods have been added to the FitsChan class to allow values for named keywords to be changed or added. - The parameter list for the astRate method of the Mapping class has been modified. It no longer returns a second derivative estimate. Existing code which uses the astRate (AST_RATE) method will need to be changed. ./ast-7.3.3/zoommap.h0000644000175000017500000002365212262533650013005 0ustar olesoles#if !defined( ZOOMMAP_INCLUDED ) /* Include this file only once */ #define ZOOMMAP_INCLUDED /* *+ * Name: * zoommap.h * Type: * C include file. * Purpose: * Define the interface to the ZoomMap class. * Invocation: * #include "zoommap.h" * Description: * This include file defines the interface to the ZoomMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The ZoomMap class implements Mappings which perform a "zoom" * transformation by multiplying all coordinate values by the same * scale factor (the inverse transformation is performed by * dividing by this scale factor). * Inheritance: * The ZoomMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * Zoom (double) * The ZoomMap scale factor, by which coordinate values are * multiplied (by the forward transformation) or divided (by the * inverse transformation). This factor is set when a ZoomMap is * created, but may later be modified. It may not be set to * zero. The default value (if cleared) is one. * * Note that if the ZoomMap is inverted (by using astInvert or * setting a non-zero value for its Invert attribute), then the * reciprocal of this Zoom value will, in effect, be used. * Methods Over-Ridden: * Public: * None. * * Protected: * astClearAttrib * Clear an attribute value for a ZoomMap. * astGetAttrib * Get an attribute value for a ZoomMap. * astSetAttrib * Set an attribute value for a ZoomMap. * astTestAttrib * Test if an attribute value has been set for a ZoomMap. * astTransform * Apply a ZoomMap to transform a set of points. * New Methods Defined: * Public: * None. * * Protected: * astClearZoom * Clear the Zoom attribute value for a ZoomMap. * astGetZoom * Get the Zoom attribute value for a ZoomMap. * astSetZoom * Set the Zoom attribute value for a ZoomMap. * astTestZoom * Test if a Zoom attribute value has been set for a ZoomMap. * Other Class Functions: * Public: * astIsAZoomMap * Test class membership. * astZoomMap * Create a ZoomMap. * * Protected: * astCheckZoomMap * Validate class membership. * astInitZoomMap * Initialise a ZoomMap. * astInitZoomMapVtab * Initialise the virtual function table for the ZoomMap class. * astLoadZoomMap * Load a ZoomMap. * Macros: * None. * Type Definitions: * Public: * AstZoomMap * ZoomMap object type. * * Protected: * AstZoomMapVtab * ZoomMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 30-JAN-1996 (RFWS): * Original version. * 18-JUL-1996 (RFWS): * Updated to provide an external interface. * 10-SEP-1996 (RFWS): * Added I/O facilities. * 8-JAN-2003 (DSB): * Added protected astInitZoomMapVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* ZoomMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstZoomMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ double zoom; /* Zoom factor */ } AstZoomMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstZoomMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ double (*GetZoom)( AstZoomMap *, int * ); int (* TestZoom)( AstZoomMap *, int * ); void (* ClearZoom)( AstZoomMap *, int * ); void (* SetZoom)( AstZoomMap *, double, int * ); } AstZoomMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstZoomMapGlobals { AstZoomMapVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstZoomMapGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(ZoomMap) /* Check class membership */ astPROTO_ISA(ZoomMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstZoomMap *astZoomMap_( int, double, const char *, int *, ...); #else AstZoomMap *astZoomMapId_( int, double, const char *, ... )__attribute__((format(printf,3,4))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstZoomMap *astInitZoomMap_( void *, size_t, int, AstZoomMapVtab *, const char *, int, double, int * ); /* Vtab initialiser. */ void astInitZoomMapVtab_( AstZoomMapVtab *, const char *, int * ); /* Loader. */ AstZoomMap *astLoadZoomMap_( void *, size_t, AstZoomMapVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitZoomMapGlobals_( AstZoomMapGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ double astGetZoom_( AstZoomMap *, int * ); int astTestZoom_( AstZoomMap *, int * ); void astClearZoom_( AstZoomMap *, int * ); void astSetZoom_( AstZoomMap *, double, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckZoomMap(this) astINVOKE_CHECK(ZoomMap,this,0) #define astVerifyZoomMap(this) astINVOKE_CHECK(ZoomMap,this,1) /* Test class membership. */ #define astIsAZoomMap(this) astINVOKE_ISA(ZoomMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astZoomMap astINVOKE(F,astZoomMap_) #else #define astZoomMap astINVOKE(F,astZoomMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitZoomMap(mem,size,init,vtab,name,ncoord,zoom) \ astINVOKE(O,astInitZoomMap_(mem,size,init,vtab,name,ncoord,zoom,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitZoomMapVtab(vtab,name) astINVOKE(V,astInitZoomMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadZoomMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadZoomMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckZoomMap to validate ZoomMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astClearZoom(this) astINVOKE(V,astClearZoom_(astCheckZoomMap(this),STATUS_PTR)) #define astGetZoom(this) astINVOKE(V,astGetZoom_(astCheckZoomMap(this),STATUS_PTR)) #define astSetZoom(this,value) \ astINVOKE(V,astSetZoom_(astCheckZoomMap(this),value,STATUS_PTR)) #define astTestZoom(this) astINVOKE(V,astTestZoom_(astCheckZoomMap(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/fchannel.c0000644000175000017500000003440112262533650013066 0ustar olesoles/* *+ * Name: * fchannel.c * Purpose: * Define a FORTRAN 77 interface to the AST Channel class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Channel class. * Routines Defined: * AST_CHANNEL * AST_ISACHANNEL * AST_READ * AST_WRITE * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 6-SEP-1996 (RFWS): * Original version. * 12-DEC-1996 (RFWS): * Added SOURCE and SINK arguments to AST_CHANNEL. * 13-NOV-2003 (DSB): * Made SourceWrap and SinkWrap into protected functions rather * than private functions, so that they can be used in fxmlchan.c */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "channel.h" /* C interface to the Channel class */ #include /* Module Variables. */ /* ================= */ static char *line_in = NULL; /* Pointer to incoming line of text */ static const char *line_out = NULL; /* Pointer to outgoing line of text */ /* Prototypes for external functions. */ /* ================================== */ /* This is the null function defined by the FORTRAN interface in fobject.c. */ F77_SUBROUTINE(ast_null)( void ); /* Source and sink function interfaces. */ /* ==================================== */ /* These functions are concerned with allowing FORTRAN implementations of Channel source and sink functions to be passed to the Channel class and invoked when necessary by C code in the main class implementation. All FORTRAN-specific aspects of this interface are encapsulated here. */ F77_SUBROUTINE(ast_getline)( CHARACTER(LINE), INTEGER(L), INTEGER(STATUS) TRAIL(LINE) ) { /* f++ * Name: * AST_GETLINE * Purpose: * Obtain text to be written by a Channel sink routine. * Type: * Public function. * Synopsis: * CALL AST_GETLINE( LINE, L, STATUS ) * Description: * This routine should only be used when implementing a routine * which will be passed as the SINK argument to AST_CHANNEL. It * should be used to obtain (from the AST library) each line of * text which is to be written to the external data sink. One such * line should be obtained in this way for each invocation of the * sink routine. * Parameters: * LINE = CHARACTER * ( * ) (Returned) * The line of text to be written. Depending on the length of * character variable supplied, the returned text may be * truncated if necessary. Note, however, that it will not be * padded with blanks in order to fill this variable. * L = INTEGER (Returned) * The number of characters returned, which may be zero. Note * that characters beyond the L'th character in the LINE * variable are not modified and may therefore contain junk. * STATUS = INTEGER (Given and Returned) * The global status. * Notes: * - This routine is only available in the Fortran interface to the * AST library. f-- */ /* Argument Pointers: */ GENPTR_CHARACTER(LINE) GENPTR_INTEGER(L) /* Local Variables: */ int i; /* Loop counter for characters */ /* Set the error context and watch the STATUS value. */ astAt( "AST_GETLINE", NULL, 0 ); astWatchSTATUS( /* Initialise the returned string length. */ *L = 0; /* Check the global error status. */ if ( !astOK ) return; /* If there is no outgoing line ready (e.g. if this routine has been called at an inappropriate point), we simply return nothing. Otherwise, loop to copy the text into the character argument supplied, ensuring that its length is not exceeded. */ if ( line_out ) { for ( i = 0; line_out[ i ] && ( i < LINE_length ); i++ ) { LINE[ i ] = line_out[ i ]; } /* Return the number of characters copied. */ *L = i; } ) } F77_SUBROUTINE(ast_putline)( CHARACTER(LINE), INTEGER(L), INTEGER(STATUS) TRAIL(LINE) ) { /* f++ * Name: * AST_PUTLINE * Purpose: * Store a text line read by a Channel source routine. * Type: * Public function. * Synopsis: * CALL AST_PUTLINE( LINE, L, STATUS ) * Description: * This routine should only be used when implementing a routine * which will be passed as the SOURCE argument to AST_CHANNEL. It * should be used to pass back (to the AST library) each line of * text read from the external data source. One such line should be * passed back in this way for each invocation of the source * routine. * Parameters: * LINE = CHARACTER * ( * ) (Given) * A character string containing the line of input text which * has been read. * L = INTEGER (Given) * The number of characters in the input line, which may be * zero. If there is no more input available (e.g. an end of * file has been reached), this value should be set negative and * this will terminate the read operation on the Channel. * STATUS = INTEGER (Given and Returned) * The global status. * Notes: * - This routine is only available in the Fortran interface to the * AST library. f-- */ /* Argument Pointers: */ GENPTR_CHARACTER(LINE) GENPTR_INTEGER(L) /* Local Variables: */ int l; /* Number of characters in line */ /* Set the error context and watch the STATUS value. */ astAt( "AST_PUTLINE", NULL, 0 ); astWatchSTATUS( /* Initialise the incoming line pointer. */ line_in = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Obtain the number of characters in the line. */ l = *L; /* Negative values (or STATUS set) indicate end of input. If the value is not negative, limit the number of characters to the length of the character variable supplied. */ if ( l >= 0 ) { if ( l > LINE_length ) l = LINE_length; /* Create a dynamic string and fill it with the incoming data. Store the resulting pointer, which will be picked up by the SourceWrap function. */ line_in = astString( LINE, l ); } ) } void astSinkWrap_( void (* sink)( const char * ), const char *line, int *status ) { /* *+ * Name: * astSinkWrap * Purpose: * Wrapper function to invoke a FORTRAN Channel sink function. * Type: * Protected function. * Synopsis: * void astSinkWrap( void (* sink)( const char * ), const char *line ) * Description: * This function invokes the sink function whose pointer is * supplied in order to write an output line to an external data * store. * Parameters: * sink * Pointer to a sink function. This should result from a cast * applied to a pointer to a function, with a single FORTRAN * INTEGER error status argument, that returns void. This is * the form of Channel sink function employed by the FORTRAN * language interface to the AST library. * line * Pointer to a constant null-terminated string containing the * line of output text. *- */ /* Local Variables; */ DECLARE_INTEGER(STATUS); /* FORTRAN error status variable */ /* Check the global error status. */ if ( !astOK ) return; /* Store the pointer to the output text line in the (static) "line_out" variable, where it will be accessed by the sink function invoking AST_GETLINE. */ line_out = line; /* Cast the sink function pointer to a pointer to the FORTRAN subroutine and then invoke it. Transfer the AST error status to and from the subroutine's error status argument. */ STATUS = astStatus; ( *(void (*)()) sink )( INTEGER_ARG(&STATUS) ); astSetStatus( STATUS ); /* Clear the outgoing line pointer. */ line_out = NULL; } char *astSourceWrap_( const char *(* source)( void ), int *status ) { /* *+ * Name: * astSourceWrap * Purpose: * Wrapper function to invoke a FORTRAN Channel source function. * Type: * Protected function. * Synopsis: * char *astSourceWrap( const char *(* source)( void ) ) * Description: * This function invokes the source function whose pointer is * supplied in order to read the next input line from an external * data store. It then returns a pointer to a dynamic string * containing a copy of the text that was read. * Parameters: * source * Pointer to a source function. This should result from a cast * applied to a pointer to a function, with a single FORTRAN * INTEGER error status argument, that returns void. This is * the form of Channel source function employed by the FORTRAN * language interface to the AST library. * Returned Value: * A pointer to a dynamically allocated, null terminated string * containing a copy of the text that was read. This string must be * freed by the caller (using astFree) when no longer required. * * A NULL pointer will be returned if there is no more input text * to read. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the global error status set or if it should fail * for any reason. *- */ /* Local Variables: */ DECLARE_INTEGER(STATUS); /* FORTRAN error status variable */ char *result; /* Result pointer to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Initialise the incoming line pointer. */ line_in = NULL; /* Cast the source function pointer to a pointer to the FORTRAN subroutine and then invoke it. Transfer the AST error status to and from the subroutine's error status argument. */ STATUS = astStatus; ( *(void (*)()) source )( INTEGER_ARG(&STATUS) ); astSetStatus( STATUS ); /* This should result in a pointer to a dynamic string containing the input text being stored in the (static) "line_in" variable as a result of the source function invoking AST_PUTLINE. Save this string pointer and clear the original. */ result = line_in; line_in = NULL; /* If an error occurred, free the returned string. */ if ( ! astOK ) result = astFree( result ); /* Return the result. */ return result; } /* FORTRAN interface functions. */ /* ============================ */ /* These functions implement the remainder of the FORTRAN interface. */ F77_INTEGER_FUNCTION(ast_channel)( void (* SOURCE)(), void (* SINK)(), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; const char *(* source)( void ); int i; void (* sink)( const char * ); astAt( "AST_CHANNEL", NULL, 0 ); astWatchSTATUS( /* Set the source and sink function pointers to NULL if a pointer to the null routine AST_NULL has been supplied. */ source = (const char *(*)( void )) SOURCE; if ( source == (const char *(*)( void )) F77_EXTERNAL_NAME(ast_null) ) { source = NULL; } sink = (void (*)( const char * )) SINK; if ( sink == (void (*)( const char * )) F77_EXTERNAL_NAME(ast_null) ) { sink = NULL; } options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astChannelFor( source, astSourceWrap, sink, astSinkWrap, "%s", options ) ); astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isachannel)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISACHANNEL", NULL, 0 ); astWatchSTATUS( RESULT = astIsAChannel( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_read)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_INTEGER_TYPE(RESULT); astAt( "AST_READ", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astRead( astI2P( *THIS ) ) ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_write)( INTEGER(THIS), INTEGER(OBJECT), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(OBJECT) F77_INTEGER_TYPE(RESULT); astAt( "AST_WRITE", NULL, 0 ); astWatchSTATUS( RESULT = astWrite( astI2P( *THIS ), astI2P( *OBJECT ) ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_warnings)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_INTEGER_TYPE(RESULT); astAt( "AST_WARNINGS", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astWarnings( astI2P( *THIS ) ) ); ) return RESULT; } ./ast-7.3.3/permmap.c0000644000175000017500000035053612262533650012763 0ustar olesoles/* *class++ * Name: * PermMap * Purpose: * Coordinate permutation Mapping. * Constructor Function: c astPermMap f AST_PERMMAP * Description: * A PermMap is a Mapping which permutes the order of coordinates, * and possibly also changes the number of coordinates, between its * input and output. * * In addition to permuting the coordinate order, a PermMap may * also assign constant values to coordinates. This is useful when * the number of coordinates is being increased as it allows fixed * values to be assigned to any new ones. * Inheritance: * The PermMap class inherits from the Mapping class. * Attributes: * The PermMap class does not define any new attributes beyond * those which are applicable to all Mappings. * Functions: c The PermMap class does not define any new functions beyond those f The PermMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 29-FEB-1996 (RFWS): * Original version. * 26-SEP-1996 (RFWS): * Added external interface and I/O facilities. * 3-JUN-1997 (RFWS): * Over-ride the MapMerge method. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitPermMapVtab * method. * 11-SEP-2003 (DSB): * Added methods astGetInPerm and astGetOutPerm. * 2-NOV-2004 (DSB): * Added method astGetConstants. * 14-MAR-2006 (DSB): * Override astEqual. * 2-MAY-2007 (DSB): * Change MapSplit so that it does not try to use the * implementation from the parent Mapping class, since this * class can do a better job. * 11-SEP-2007 (DSB): * In MapSplit, check that the permuted axis index is less than the * number of axes available. Use AST__BAD otherwise. * 10-JAN-2011 (DSB): * Add protected PermSplit attribute. * 11-FEB-2011 (DSB): * Do not allow MapSplit to return a Mapping with zero outputs. * 22-NOV-2012 (DSB): * When using a default inperm array (as indicated by a NULL pointer * for inperm), ensure the array is padded with "-1" values if the * number of inputs exceeds the number of outputs. Also do the * equivalent for default outperm arrays. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS PermMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "unitmap.h" /* Unit Mappings */ #include "permmap.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Macros */ /* ============= */ /* A macro that returns the inperm or outperm value to use for a given index, taking account of the possibility that the inperm or outperm may be NULL (implying a unit permutation), and that he numbers of inputs and outputs may not be equal. "perms" is a pointer to the integer permutation array (inperm or outperm), "i" is the index of the required element of the permutation array, and "maxperm" is one more than the maximum value allowed in the permutation array (i.e. the number of PermMap outputs if "perms" is inperm, or PermMap inputs if "perms" is outperm). */ #define PERMVAL( perms, i, maxperm ) ( perms ? perms[ i ] : ( i < maxperm ? i : -1 )) /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(PermMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(PermMap,Class_Init) #define class_vtab astGLOBAL(PermMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstPermMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstPermMap *astPermMapId_( int, const int [], int, const int [], const double [], const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static double *GetConstants( AstPermMap *, int * ); static double Rate( AstMapping *, double *, int, int, int * ); static int Equal( AstObject *, AstObject *, int * ); static int *GetInPerm( AstPermMap *, int * ); static int *GetOutPerm( AstPermMap *, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int NullPerm( AstPermMap *, int, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void SetPermSplit( AstPermMap *, int, int * ); static void ClearPermSplit( AstPermMap *, int * ); static int TestPermSplit( AstPermMap *, int * ); static int GetPermSplit( AstPermMap *, int * ); /* Member functions. */ /* ================= */ static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two PermMaps are equivalent. * Type: * Private function. * Synopsis: * #include "permmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * PermMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two PermMaps are equivalent. * Parameters: * this * Pointer to the first Object (a PermMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the PermMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstPermMap *that; AstPermMap *this; int *that_inp; int *that_outp; int *this_inp; int *this_outp; int i; int nin; int nin_that; int nout; int nout_that; int p1; int p2; int result; int that_inp_len; int that_outp_len; int this_inp_len; int this_outp_len; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two PermMap structures. */ this = (AstPermMap *) this_object; that = (AstPermMap *) that_object; /* Check the second object is a PermMap. We know the first is a PermMap since we have arrived at this implementation of the virtual function. */ if( astIsAPermMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNout( that ) == nout && astGetNin( that ) == nin ) { /* Assume the PermMaps are equivalent. */ result = 1; /* Get the number of inputs and outputs in the second PermMap. */ nin_that = astGetNin( that ); nout_that = astGetNout( that ); /* Get pointers to the effective inperm and outperm array for each PermMap. If the Invert flags of the two PermMaps are not equal, we swap the arrays for the second PermMap in order to take account of the relative inversion of the second PermMap. */ this_inp = this->inperm; this_outp = this->outperm; if( astGetInvert( this ) ) { this_inp_len = nout; this_outp_len = nin; } else { this_inp_len = nin; this_outp_len = nout; } if( astGetInvert( this ) != astGetInvert( that ) ) { that_inp = that->outperm; that_outp = that->inperm; if( astGetInvert( that ) ) { that_inp_len = nin_that; that_outp_len = nout_that; } else { that_inp_len = nout_that; that_outp_len = nin_that; } } else { that_inp = that->inperm; that_outp = that->outperm; if( astGetInvert( that ) ) { that_inp_len = nout_that; that_outp_len = nin_that; } else { that_inp_len = nin_that; that_outp_len = nout_that; } } /* Loop round every PermMap input. */ for( i = 0; i < nin; i++ ) { /* See what is fed to this input by the inverse transformation. A zero or positive integer "p" value indicates that the input is fed from the output with the corresponding index. A negative integer "p" value means the input is fed a constant value stored at index (-p-1) in the associated constants array. */ p1 = PERMVAL( this_inp, i, this_outp_len ); p2 = PERMVAL( that_inp, i, that_outp_len ); /* If the "p" values differ, we may have evidence that the PermMaps are not equivalent. */ if( p1 != p2 ) { /* If either "p" value is zero or positive, then the PermMaps are definitely different since input "i" is fed from differing outputs, or one is fed from an input and the other is fed a constant. */ if( p1 >= 0 || p2 >= 0 ) { result = 0; break; /* If both "p" values are negative, then both inputs are fed a constant value. The PermMaps differ if these constants differ. */ } else if( this->constant[ -p1 - 1 ] != that->constant[ -p2 - 1 ] ) { result = 0; break; } } } /* If we have not yet discovered any evidence that the PermMaps differ, go on to check each output in the same way that we have just checked the inputs. */ if( result ) { for( i = 0; i < nout; i++ ) { p1 = PERMVAL( this_outp, i, this_inp_len ); p2 = PERMVAL( that_outp, i, that_inp_len ); if( p1 != p2 ) { if( p1 >= 0 || p2 >= 0 ) { result = 0; break; } else if( this->constant[ -p1 - 1 ] != that->constant[ -p2 - 1 ] ) { result = 0; break; } } } } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static double *GetConstants( AstPermMap *this, int *status ){ /* *+ * Name: * astGetConstants * Purpose: * Return a pointer to the constants array of a PermMap. * Type: * Protected virtual function. * Synopsis: * #include "permmap.h" * double *astGetConstants( AstPermMap *this ) * Class Membership: * PermMap method * Description: * This function returns a pointer to a dynamically allocated array * holding a copy of the constants array supplied when the PermMap was * created. * * Negative values in the arrays returned by the astGetInPerm and * astGetOutPerm methods can be used as indices into the constants * array returned by this method, if they are first negated and then * decrement by one. Thus an inperm value of -3 refers to element 2 of * the constants array. * Parameters: * this * Pointer to the PermMap. * Returned Value: * A pointer to a dynamically allocated array holding a copy of the * constants array. The pointer should be freed using astFree when it is * no longer needed. NULL will be returned if the PermMap has no * constants. * Notes: * - A value of NULL will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ double *result; /* Pointer to the returned array */ /* Initialise the returned result. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Allocate memory and put a copy of the InPerm array in it. */ result = (double *) astStore( NULL, this->constant, astSizeOf( this->constant ) ); /* Return the result. */ return result; } static int *GetInPerm( AstPermMap *this, int *status ){ /* * Name: * GetInPerm * Purpose: * Return a pointer to the InPerm array of a PermMap. * Type: * Protected virtual function. * Synopsis: * #include "permmap.h" * int *astGetInPerm( AstPermMap *this, int *status ) * Class Membership: * PermMap method * Description: * This function returns a pointer to a dynamically allocated array * holding a copy of the InPerm array supplied when thre PermMap was * created. * Parameters: * this * Pointer to the PermMap. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array holding a copy of the * InPerm array. The pointer should be freed using astFree when it is * no longer needed. The number of elements in the array will be given * by the value of the Nin attribute. The value in element "i" is the * zero-based index of the output axis which provides values for input * "i" when the inverse transformation is used. If the value in element * "i" is less than zero, then input "i" is fed a constant value. This * constant value is stored in the "constants" array (see astGetConstants) * at an index equal to the absolute value of inperm[i], minus 1. Thus * if element 3 of the array returned by this function has value -2, * then input axis 3 is fed the value held in constants[1]. If the * value of element "i" of the returned inperm array is greater than * or equal to the number of output axes, then input "i" will be fed * the constant AST__BAD. * Notes: * - A value of NULL will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ int i; /* Loop count */ int nin; /* Number of inputs. */ int *result; /* Pointer to the returned array */ /* Initialise the returned result. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If no inperm array is stored, every input is derived from the corresponding output. Therefore, return an array holding 0 to Nin-1. */ if( !this->inperm ) { nin = astGetNin( this ); result = (int *) astMalloc( sizeof( int ) * (size_t) nin ); if( astOK ) for( i = 0; i < nin; i++ ) result[ i ] = i; /* Otherwise, allocate memoy and put a copy of the InPerm array in it. */ } else { result = (int *) astStore( NULL, this->inperm, sizeof( int ) * (size_t) astGetNin( this ) ); } /* Return the result. */ return result; } static int *GetOutPerm( AstPermMap *this, int *status ){ /* * Name: * GetOutPerm * Purpose: * Return a pointer to the OutPerm array of a PermMap. * Type: * Protected virtual function. * Synopsis: * #include "permmap.h" * int *astGetOutPerm( AstPermMap *this, int *status ) * Class Membership: * PermMap method * Description: * This function returns a pointer to a dynamically allocated array * holding a copy of the OutPerm array supplied when thre PermMap was * created. * Parameters: * this * Pointer to the PermMap. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array holding a copy of the * OutPerm array. The pointer should be freed using astFree when it is * no longer needed. The number of elements in the array will be given * by the value of the Nout attribute. The value in element "i" is the * zero-based index of the input axis which provides values for output * "i" when the forward transformation is used. If the value in element * "i" is less than zero, then output "i" is fed a constant value. This * constant value is stored in the "constants" array (see astGetConstants) * at an index equal to the absolute value of outperm[i], minus 1. Thus * if element 3 of the array returned by this function has value -2, * then output axis 3 is fed the value held in constants[1]. If the * value of element "i" of the returned outperm array is greater than * or equal to the number of input axes, then output "i" will be fed * the constant AST__BAD. * Notes: * - A value of NULL will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ int i; /* Loop count */ int nout; /* Number of outputs. */ int *result; /* Pointer to the returned array */ /* Initialise the returned result. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If no outperm array is stored, every output is derived from the corresponding input. Therefore, return an array holding 0 to Nout-1. */ if( !this->outperm ) { nout = astGetNout( this ); result = (int *) astMalloc( sizeof( int ) * (size_t) nout ); if( astOK ) for( i = 0; i < nout; i++ ) result[ i ] = i; /* Otherwise, allocate memory and put a copy of the OutPerm array in it. */ } else { result = (int *) astStore( NULL, this->outperm, sizeof( int ) * (size_t) astGetNout( this ) ); } /* Return the result. */ return result; } void astInitPermMapVtab_( AstPermMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitPermMapVtab * Purpose: * Initialise a virtual function table for a PermMap. * Type: * Protected function. * Synopsis: * #include "permmap.h" * void astInitPermMapVtab( AstPermMapVtab *vtab, const char *name ) * Class Membership: * PermMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the PermMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAPermMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->GetConstants = GetConstants; vtab->GetInPerm = GetInPerm; vtab->GetOutPerm = GetOutPerm; vtab->ClearPermSplit = ClearPermSplit; vtab->GetPermSplit = GetPermSplit; vtab->SetPermSplit = SetPermSplit; vtab->TestPermSplit = TestPermSplit; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_transform = mapping->Transform; mapping->Transform = Transform; mapping->MapSplit = MapSplit; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; mapping->Rate = Rate; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "PermMap", "Coordinate permutation" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a PermMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * PermMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated PermMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated PermMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated PermMap which is to be merged with * its neighbours. This should be a cloned copy of the PermMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * PermMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated PermMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *map; /* Pointer to Mapping */ AstMapping *new; /* Pointer to replacement Mapping */ AstPermMap *permmap; /* Pointer to PermMap */ const char *class; /* Pointer to Mapping class string */ double *con; /* Pointer to constants array */ double constant; /* Constant value */ int *inperm; /* Pointer to "inperm" permutation array */ int *newperm; /* Pointer to new permutation array */ int *outperm; /* Pointer to "outperm" permutation array */ int *perm; /* Pointer to individual permutation array */ int back; /* Considering inverse transformation? */ int coord; /* Loop counter for coordinates */ int icon; /* Loop counter for constants */ int iend; /* Loop ending value */ int imap1; /* Index of first Mapping */ int imap2; /* Index of last Mapping */ int imap; /* Loop counter for Mappings */ int inc; /* Loop increment */ int invert; /* Invert attribute value */ int istart; /* Loop starting value */ int maxperm; /* Max value (+1) allowed in permutation array */ int ncon; /* Number of constants */ int ncoord_in; /* Effective number of input coordinates */ int ncoord_out; /* Effective number of output coordinates */ int ngone; /* Number of Mappings eliminated */ int nin; /* Total number of input coordinates */ int ninsum; /* Accumulated count of input coordinates */ int nout; /* Total number of output coordinates */ int noutsum; /* Accumulated count of output coordinates */ int nperm; /* Number of permutation array elements */ int p; /* Permuted coordinate index */ int result; /* Result value to return */ int simpler; /* Mapping(s) simplified? */ int store_in; /* Need to store "inperm" array contents? */ int store_out; /* Need to store "outperm" array contents? */ int unit; /* Replacement Mapping is a UnitMap? */ /* Initialise the returned result. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Further initialisation. */ con = NULL; inperm = outperm = NULL; ncon = 0; permmap = NULL; /* In series. */ /* ---------- */ /* Handle the case where the Mappings are connected in series. */ if ( series ) { /* Search adjacent lower-numbered Mappings until one is found which is not a PermMap or a UnitMap. */ imap1 = where; while ( ( imap1 - 1 ) >= 0 ) { class = astGetClass( ( *map_list )[ imap1 - 1 ] ); if ( astOK ) { if ( strcmp( class, "PermMap" ) && strcmp( class, "UnitMap" ) ) break; imap1--; } } /* Similarly search adjacent higher-numbered Mappings. */ imap2 = where; while ( ( imap2 + 1 ) < *nmap ) { class = astGetClass( ( *map_list )[ imap2 + 1 ] ); if ( astOK ) { if ( strcmp( class, "PermMap" ) && strcmp( class, "UnitMap" ) ) break; imap2++; } } /* Obtain a pointer to the first Mapping found and determine if it is to be applied with its Invert attribute set. */ map = ( *map_list )[ imap1 ]; invert = ( *invert_list )[ imap1 ]; /* Use this first Mapping (allowing for how its Invert attribute is currently set) to determine the number of input coordinates that the simplified Mapping should have. */ if ( astGetInvert( map ) ) { nin = invert ? astGetNin( map ) : astGetNout( map ); } else { nin = invert ? astGetNout( map ) : astGetNin( map ); } /* Repeat this process for the last Mapping found, to determine the number of output coordinates for the simplified Mapping. */ map = ( *map_list )[ imap2 ]; invert = ( *invert_list )[ imap2 ]; if ( astGetInvert( map ) ) { nout = invert ? astGetNout( map ) : astGetNin( map ); } else { nout = invert ? astGetNin( map ) : astGetNout( map ); } /* Allocate memory to hold input and output permutation arrays for the simplified Mapping, together with a list of constants. */ inperm = astMalloc( sizeof( int ) * (size_t) nin ); outperm = astMalloc( sizeof( int ) * (size_t) nout ); con = astMalloc( sizeof( double ) * (size_t) ( nin + nout ) ); if ( astOK ) { /* Initialise the number of constants. */ ncon = 0; /* Loop twice, to calculate the forward and inverse (backward) simplified permutation arrays in turn. */ for ( back = 0; back <= 1; back++ ) { /* Obtain a pointer to the appropriate (forward/inverse) permutation array that we wish to fill, and obtain the number of elements it will contain. Initialise the array contents to represent a null permutation.*/ newperm = back ? outperm : inperm; nperm = back ? nout : nin; for ( coord = 0; coord < nperm; coord++ ) newperm[ coord ] = coord; /* Set up limits to scan through the list of Mappings being merged in either the forward or reverse order, as required. */ istart = back ? imap2 : imap1; iend = back ? imap1 - 1 : imap2 + 1; inc = back ? -1 : 1; /* Loop through the Mappings, obtaining a pointer to each, together with the value to be used for its Invert attribute. Invert this attribute value if calculating the overall inverse (backward) permutation array. */ for ( imap = istart; imap != iend; imap += inc ) { map = ( *map_list )[ imap ]; invert = ( *invert_list )[ imap ]; if ( back ) invert = !invert; /* Determine the class to which the Mapping belongs. */ class = astGetClass( map ); if ( astOK ) { /* If it is a PermMap, obtain a pointer to the PermMap structure and hence to the relevant permutation array. Otherwise (if it is a UnitMap), leave the permutation array pointer NULL, which indicates a null permutation. */ perm = NULL; maxperm = astGetNout( map ); if ( !strcmp( class, "PermMap" ) ) { permmap = (AstPermMap *) map; perm = invert ? permmap->outperm : permmap->inperm; } /* Obtain the effective number of output coordinates associated with this individual Mapping (when transforming points in the direction to which this permutation array applies). */ if ( astGetInvert( map ) ) { ncoord_out = invert ? astGetNout( map ) : astGetNin( map ); } else { ncoord_out = invert ? astGetNin( map ) : astGetNout( map ); } /* Loop through the elements of the simplified permutation array to accumulate the effects of the current individual Mapping. */ if ( astOK ) { for ( coord = 0; coord < nperm; coord++ ) { /* Find the effective input coordinate for the current Mapping from the permutation accumulated so far, and check this is not negative. If it is, the accumulated permutation refers to a "bad" coordinate value or a constant, so the current Mapping makes no further difference. */ p = newperm[ coord ]; if ( p >= 0 ) { /* Otherwise, obtain the permuting effect of the current Mapping, allowing for the possibility of its permutation array being NULL (implying a null permutation). */ p = PERMVAL( perm, p, maxperm ); /* If the permuted index refers to a valid (effective) output coordinate for the individual Mapping, then accumulate its effect in the overall permutation array. */ if ( ( p >= 0 ) && ( p < ncoord_out ) ) { newperm[ coord ] = p; /* Otherwise (this can only occur if the individual Mapping is a PermMap), determine whether it refers to a "bad" coordinate value or a constant. If the former, extract the constant's value, otherwise use a constant value of AST__BAD. */ } else { if ( ( p < 0 ) && permmap->constant ) { constant = permmap->constant[ (-p) - 1 ]; } else { constant = AST__BAD; } /* If the result (however reached) is a coordinate value of AST__BAD, then mark the accumulated permutation array with a value of -1 to indicate this. */ if ( constant == AST__BAD ) { newperm[ coord ] = -1; /* Otherwise, search the array of constants to see if this one has been encountered before. If not, append the new constant to the list. */ } else { for ( icon = 0; icon < ncon; icon++ ) { if ( con[ icon ] == constant ) break; } if ( icon == ncon ) con[ ncon++ ] = constant; /* Store a (negative) reference to the new constant in the accumulated permutation array (note we use an extra offset of -1 here in forming these references, so that the value -1 itself can be used to indicate a "bad" coordinate value without an entry in the constants array). */ newperm[ coord ] = (-icon) - 2; } } } } } } } } } /* In parallel. */ /* ------------ */ /* Handle the case where the Mappings are connected in parallel. */ } else { /* Obtain a pointer to the nominated Mapping (which is a PermMap) and determine if it is to be applied with its Invert attribute set. */ map = ( *map_list )[ where ]; invert = ( *invert_list )[ where ]; /* Use this nominated Mapping to initialise the counts of input and output coordinates for the simplified Mapping (allowing for how its Invert attribute is currently set). */ if ( astGetInvert( map ) ) { nin = invert ? astGetNin( map ) : astGetNout( map ); nout = invert ? astGetNout( map ) : astGetNin( map ); } else { nin = invert ? astGetNout( map ) : astGetNin( map ); nout = invert ? astGetNin( map ) : astGetNout( map ); } /* Search adjacent lower-numbered Mappings until one is found which is not a PermMap or a UnitMap. */ imap1 = where; while ( astOK && ( ( imap1 - 1 ) >= 0 ) ) { map = ( *map_list )[ imap1 - 1 ]; class = astGetClass( map ); if ( astOK ) { if ( strcmp( class, "PermMap" ) && strcmp( class, "UnitMap" ) ) break; /* For each Mapping found, obtain the effective numbers of input and output coordinates (allowing for all the direction flags, as above) and accumulate the total count of input and output coordinates for the overall simplified Mapping. */ invert = ( *invert_list )[ imap1 - 1 ]; if ( astGetInvert( map ) ) { nin += ( invert ? astGetNin( map ) : astGetNout( map ) ); nout += ( invert ? astGetNout( map ) : astGetNin( map ) ); } else { nin += ( invert ? astGetNout( map ) : astGetNin( map ) ); nout += ( invert ? astGetNin( map ) : astGetNout( map ) ); } imap1--; } } /* Similarly search higher-numbered Mappings and accumulate their coordinate counts. */ imap2 = where; while ( astOK && ( ( imap2 + 1 ) < *nmap ) ) { map = ( *map_list )[ imap2 + 1 ]; class = astGetClass( map ); if ( astOK ) { if ( strcmp( class, "PermMap" ) && strcmp( class, "UnitMap" ) ) break; invert = ( *invert_list )[ imap2 + 1 ]; if ( astGetInvert( map ) ) { nin += ( invert ? astGetNin( map ) : astGetNout( map ) ); nout += ( invert ? astGetNout( map ) : astGetNin( map ) ); } else { nin += ( invert ? astGetNout( map ) : astGetNin( map ) ); nout += ( invert ? astGetNin( map ) : astGetNout( map ) ); } imap2++; } } /* Allocate memory to hold input and output permutation arrays for the simplified Mapping, together with a list of constants. */ inperm = astMalloc( sizeof( int ) * (size_t) nin ); outperm = astMalloc( sizeof( int ) * (size_t) nout ); con = astMalloc( sizeof( double ) * (size_t) ( nin + nout ) ); if ( astOK ) { /* Initialise the number of constants. */ ncon = 0; /* Loop twice, to calculate the forward and inverse (backward) simplified permutation arrays in turn. */ for ( back = 0; back <= 1; back++ ) { /* Obtain a pointer to the appropriate (forward/inverse) permutation array that we wish to fill, and obtain the number of elements it will contain. */ newperm = back ? outperm : inperm; nperm = back ? nout : nin; /* Initialise counts of (effective) input and output coordinates. */ ninsum = noutsum = 0; /* Loop through the Mappings, obtaining a pointer to each, together with the value to be used for its Invert attribute. Invert this attribute value if calculating the overall inverse (backward) permutation array. */ for ( imap = imap1; imap <= imap2; imap++ ) { map = ( *map_list )[ imap ]; invert = ( *invert_list )[ imap ]; if ( back ) invert = !invert; /* Determine the class to which the Mapping belongs. */ class = astGetClass( map ); if ( astOK ) { /* If it is a PermMap, obtain a pointer to the PermMap structure and hence to the relevant permutation array. Otherwise (if it is a UnitMap), leave the permutation array pointer NULL, which indicates a null permutation. */ perm = NULL; maxperm = astGetNout( map ); if ( !strcmp( class, "PermMap" ) ) { permmap = (AstPermMap *) map; perm = invert ? permmap->outperm : permmap->inperm; } /* Obtain the effective number of input and output coordinates associated with this individual Mapping (when transforming points in the direction to which this permutation array applies). */ if ( astGetInvert( map ) ) { ncoord_in = invert ? astGetNin( map ) : astGetNout( map ); ncoord_out = invert ? astGetNout( map ) : astGetNin( map ); } else { ncoord_in = invert ? astGetNout( map ) : astGetNin( map ); ncoord_out = invert ? astGetNin( map ) : astGetNout( map ); } /* Loop through the (effective) input coordinates of the current individual Mapping to accumulate their effect on the overall permutation array. */ if ( astOK ) { for ( coord = 0; coord < ncoord_in; coord++ ) { /* Obtain the permuting effect of the current Mapping, allowing for the possibility of its permutation array being NULL. */ p = PERMVAL( perm, coord, maxperm ); /* If the permuted index refers to a valid (effective) output coordinate for the individual Mapping, then accumulate its effect on the overall permutation array, allowing for the coordinate numbering offset produced by any Mappings already accumulated. */ if ( ( p >= 0 ) && ( p < ncoord_out ) ) { newperm[ coord + ninsum ] = p + noutsum; /* Otherwise (this can only occur if the individual Mapping is a PermMap), determine whether it refers to a "bad" coordinate value or a constant. If the former, extract the constant's value, otherwise use a constant value of AST__BAD. */ } else { if ( ( p < 0 ) && permmap->constant ) { constant = permmap->constant[ (-p) - 1 ]; } else { constant = AST__BAD; } /* If the result (however reached) is a coordinate value of AST__BAD, then mark the accumulated permutation array with a value of -1 to indicate this. */ if ( constant == AST__BAD ) { newperm[ coord + ninsum ] = -1; /* Otherwise, search the array of constants to see if this one has been encountered before. If not, append the new constant to the list. */ } else { int icon; for ( icon = 0; icon < ncon; icon++ ) { if ( con[ icon ] == constant ) break; } if ( icon == ncon ) con[ ncon++ ] = constant; /* Store a (negative) reference to the new constant in the accumulated permutation array (note we use an extra offset of -1 here in forming these references, so that the value -1 itself can be used to indicate a "bad" coordinate value without an entry in the constants array). */ newperm[ coord + ninsum ] = (-icon) - 2; } } } } /* Accumulate the counts of (effective) input and output coordinates for each individual Mapping. */ ninsum += ncoord_in; noutsum += ncoord_out; } } } } } /* Inspect each element of the accumulated "inperm" array to determine if it needs to be stored by the replacement PermMap. */ if ( astOK ) { store_in = 0; for ( coord = 0; coord < nin; coord++ ) { /* It need not be stored if it produces a null permutation, where each input coordinate takes its value from the corresponding output coordinate (or where a "bad" value results if there is no corresponding output coordinate). Note any deviation from this pattern. */ if ( coord < nout ) { store_in = store_in || ( inperm[ coord ] != coord ); } else { store_in = store_in || ( inperm[ coord ] != -1 ); } /* Also convert permutation array values of -1 into non-existent positive coordinate indices (indicating "bad" coordinate values) and adjust (negative) references to constants by +1 to eliminate the extra offset of -1 used temporarily above. This returns the permutation array values to normal. */ if ( inperm[ coord ] < 0 ) { if ( !++inperm[ coord ] ) inperm[ coord ] = nout; } } /* Similarly inspect the "outperm" array and return its values to normal. */ store_out = 0; for ( coord = 0; coord < nout; coord++ ) { if ( coord < nin ) { store_out = store_out || ( outperm[ coord ] != coord ); } else { store_out = store_out || ( outperm[ coord ] != -1 ); } if ( outperm[ coord ] < 0 ) { if ( !++outperm[ coord ] ) outperm[ coord ] = nin; } } /* Determine how many adjacent Mappings can be eliminated by merging them. */ ngone = imap2 - imap1; /* Determine if the resultant PermMap can be simplified still further to become a UnitMap (a null Mapping). This will be the case if both the forward and inverse coordinate permutations it produces are null, and if the number of input and output coordinates are equal. */ unit = !store_in && !store_out && ( nin == nout ); /* We must now determine whether we have actually produced any simplification. This is important, because if we indicate a simplification when none has, in fact, been achieved, then this function may get called over and over again without end. */ /* Simplification is clearly evident if (a) Mappings have been eliminated ("ngone" is non-zero), or (b) a PermMap has been reduced to a UnitMap, or (c) where there was originally only one PermMap to simplify, its invert flag was set (the replacement Mapping will always have this flag cleared). */ simpler = ngone || unit || ( *invert_list )[ where ]; /* If the above tests do not indicate simplification, then we can only be considering the case where there was a single initial PermMap. In this case we have also achieved simplification if either the "inperm" or "outperm" array no longer needs storing whereas previously it was stored. */ permmap = (AstPermMap *) ( *map_list )[ where ]; if ( !simpler ) { simpler = ( !store_in && !NullPerm( permmap, 0, status ) ) || ( !store_out && !NullPerm( permmap, 1, status ) ); } /* If we still haven't detected any simplification, then compare the original and replacement "inperm" arrays (if present) in detail for equality. We declare simplification to have occurred if they differ. */ if ( !simpler && store_in ) { for ( coord = 0; coord < nin; coord++ ) { simpler = ( inperm[ coord ] != permmap->inperm[ coord ] ); if ( simpler ) break; } } /* Similarly, if necessary, compare the original and replacement "outperm" arrays. */ if ( !simpler && store_out ) { for ( coord = 0; coord < nout; coord++ ) { simpler = ( outperm[ coord ] != permmap->outperm[ coord ] ); if ( simpler ) break; } } /* Do nothing more unless there has been some simplification. */ if ( simpler ) { /* If the PermMaps (and UnitMaps) can be replaced by a UnitMap, then create the replacement. */ if ( unit ) { new = (AstMapping *) astUnitMap( nin, "", status ); /* Otherwise, create a replacement PermMap, setting as many arguments to NULL in the constructor function as can be achieved without affecting the result. */ } else { new = (AstMapping *) astPermMap( nin, store_in ? inperm : NULL, nout, store_out ? outperm : NULL, ncon ? con : NULL, "", status ); } /* Annul the pointers to all the Mappings that are being replaced. */ if ( astOK ) { for ( imap = imap1; imap <= imap2; imap++ ) { ( *map_list )[ imap ] = astAnnul( ( *map_list )[ imap ] ); } /* Insert the new pointer and the associated invert flag. */ ( *map_list )[ imap1 ] = new; ( *invert_list )[ imap1 ] = 0; /* Loop to close the resulting gap by moving subsequent elements down in the arrays. */ for ( imap = imap2 + 1; imap < *nmap; imap++ ) { ( *map_list )[ imap - ngone ] = ( *map_list )[ imap ]; ( *invert_list )[ imap - ngone ] = ( *invert_list )[ imap ]; } /* Clear the vacated elements at the end. */ for ( imap = *nmap - ngone; imap < *nmap; imap++ ) { ( *map_list )[ imap ] = NULL; ( *invert_list )[ imap ] = 0; } /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap ) -= ngone; result = imap1; } } } /* Free the workspace arrays. */ inperm = astFree( inperm ); outperm = astFree( outperm ); con = astFree( con ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * PermMap. * Type: * Private function. * Synopsis: * #include "permmap.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * PermMap method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing PermMap. This is only possible if the specified inputs * correspond to some subset of the PermMap outputs. That is, there * must exist a subset of the PermMap outputs for which each output * depends only on the selected PermMap inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied PermMap, then a NULL Mapping is returned. * Parameters: * this * Pointer to the PermMap to be split (the PermMap is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied PermMap, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied PermMap has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied PermMap. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ AstPermMap *this; /* Pointer to PermMap structure */ double *con; /* Pointer to constants array */ int *inp; /* Input perm array to use with supplied PermMap */ int *inpm; /* Input perm array to use with new PermMap */ int *outp; /* Output perm array to use with supplied PermMap */ int *outpm; /* Output perm array to use with new PermMap */ int *result; /* Pointer to returned array */ int i; /* Loop count */ int iin; /* Mapping input index */ int iout; /* Output index */ int j; /* Loop count */ int nout; /* No. of outputs in the new PermMap */ int npin; /* No. of inputs in the supplied Mapping */ int npout; /* No. of outputs in the supplied Mapping */ int ok; /* Are input indices OK? */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the PermMap structure. */ this = (AstPermMap *) this_map; /* Get the number of inputs and outputs in the supplied PermMap. */ npin = astGetNin( this ); npout = astGetNout( this ); /* Check all input axis indices are valid. */ ok = 1; for( i = 0; i < nin; i++ ) { if( in[ i ] < 0 || in[ i ] >= npin ) { ok = 0; break; } } /* Get pointers to the input and output permutation arrays and constant array taking account of whether the PermMap has been inverted. */ if( astGetInvert( this ) ) { outp = this->inperm; inp = this->outperm; } else { outp = this->outperm; inp = this->inperm; } con = this->constant; /* The "normal" method, as described in the prologue. */ if( astGetPermSplit( this ) == 0 ) { /* Allocate memory for the returned array of output indices. */ result = astMalloc( sizeof( int )*(size_t) npout ); /* Allocate memory for the inperm and outperm arrays of the returned PermMap. Make these the largest they could possible need to be. */ inpm = astMalloc( sizeof( int )*(size_t) npin ); outpm = astMalloc( sizeof( int )*(size_t) npout ); if( astOK ) { /* Initialise number of outputs in returned PermMap. */ nout = 0; /* Loop round each output of the supplied PermMap. */ for( iout = 0; iout < npout; iout++ ) { /* Is this output fed by one of the selected inputs? If so store the input index of the returned Mapping, which feeds this output and add this output index to the list of returned outputs. */ iin = PERMVAL( outp, iout, npin ); if( iin >= 0 && iin < npin ) { for( i = 0; i < nin; i++ ) { if( in[ i ] == iin ) { outpm[ nout ] = i; result[ nout ] = iout; nout++; break; } } } } /* We now need to set up the inperm array for the returned PermMap. This ensures that the inverse transformation in the returned Mapping provides values for the selected inputs. Loop round all the selected inputs. */ for( i = 0; i < nin; i++ ) { iin = in[ i ]; /* Is this input constant or fed by one of the selected outputs? If so store the output or constant index in the returned Mapping which feeds this input. */ ok = 0; iout = PERMVAL( inp, iin, npout ); if( iout >= 0 && iout < npout ) { for( j = 0; j < nout; j++ ) { if( result[ j ] == iout ) { ok = 1; inpm[ i ] = j; break; } } } else { inpm[ i ] = iout; ok = 1; } /* If this input is fed by an output which has not been selected, then we cannot produce the required Mapping. */ if( !ok ) break; } /* If possible produce the returned PermMap. Otherwise, free the returned array. */ if( ok && nout > 0 ) { *map = (AstMapping *) astPermMap( nin, inpm, nout, outpm, con, "", status ); } else { result = astFree( result ); } /* Free other resources. */ inpm = astFree( inpm ); outpm = astFree( outpm ); } /* The "alternative" method. Only the inperm array is used - the outperm array is assumed to be an exact inverse of the inperm array. In other words, only the inverse transformation is used, and the forward transformation is assumed to be the exact opposite. */ } else { /* The returned array of output indices holds the "inperm" values for the selected inputs. */ result = astMalloc( sizeof( int )*(size_t) nin ); if( astOK ) { for( i = 0; i < nin; i++ ) { result[ i ] = PERMVAL( inp, in[ i ], npout ); /* Check the input is not fed by a constant. */ if( result[ i ] < 0 ) { result = astFree( result ); break; /* Check that the the output has not already been used. */ } else { for( j = 0; j < i; j++ ) { if( result[ j ] == result[ i ] ) { result = astFree( result ); break; } } } } /* If the split was possible, the returned Mapping is a UnitMap. */ if( result ) *map = (AstMapping *) astUnitMap( nin, " ", status ); } } /* If the returned Mapping has no outputs, do not return it. */ if( !result && *map ) { *map = astAnnul( *map ); } /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static int NullPerm( AstPermMap *this, int forward, int *status ){ /* * Name: * NullPerm * Purpose: * See if a PermMap transformation represents a null axis permutation. * Type: * Private function. * Synopsis: * #include "permmap.h" * int NullPerm( AstPermMap *this, int forward, int *status ) * Class Membership: * PermMap method * Description: * This function returns a logical value indicating if the specified * transformation of the supplied PermMap is a null (i.e. unit) * transformation. * Parameters: * this * Pointer to the PermMap. * forward * Check the forward transformation? Otherise, check the inverse * transformation. * status * Pointer to the inherited status variable. * Returned Value: * One if the specified transformation is a null axis permutation. * Zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ int i; /* Coordinate index */ int nin; /* Number of Mapping inputs */ int nout; /* Number of Mapping outputs */ int result; /* Returned value */ /* Initialise the returned result. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* First check the forward transformation, given by the outperm array. */ if( forward ) { /* If no outperm array is stored, every output is derived from the corresponding input. Therefore, return 1 indicating a null axis permutation. */ if( !this->outperm ) { result = 1; /* Otherwise, check that every element in the outperm array indicates that the output is derived from the input with the saem index. */ } else { result = 1; nout = astGetNout( this ); for( i = 0; i < nout; i++ ) { if( this->outperm[ i ] != i ) { result = 0; break; } } } /* Now check the inverse transformation, given by the inperm array. */ } else { /* If no inperm array is stored, every input is derived from the corresponding output. Therefore, return 1 indicating a null axis permutation. */ if( !this->inperm ) { result = 1; /* Otherwise, check that every element in the inperm array indicates that the input is derived from the output with the same index. */ } else { result = 1; nin = astGetNin( this ); for( i = 0; i < nin; i++ ) { if( this->inperm[ i ] != i ) { result = 0; break; } } } } /* If an error has occurred, return zero. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){ /* * Name: * Rate * Purpose: * Calculate the rate of change of a Mapping output. * Type: * Private function. * Synopsis: * #include "permmap.h" * result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ) * Class Membership: * PermMap member function (overrides the astRate method inherited * from the Mapping class ). * Description: * This function returns the rate of change of a specified output of * the supplied Mapping with respect to a specified input, at a * specified input position. * Parameters: * this * Pointer to the Mapping to be applied. * at * The address of an array holding the axis values at the position * at which the rate of change is to be evaluated. The number of * elements in this array should equal the number of inputs to the * Mapping. * ax1 * The index of the Mapping output for which the rate of change is to * be found (output numbering starts at 0 for the first output). * ax2 * The index of the Mapping input which is to be varied in order to * find the rate of change (input numbering starts at 0 for the first * input). * status * Pointer to the inherited status variable. * Returned Value: * The rate of change of Mapping output "ax1" with respect to input * "ax2", evaluated at "at", or AST__BAD if the value cannot be * calculated. */ /* Local Variables: */ AstPermMap *map; int *outperm; int result; /* Check inherited status */ if( !astOK ) return AST__BAD; /* Get a pointer to the PermMap structure. */ map = (AstPermMap *) this; /* Obtain a pointer to the appropriate output coordinate permutation array, according to whether the PermMap has been inverted. If the specified output is derived from the specified input then the rate is unity. Otherwise it is zero. */ outperm = astGetInvert( this ) ? map->inperm : map->outperm; if( outperm ) { result = ( ax2 == outperm[ ax1 ] ) ? 1.0 : 0.0; } else { result = ( ax2 == ax1 ) ? 1.0 : 0.0; } return result; } static AstPointSet *Transform( AstMapping *map, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a PermMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "permmap.h" * AstPointSet *Transform( AstMapping *map, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * PermMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a PermMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required coordinate * permutation. * Parameters: * map * Pointer to the PermMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the PermMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPermMap *this; /* Pointer to PermMap to be applied */ AstPointSet *result; /* Pointer to output PointSet */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double constant; /* Constant coordinate value */ int *perm; /* Pointer to permutation array */ int coord; /* Loop counter for coordinates */ int maxperm; /* Max value in permutation array */ int ncoord_in; /* Number of coordinates per input point */ int ncoord_out; /* Number of coordinates per output point */ int npoint; /* Number of points */ int p; /* Permuted coordinate index */ int point; /* Loop counter for points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the PermMap. */ this = (AstPermMap *) map; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( map, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the permutation needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input and output PointSets and obtain pointers for accessing the input and output coordinate values. */ ncoord_in = astGetNcoord( in ); ncoord_out = astGetNcoord( result ); npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Obtain a pointer to the appropriate coordinate permutation array, according to the direction of transformation required and whether the PermMap has been inverted. Also get the maximum allowed value in the permutation array. */ if ( ( astGetInvert( this ) != 0 ) == ( forward != 0 ) ) { perm = this->inperm; maxperm = ncoord_out; } else { perm = this->outperm; maxperm = ncoord_in; } /* Perform coordinate permutation. */ /* ------------------------------- */ if ( astOK ) { /* Loop to generate values for each output coordinate. */ for ( coord = 0; coord < ncoord_out; coord++ ) { /* If the permutation array is not NULL, use it to look up which input coordinate to use. Otherwise, use the corresponding input coordinate. */ p = PERMVAL( perm, coord, maxperm ); /* If a valid input coordinate has been identified, simply copy the required coordinate values from input to output. */ if ( ( p >= 0 ) && ( p < ncoord_in ) ) { (void) memcpy( ptr_out[ coord ], ptr_in[ p ], sizeof( double ) * (size_t) npoint ); /* If the permuted coordinate index is negative, use it to index the "constant" array to obtain a constant value to assign. If this array is NULL, use AST__BAD as the constant. */ } else if ( p < 0 ) { constant = this->constant ? this->constant[ (-p) - 1 ] : AST__BAD; /* Assign the constant value to the output coordinate for all points. */ for ( point = 0; point < npoint; point++ ) { ptr_out[ coord ][ point ] = constant; } /* In all other cases, simply assign the value AST__BAD to the output coordinate for all points. */ } else { for ( point = 0; point < npoint; point++ ) { ptr_out[ coord ][ point ] = AST__BAD; } } } } /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* *att+ * Name: * PermSplit * Purpose: * The method to use when splitting a PermMap using astMapSplit. * Type: * Protected attribute. * Synopsis: * Integer. * Description: * This attribute controls the behaviour of the implementation of the * astMapSplit method provided by the PermMap class. If set to zero (the * default), astMapSplit will split PermMaps according to the public * documentation for the method. If set non-zero, the forward transformation * of the PermMap defined by the "outperm" array will be ignored. * Instead, the forward transformation is assumed to be the exact * inverse of the inverse transformation. The Mapping returned will * then be a UnitMap with Nin equal to the number of picked inputs, * and the returned array of output indices will hold the "inperm" * values for the picked inputs. Note, if any of these "inperm" values * are negative (indicating that the inverse transformation supplies a * constant value for the input), or if more than one of the selected * inputs are fed (by the inverse transformation) by the same output, * then the PermMap cannot be split. * Applicability: * PermMap * All PermMaps have this attribute. *att- */ astMAKE_CLEAR(PermMap,PermSplit,permsplit,-INT_MAX) astMAKE_GET(PermMap,PermSplit,int,0,( this->permsplit != -INT_MAX ? this->permsplit : 0 )) astMAKE_SET(PermMap,PermSplit,int,permsplit,( value != 0 )) astMAKE_TEST(PermMap,PermSplit,( this->permsplit != -INT_MAX )) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for PermMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for PermMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstPermMap *in; /* Pointer to input PermMap */ AstPermMap *out; /* Pointer to output PermMap */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output PermMaps. */ in = (AstPermMap *) objin; out = (AstPermMap *) objout; /* For safety, first clear any references to the input memory from the output PermMap. */ out->inperm = NULL; out->outperm = NULL; out->constant = NULL; /* For each input array which is not NULL, make a copy in allocated memory, storing a pointer to it in the output PermMap structure. */ if ( in->inperm ) out->inperm = astStore( NULL, in->inperm, astSizeOf( in->inperm ) ); if ( in->outperm ) out->outperm = astStore( NULL, in->outperm, astSizeOf( in->outperm ) ); if ( in->constant ) out->constant = astStore( NULL, in->constant, astSizeOf( in->constant ) ); /* If an error occurred, clean up by freeing all memory allocated above. */ if ( !astOK ) { out->inperm = astFree( out->inperm ); out->outperm = astFree( out->outperm ); out->constant = astFree( out->constant ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for PermMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for PermMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstPermMap *this; /* Pointer to PermMap */ /* Obtain a pointer to the PermMap structure. */ this = (AstPermMap *) obj; /* Free all memory allocated by the PermMap. */ this->inperm = astFree( this->inperm ); this->outperm = astFree( this->outperm ); this->constant = astFree( this->constant ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for PermMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the PermMap class to an output Channel. * Parameters: * this * Pointer to the PermMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define COMMENT_LEN 150 /* Maximum length of a comment string */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstPermMap *this; /* Pointer to the PermMap structure */ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword strings */ int coord; /* Loop counter for coordinates */ int iconst; /* Loop counter for constants */ int invert; /* Invert attribute value */ int ival; /* Integer value */ int nconst; /* Number of constants */ int nin; /* Number of input coordinates */ int nout; /* Number of output coordinates */ int set; /* Value is "set"? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the PermMap structure. */ this = (AstPermMap *) this_object; /* Determine if the PermMap is inverted and obtain the "true" number of input and output coordinates by un-doing the effects of any inversion. */ invert = astGetInvert( this ); nin = !invert ? astGetNin( this ) : astGetNout( this ); nout = !invert ? astGetNout( this ) : astGetNin( this ); /* Initialise the count of constants in use. */ nconst = 0; /* Write out values representing the instance variables for the PermMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* PermSplit */ /* --------- */ set = TestPermSplit( this, status ); ival = set ? GetPermSplit( this, status ) : astGetPermSplit( this ); astWriteInt( channel, "pmsplt", set, 0, ival, ival ? "Use alternative astMapSplit implementation" : "Use normal astMapSplit implementation" ); /* "outperm" array contents. */ /* ------------------------- */ /* Write the boolean "OutCpy" value to indicate if output coordinates are obtained simply by copying corresponding input coordinates. This will be the case if "this->outperm" is NULL. */ ival = this->outperm ? 0 : 1; set = ( ival != 0 ); astWriteInt( channel, "OutCpy", set, 0, ival, ival ? "Output coordinates = input coordinates" : "Output coordinates specified individually" ); /* If output coordinates are specified individually, create a keyword for each element of the "outperm" array. */ if ( this->outperm ) { for ( coord = 0; coord < nout; coord++ ) { (void) sprintf( key, "Out%d", coord + 1 ); /* Obtain the array value. If it refers to a coordinate that does not exist, change the value to zero (indicating a "bad" value for this coordinate). Create an appropriate comment. */ ival = this->outperm[ coord ]; if ( ival >= nin ) { ival = 0; (void) sprintf( comment, "Output coordinate %d is \"bad\"", coord + 1 ); /* If the coordinate reference is valid, convert to 1-based coordinate numbering and create an appropriate comment. */ } else if ( ival >= 0 ) { ival++; (void) sprintf( comment, "Output coordinate %d = input coordinate %d", coord + 1, ival ); /* If the reference is to a constant, create an appropriate comment (which depends on whether there are any constants). */ } else { if ( this->constant ) { (void) sprintf( comment, "Output coordinate %d = constant no. %d", coord + 1, -ival ); } else { (void) sprintf( comment, "Output coordinate %d is \"bad\"", coord + 1 ); } /* Update the top constant number referenced. */ if ( nconst < -ival ) nconst = -ival; } /* Write out the array value with accompanying comment. */ astWriteInt( channel, key, 1, 1, ival, comment ); } } /* "inperm" array contents. */ /* ------------------------ */ /* Write the boolean "InCpy" value to indicate if input coordinates are obtained simply by copying corresponding output coordinates. This will be the case if "this->inperm" is NULL. */ ival = this->inperm ? 0 : 1; set = ( ival != 0 ); astWriteInt( channel, "InCpy", set, 0, ival, ival ? "Input coordinates = output coordinates" : "Input coordinates specified individually" ); /* If input coordinates are specified individually, create a keyword for each element of the "inperm" array. */ if ( this->inperm ) { for ( coord = 0; coord < nin; coord++ ) { (void) sprintf( key, "In%d", coord + 1 ); /* Obtain the array value. If it refers to a coordinate that does not exist, change the value to zero (indicating a "bad" value for this coordinate). Create an appropriate comment. */ ival = this->inperm[ coord ]; if ( ival >= nout ) { ival = 0; (void) sprintf( comment, "Input coordinate %d is \"bad\"", coord + 1 ); /* If the coordinate reference is valid, convert to 1-based coordinate numbering and create an appropriate comment. */ } else if ( ival >= 0 ) { ival++; (void) sprintf( comment, "Input coordinate %d = output coordinate %d", coord + 1, ival ); /* If the reference is to a constant, create an appropriate comment (which depends on whether there are any constants). */ } else { if ( this->constant ) { (void) sprintf( comment, "Input coordinate %d = constant no. %d", coord + 1, -ival ); } else { (void) sprintf( comment, "Input coordinate %d is \"bad\"", coord + 1 ); } /* Update the top constant number referenced. */ if ( nconst < -ival ) nconst = -ival; } /* Write out the array value with accompanying comment. */ astWriteInt( channel, key, 1, 1, ival, comment ); } } /* Number of constants. */ /* -------------------- */ /* First check if there are any constants, then write out how many there are. */ if ( !this->constant ) nconst = 0; set = ( nconst != 0 ); astWriteInt( channel, "Nconst", set, 0, nconst, "Number of constants" ); /* Constants. */ /* ---------- */ /* Loop to create a keyword and comment for each constant. */ for ( iconst = 0; iconst < nconst; iconst++ ) { (void) sprintf( key, "Con%d", iconst + 1 ); (void) sprintf( comment, "Constant number %d", iconst + 1 ); /* Write out each constant value and comment. */ set = ( this->constant[ iconst ] != AST__BAD ); if ( set ) { astWriteDouble( channel, key, 1, 1, this->constant[ iconst ], comment ); } else { astWriteString( channel, key, 0, 1, "", comment ); } } /* Undefine macros local to this function. */ #undef COMMENT_LEN #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAPermMap and astCheckPermMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(PermMap,Mapping) astMAKE_CHECK(PermMap) AstPermMap *astPermMap_( int nin, const int inperm[], int nout, const int outperm[], const double constant[], const char *options, int *status, ...) { /* *++ * Name: c astPermMap f AST_PERMMAP * Purpose: * Create a PermMap. * Type: * Public function. * Synopsis: c #include "permmap.h" c AstPermMap *astPermMap( int nin, const int inperm[], int nout, c const int outperm[], double constant[], c const char *options, ... ) f RESULT = AST_PERMMAP( NIN, INPERM, NOUT, OUTPERM, CONSTANT, OPTIONS, f STATUS ) * Class Membership: * PermMap constructor. * Description: * This function creates a new PermMap and optionally initialises its * attributes. * * A PermMap is a Mapping which permutes the order of coordinates, * and possibly also changes the number of coordinates, between its * input and output. * * In addition to permuting the coordinate order, a PermMap may * also assign constant values to coordinates. This is useful when * the number of coordinates is being increased as it allows fixed * values to be assigned to any new ones. * Parameters: c nin f NIN = INTEGER (Given) * The number of input coordinates. c inperm f INPERM = INTEGER( NIN ) (Given) c An optional array with "nin" elements which, for each input f An array which, for each input * coordinate, should contain the number of the output * coordinate whose value is to be used (note that this array * therefore defines the inverse coordinate transformation). * Coordinates are numbered starting from 1. * * For details of additional special values that may be used in c this array, see the description of the "constant" parameter. f this array, see the description of the CONSTANT argument. c c If a NULL pointer is supplied instead of an array, each input c coordinate will obtain its value from the corresponding c output coordinate (or will be assigned the value AST__BAD if c there is no corresponding output coordinate). c nout f NOUT = INTEGER (Given) * The number of output coordinates. c outperm f OUTPERM = INTEGER( NOUT ) (Given) c An optional array with "nout" elements which, for each output f An array which, for each output * coordinate, should contain the number of the input coordinate * whose value is to be used (note that this array therefore * defines the forward coordinate transformation). Coordinates * are numbered starting from 1. * * For details of additional special values that may be used in c this array, see the description of the "constant" parameter. f this array, see the description of the CONSTANT argument. c c If a NULL pointer is supplied instead of an array, each output c coordinate will obtain its value from the corresponding c input coordinate (or will be assigned the value AST__BAD if c there is no corresponding input coordinate). c constant f CONSTANT = DOUBLE PRECISION( * ) (Given) c An optional array containing values which may be assigned to f An array containing values which may be assigned to * input and/or output coordinates instead of deriving them c from other coordinate values. If either of the "inperm" or f from other coordinate values. If either of the INPERM or c "outperm" arrays contains a negative value, it is used to f OUTPERM arrays contains a negative value, it is used to c address this "constant" array (such that -1 addresses the f address this CONSTANT array (such that -1 addresses the * first element, -2 addresses the second element, etc.) and the * value obtained is used as the corresponding coordinate value. * * Care should be taken to ensure that locations lying outside * the extent of this array are not accidentally addressed. The c array is not used if the "inperm" and "outperm" arrays do not f array is not used if the INPERM and OUTPERM arrays do not * contain negative values. c c If a NULL pointer is supplied instead of an array, the c behaviour is as if the array were of infinite length and c filled with the value AST__BAD. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new PermMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new PermMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astPermMap() f AST_PERMMAP = INTEGER * A pointer to the new PermMap. * Notes: c - If either of the "inperm" or "outperm" arrays contains a f - If either of the INPERM or OUTPERM arrays contains a * zero value (or a positive value which does not identify a valid * output/input coordinate, as appropriate), then the value * AST__BAD is assigned as the new coordinate value. * - This function does not attempt to ensure that the forward and * inverse transformations performed by the PermMap are * self-consistent in any way. You are therefore free to supply * coordinate permutation arrays that achieve whatever effect is * desired. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPermMap *new; /* Pointer to new PermMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the PermMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPermMap( NULL, sizeof( AstPermMap ), !class_init, &class_vtab, "PermMap", nin, inperm, nout, outperm, constant ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new PermMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new PermMap. */ return new; } AstPermMap *astPermMapId_( int nin, const int inperm[], int nout, const int outperm[], const double constant[], const char *options, ... ) { /* * Name: * astPermMapId_ * Purpose: * Create a PermMap. * Type: * Private function. * Synopsis: * #include "permmap.h" * AstPermMap *astPermMapId_( int nin, const int inperm[], int nout, * const int outperm[], const double constant[], * const char *options, ... ) * Class Membership: * PermMap constructor. * Description: * This function implements the external (public) interface to the * astPermMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astPermMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * This function also converts the coordinate numbering in the * permutation arrays from 1-based (used externally) to zero-based * (used internally). * * The variable argument list also prevents this function from * invoking astPermMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astPermMap_. * Returned Value: * The ID value associated with the new PermMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPermMap *new; /* Pointer to new PermMap */ int *inperm1; /* Pointer to temporary copy of "inperm" */ int *outperm1; /* Pointer to temporary copy of "outperm" */ int coord; /* Loop counter for coordinates */ /* Variable argument list */ va_list args; /* Get a pointer to the thread specific global data structure. */ int *status; /* Pointer to inherited status value */ astGET_GLOBALS(NULL); /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* If the "nin" and "nout" values are acceptable, allocate memory to hold temporary copies of the "inperm" and "outperm" arrays (but only if these arrays are not NULL). */ inperm1 = NULL; outperm1 = NULL; if ( ( nin >= 0 ) && ( nout >= 0 ) ) { if ( inperm ) inperm1 = astMalloc( sizeof( int ) * (size_t) nin ); if ( outperm ) outperm1 = astMalloc( sizeof( int ) * (size_t) nout ); if ( astOK ) { /* If necessary, make a copy of the "inperm" array, converting any zero values into (zero-based) coordinate numbers that do not exist, indicating a "bad" coordinate value. */ if ( inperm ) { for ( coord = 0; coord < nin; coord++ ) { if ( inperm[ coord ] < 0 ) { inperm1[ coord ] = inperm[ coord ]; } else if ( inperm[ coord ] == 0 ) { inperm1[ coord ] = nout; /* Convert valid coordinate references from 1-based (used externally) to zero-based (used internally). */ } else { inperm1[ coord ] = inperm[ coord ] - 1; } } } /* Repeat this process on the "outperm" array. */ if ( outperm ) { for ( coord = 0; coord < nout; coord++ ) { if ( outperm[ coord ] < 0 ) { outperm1[ coord ] = outperm[ coord ]; } else if ( outperm[ coord ] == 0 ) { outperm1[ coord ] = nin; } else { outperm1[ coord ] = outperm[ coord ] - 1; } } } } } /* Initialise the PermMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPermMap( NULL, sizeof( AstPermMap ), !class_init, &class_vtab, "PermMap", nin, inperm1, nout, outperm1, constant ); /* If necessary, free the temporary arrays allocated above. */ if ( ( nin >= 0 ) && ( nout >= 0 ) ) { if ( inperm ) inperm1 = astFree( inperm1 ); if ( outperm ) outperm1 = astFree( outperm1 ); } /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new PermMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new PermMap. */ return astMakeId( new ); } AstPermMap *astInitPermMap_( void *mem, size_t size, int init, AstPermMapVtab *vtab, const char *name, int nin, const int inperm[], int nout, const int outperm[], const double constant[], int *status ) { /* *+ * Name: * astInitPermMap * Purpose: * Initialise a PermMap. * Type: * Protected function. * Synopsis: * #include "permmap.h" * AstPermMap *astInitPermMap( void *mem, size_t size, int init, * AstPermMapVtab *vtab, const char *name, * int nin, const int inperm[], * int nout, const int outperm[], * const double constant[] ) * Class Membership: * PermMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new PermMap object. It allocates memory (if necessary) to accommodate * the PermMap plus any additional data associated with the derived class. * It then initialises a PermMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a PermMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the PermMap is to be initialised. * This must be of sufficient size to accommodate the PermMap data * (sizeof(PermMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the PermMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the PermMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the PermMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new PermMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * nin * The number of input coordinate values per point. * inperm * Pointer to an array of int, with nin elements. For each input * coordinate, the corresponding element of this array should contain the * (zero-based) index of the output coordinate whose value is to be used. * (Note that this array therefore defines the inverse coordinate * transformation.) If a NULL value is supplied, the corresponding output * coordinate value is used (or AST__BAD if there is no corresponding * output coordinate). * * For details of additional special values that may be used in this * array, see the description of the "constant" parameter. * nout * The number of output coordinate values per point. * outperm * Pointer to an array of int, with nout elements. For each output * coordinate, the corresponding element of this array should contain the * (zero-based) index of the input coordinate whose value is to be used. * (Note that this array therefore defines the forward coordinate * transformation.) If a NULL value is supplied, the corresponding input * coordinate value is used (or AST__BAD if there is no corresponding * input coordinate). * * For details of additional special values that may be used in this * array, see the description of the "constant" parameter. * constant * Pointer to an array of double, which contains optional values which * may be assigned to input and/or output coordinate values (instead of * deriving them from other coordinate values). If either of the * "inperm" or "outperm" arrays contains a negative value, it is used to * address this "constant" array (such that -1 addresses the first * element, -2 addresses the second element, etc.) and the value obtained * is used as the corresponding coordinate value. Care should be taken * to ensure that locations lying outside the extent of this array are * not accidentally addressed. * * If a NULL value is supplied for this parameter, the behaviour is as * if the constant array were of infinite length and filled with the * value AST__BAD. * Returned Value: * A pointer to the new PermMap. * Notes: * - This function does not attempt to ensure that the forward and inverse * transformations performed by the resulting PermMap are consistent in any * way. The caller is therefore free to define the permutation arrays to * achieve whatever effect is desired. * - If either of the "inperm" or "outperm" arrays contains a positive * value which does not identify a valid output/input coordinate (as * appropriate), then the value AST__BAD is assigned as the new coordinate * value. * - This function makes a copy of the contents of the arrays supplied. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstPermMap *new; /* Pointer to new PermMap */ int i; /* Loop counter for coordinates */ int neg; /* Most negative permutation index */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitPermMapVtab( vtab, name ); /* Initialise a Mapping structure (the parent class) as the first component within the PermMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstPermMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, nin, nout, 1, 1 ); if ( astOK ) { /* Initialise the PermMap data. */ /* ---------------------------- */ new->permsplit = -INT_MAX; /* Initialise the array pointers. */ new->inperm = NULL; new->outperm = NULL; new->constant = NULL; /* If an "inperm" and/or "outperm" array has been supplied, allocate memory and store a copy. */ if ( inperm ) new->inperm = astStore( NULL, inperm, sizeof( int ) * (size_t) nin ); if ( outperm ) new->outperm = astStore( NULL, outperm, sizeof( int ) * (size_t) nout ); /* If a "constant" array has been supplied, we must also store a copy of it, but must first determine how many of its elements we need. */ if ( constant ) { /* Loop through the "inperm" array (if supplied) to find the most negative value it contains. This corresponds with the maximum index into the constant array. */ neg = 0; if ( inperm ) { for ( i = 0; i < nin; i++ ) { if ( inperm[ i ] < neg ) neg = inperm[ i ]; } } /* Also perform this process on the "outperm" array (if supplied). */ if ( outperm ) { for ( i = 0; i < nout; i++ ) { if ( outperm[ i ] < neg ) neg = outperm[ i ]; } } /* If a negative value was found, use its size to determine how many elements of the "constant" array to store in allocated memory. */ if ( neg < 0 ) { new->constant = astStore( NULL, constant, sizeof( double ) * (size_t) (-neg) ); } } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) { new = astDelete( new ); } } /* Return a pointer to the new object. */ return new; } AstPermMap *astLoadPermMap_( void *mem, size_t size, AstPermMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadPermMap * Purpose: * Load a PermMap. * Type: * Protected function. * Synopsis: * #include "permmap.h" * AstPermMap *astLoadPermMap( void *mem, size_t size, * AstPermMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * PermMap loader. * Description: * This function is provided to load a new PermMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * PermMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a PermMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the PermMap is to be * loaded. This must be of sufficient size to accommodate the * PermMap data (sizeof(PermMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the PermMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the PermMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstPermMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new PermMap. If this is NULL, a pointer * to the (static) virtual function table for the PermMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "PermMap" is used instead. * Returned Value: * A pointer to the new PermMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstPermMap *new; /* Pointer to the new PermMap */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword strings */ int coord; /* Loop counter for coordinates */ int iconst; /* Loop counter for constants */ int in_cpy; /* Input coordinates obtained by copying? */ int invert; /* Invert attribute value */ int ival; /* Integer value */ int nconst; /* Number of constants */ int nin; /* Number of input coordinates */ int nout; /* Number of output coordinates */ int out_cpy; /* Output coordinates obtained by copying? */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this PermMap. In this case the PermMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstPermMap ); vtab = &class_vtab; name = "PermMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitPermMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built PermMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "PermMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Initialise the PermMap's pointers. */ new->inperm = NULL; new->outperm = NULL; new->constant = NULL; /* Determine if the PermMap is inverted and obtain the "true" number of input and output coordinates by un-doing the effects of any inversion. */ invert = astGetInvert( new ); nin = !invert ? astGetNin( new ) : astGetNout( new ); nout = !invert ? astGetNout( new ) : astGetNin( new ); /* PermSplit. */ /* ---------- */ new->permsplit = astReadInt( channel, "pmsplt", -INT_MAX ); if ( TestPermSplit( new, status ) ) SetPermSplit( new, new->permsplit, status ); /* InCpy and OutCpy. */ /* ----------------- */ /* Obtain boolean values via the "InCpy" and "OutCpy" keywords which indicate if input/output coordinates should be obtained simply by copying the corresponding output/input coordinates. */ in_cpy = astReadInt( channel, "incpy", 0 ); out_cpy = astReadInt( channel, "outcpy", 0 ); /* If coordinates are specified individually (not simply copied), then allocate memory for the coordinate permutation arrays. */ if ( !in_cpy ) new->inperm = astMalloc( sizeof( int ) * (size_t) nin ); if ( !out_cpy ) new->outperm = astMalloc( sizeof( int ) * (size_t) nout ); /* If an error occurred, ensure that all allocated memory is freed. */ if ( !astOK ) { if ( !in_cpy ) new->inperm = astFree( new->inperm ); if ( !out_cpy ) new->outperm = astFree( new->outperm ); /* Otherwise read data into these arrays... */ } else { /* "inperm" array contents. */ /* ------------------------ */ /* If required, create a keyword for each element of the "inperm" array and read the element's value. */ if ( !in_cpy ) { for ( coord = 0; coord < nin; coord++ ) { (void) sprintf( key, "in%d", coord + 1 ); ival = astReadInt( channel, key, 0 ); /* If the value is zero (indicating a "bad" coordinate), convert it to a (zero-based) coordinate number that doesn't exist. */ if ( ival == 0 ) { ival = nout; /* If the coordinate reference is valid, convert to zero-based coordinate numbering for internal use. */ } else if ( ival > 0 ) { ival--; } /* Store the value. */ new->inperm[ coord ] = ival; } } /* "outperm" array contents. */ /* ------------------------- */ /* If required, create a keyword for each element of the "outperm" array and read the element's value. */ if ( !out_cpy ) { for ( coord = 0; coord < nout; coord++ ) { (void) sprintf( key, "out%d", coord + 1 ); ival = astReadInt( channel, key, 0 ); /* If the value is zero (indicating a "bad" coordinate), convert it to a (zero-based) coordinate number that doesn't exist. */ if ( ival == 0 ) { ival = nin; /* If the coordinate reference is valid, convert to zero-based coordinate numbering for internal use. */ } else if ( ival > 0 ) { ival--; } /* Store the value. */ new->outperm[ coord ] = ival; } } /* Number of constants. */ /* -------------------- */ /* Determine the number of constants and allocate memory to hold them. */ nconst = astReadInt( channel, "nconst", 0 ); if ( nconst < 0 ) nconst = 0; new->constant = astMalloc( sizeof( double ) * (size_t) nconst ); if ( astOK ) { /* Constants. */ /* ---------- */ /* Create a keyword for each constant and read its value. */ for ( iconst = 0; iconst < nconst; iconst++ ) { (void) sprintf( key, "con%d", iconst + 1 ); new->constant[ iconst ] = astReadDouble( channel, key, AST__BAD ); } } } /* If an error occurred, clean up by deleting the new PermMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new PermMap pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ double *astGetConstants_( AstPermMap *this, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,PermMap,GetConstants))( this, status ); } int *astGetInPerm_( AstPermMap *this, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,PermMap,GetInPerm))( this, status ); } int *astGetOutPerm_( AstPermMap *this, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,PermMap,GetOutPerm))( this, status ); } ./ast-7.3.3/err_ems.c0000644000175000017500000000645612262533650012755 0ustar olesoles/* * Name: * err_ems.c * Purpose: * Implement the "err" module for the EMS error system. * Description: * This file implements an alternative "err" module for the AST * library. It is used to deliver error messages through the * Starlink EMS error message system (Starlink System Note 4) * rather than by the default mechanism. * Copyright: * Copyright (C) 2008 Science and Technology Facilities Council. * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (STARLINK) * {enter_new_authors_here} * History: * 6-NOV-1996 (DSB): * Original version. * 16-SEP-2008 (TIMJ): * Use modern EMS interface * {enter_changes_here} */ /* Module Macros. */ /* ============== */ /* Define the astCLASS macro (even although this is not a class implementation). This indicates to header files that they should make "protected" symbols available. */ #define astCLASS /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "err.h" /* Interface to this module */ #include "ems.h" /* Interface to the EMS system */ /* Function implementations. */ /* ========================= */ void astPutErr_( int status, const char *message ) { /* *+ * Name: * astPutErr * Purpose: * Deliver an error message. * Type: * Protected function. * Synopsis: * #include "err.h" * void astPutErr( int status, const char *message ) * Description: * This function delivers an error message and (optionally) an * accompanying status value to the user. It may be re-implemented * in order to deliver error messages in different ways, according * to the environment in which the AST library is being used. * Parameters: * status * The error status value. * message * A pointer to a null-terminated character string containing * the error message to be delivered. This should not contain * newline characters. * Notes: * - This function is documented as "protected" but, in fact, is * publicly accessible so that it may be re-implemented as * required. *- */ /* Local Variables: */ int local_status; /* Local status value */ /* Make a copy of the status value supplied. Then invoke ems_rep_c to report the error message through EMS and to associate the error status with it. Ignore any returned status value. */ local_status = status; emsRep( "AST_ERROR", message, &local_status ); } ./ast-7.3.3/keymap.h0000644000175000017500000007342212262533650012611 0ustar olesoles#if !defined( KEYMAP_INCLUDED ) /* Include this file only once */ #define KEYMAP_INCLUDED /* *+ * Name: * keymap.h * Type: * C include file. * Purpose: * Define the interface to the KeyMap class. * Invocation: * #include "keymap.h" * Description: * This include file defines the interface to the KeyMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The KeyMap class extends the Object class to represent a set of * key/value pairs. Keys are strings, and values can be integer, * floating point, string or Object - scalar of vector. * Inheritance: * The KeyMap class inherits from the Object class. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 13-NOV-2004 (DSB): * Original version. * 5-JUN-2006 (DSB): * Added support for single precision entries. * 7-MAR-2008 (DSB): * Added support for pointer ("P") entries. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Coordinate objects (parent class) */ /* C header files. */ /* --------------- */ /* Macros */ /* ====== */ /* Data type constants: */ #define AST__BADTYPE 0 #define AST__INTTYPE 1 #define AST__DOUBLETYPE 2 #define AST__STRINGTYPE 3 #define AST__OBJECTTYPE 4 #define AST__FLOATTYPE 5 #define AST__POINTERTYPE 6 #define AST__SINTTYPE 7 #define AST__UNDEFTYPE 8 #define AST__BYTETYPE 9 /* Define constants used to size global arrays in this module. */ #define AST__KEYMAP_GETATTRIB_BUFF_LEN 50 /* Max length of string returned by GetAttrib */ #define AST__KEYMAP_CONVERTVALUE_MAX_STRINGS 50 /* Number of string values to buffer in ConvertValue */ #define AST__KEYMAP_CONVERTVALUE_BUFF_LEN 50 /* Max. characters in result buffer for ConvertValue */ #define AST__KEYMAP_MAPKEY_MAX_STRINGS 50 /* Number of string values to buffer in MapKey */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Maximum key length when using case insensitive keymaps */ #define AST__MXKEYLEN 200 /* Type Definitions. */ /* ================= */ /* This structure contains information describing a single generic entry in a KeyMap. This structure is extended by other structures to hold data of specific data types. */ typedef struct AstMapEntry { struct AstMapEntry *next; /* Pointer to next structure in unsorted list. */ const char *key; /* The name used to identify the entry */ unsigned long hash; /* The full width hash value */ int type; /* Data type. */ int nel; /* 0 => scalar, >0 => array with "nel" elements */ const char *comment; /* Pointer to a comment for the entry */ int defined; /* Non-zero if the entry value is defined */ struct AstMapEntry *snext;/* Pointer to next structure in sorted list. */ struct AstMapEntry *sprev;/* Pointer to previous structure in sorted list. */ int member; /* No. of values added to KeyMap prior to this one */ int keymember; /* No. of keys added to KeyMap prior to this one */ int sortby; /* Used for comunnication with qsort function */ } AstMapEntry; /* KeyMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstKeyMap { /* Attributes inherited from the parent class. */ AstObject object; /* Parent class structure */ /* Attributes specific to objects in this class. */ int sizeguess; /* Guess at KeyMap size */ AstMapEntry **table; /* Hash table containing pointers to the KeyMap entries */ int *nentry; /* No. of Entries in each table element */ int mapsize; /* Length of table */ int keycase; /* Are keys case sensitive? */ int keyerror; /* Report error if no key? */ int maplocked; /* Prevent addition of new entries? */ int sortby; /* How the keys should be sorted */ AstMapEntry *first; /* Pointer to first structure in sorted list. */ int nsorted; /* Length of sorted list */ int member_count; /* Total no. of values ever added to keyMap */ AstMapEntry *firstA; /* Pointer to first "AST object"-type entry */ int iter_itab; /* Next hash table entry to return */ AstMapEntry *iter_entry; /* Next entry to return */ } AstKeyMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstKeyMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstObjectVtab object_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* MapPut0I)( AstKeyMap *, const char *, int, const char *, int * ); void (* MapPut0D)( AstKeyMap *, const char *, double, const char *, int * ); void (* MapPut0B)( AstKeyMap *, const char *, unsigned char, const char *, int * ); void (* MapPut0S)( AstKeyMap *, const char *, short int, const char *, int * ); void (* MapPut0F)( AstKeyMap *, const char *, float, const char *, int * ); void (* MapPut0C)( AstKeyMap *, const char *, const char *, const char *, int * ); void (* MapPut0A)( AstKeyMap *, const char *, AstObject *, const char *, int * ); void (* MapPut0P)( AstKeyMap *, const char *, void *, const char *, int * ); void (* MapPut1I)( AstKeyMap *, const char *, int, const int[], const char *, int * ); void (* MapPut1D)( AstKeyMap *, const char *, int, const double[], const char *, int * ); void (* MapPut1B)( AstKeyMap *, const char *, int, const unsigned char[], const char *, int * ); void (* MapPut1S)( AstKeyMap *, const char *, int, const short int[], const char *, int * ); void (* MapPut1F)( AstKeyMap *, const char *, int, const float[], const char *, int * ); void (* MapPut1C)( AstKeyMap *, const char *, int, const char *const [], const char *, int * ); void (* MapPut1A)( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * ); void (* MapPut1P)( AstKeyMap *, const char *, int, void *const [], const char *, int * ); void (* MapPutU)( AstKeyMap *, const char *, const char *, int * ); int (* MapGet0I)( AstKeyMap *, const char *, int *, int * ); int (* MapGet0D)( AstKeyMap *, const char *, double *, int * ); int (* MapGet0B)( AstKeyMap *, const char *, unsigned char *, int * ); int (* MapGet0S)( AstKeyMap *, const char *, short int *, int * ); int (* MapGet0F)( AstKeyMap *, const char *, float *, int * ); int (* MapGet0C)( AstKeyMap *, const char *, const char **, int * ); int (* MapGet0A)( AstKeyMap *, const char *, AstObject **, int * ); int (* MapGet0P)( AstKeyMap *, const char *, void **, int * ); int (* MapGet1A)( AstKeyMap *, const char *, int, int *, AstObject **, int * ); int (* MapGet1P)( AstKeyMap *, const char *, int, int *, void **, int * ); int (* MapGet1C)( AstKeyMap *, const char *, int, int, int *, char *, int * ); int (* MapGet1D)( AstKeyMap *, const char *, int, int *, double *, int * ); int (* MapGet1B)( AstKeyMap *, const char *, int, int *, unsigned char *, int * ); int (* MapGet1S)( AstKeyMap *, const char *, int, int *, short int *, int * ); int (* MapGet1F)( AstKeyMap *, const char *, int, int *, float *, int * ); int (* MapGet1I)( AstKeyMap *, const char *, int, int *, int *, int * ); int (* MapGetElemA)( AstKeyMap *, const char *, int, AstObject **, int * ); int (* MapGetElemP)( AstKeyMap *, const char *, int, void **, int * ); int (* MapGetElemC)( AstKeyMap *, const char *, int, int, char *, int * ); int (* MapGetElemD)( AstKeyMap *, const char *, int, double *, int * ); int (* MapGetElemB)( AstKeyMap *, const char *, int, unsigned char *, int * ); int (* MapGetElemS)( AstKeyMap *, const char *, int, short int *, int * ); int (* MapGetElemF)( AstKeyMap *, const char *, int, float *, int * ); int (* MapGetElemI)( AstKeyMap *, const char *, int, int *, int * ); void (* MapPutElemA)( AstKeyMap *, const char *, int, AstObject *, int * ); void (* MapPutElemP)( AstKeyMap *, const char *, int, void *, int * ); void (* MapPutElemC)( AstKeyMap *, const char *, int, const char *, int * ); void (* MapPutElemD)( AstKeyMap *, const char *, int, double, int * ); void (* MapPutElemB)( AstKeyMap *, const char *, int, unsigned char, int * ); void (* MapPutElemS)( AstKeyMap *, const char *, int, short int, int * ); void (* MapPutElemF)( AstKeyMap *, const char *, int, float, int * ); void (* MapPutElemI)( AstKeyMap *, const char *, int, int, int * ); void (* MapRemove)( AstKeyMap *, const char *, int * ); void (* MapRename)( AstKeyMap *, const char *, const char *, int * ); void (* MapCopy)( AstKeyMap *, AstKeyMap *, int * ); int (* MapSize)( AstKeyMap *, int * ); int (* MapLength)( AstKeyMap *, const char *, int * ); int (* MapLenC)( AstKeyMap *, const char *, int * ); int (* MapType)( AstKeyMap *, const char *, int * ); int (* MapHasKey)( AstKeyMap *, const char *, int * ); int (* MapDefined)( AstKeyMap *, const char *, int * ); const char *(* MapIterate)( AstKeyMap *, int, int * ); const char *(* MapKey)( AstKeyMap *, int, int * ); int (* GetSizeGuess)( AstKeyMap *, int * ); int (* TestSizeGuess)( AstKeyMap *, int * ); void (* SetSizeGuess)( AstKeyMap *, int, int * ); void (* ClearSizeGuess)( AstKeyMap *, int * ); int (* GetMapLocked)( AstKeyMap *, int * ); int (* TestMapLocked)( AstKeyMap *, int * ); void (* ClearMapLocked)( AstKeyMap *, int * ); void (* SetMapLocked)( AstKeyMap *, int, int * ); int (* GetKeyError)( AstKeyMap *, int * ); int (* TestKeyError)( AstKeyMap *, int * ); void (* ClearKeyError)( AstKeyMap *, int * ); void (* SetKeyError)( AstKeyMap *, int, int * ); int (* GetKeyCase)( AstKeyMap *, int * ); int (* TestKeyCase)( AstKeyMap *, int * ); void (* ClearKeyCase)( AstKeyMap *, int * ); void (* SetKeyCase)( AstKeyMap *, int, int * ); int (* GetSortBy)( AstKeyMap *, int * ); int (* TestSortBy)( AstKeyMap *, int * ); void (* ClearSortBy)( AstKeyMap *, int * ); void (* SetSortBy)( AstKeyMap *, int, int * ); } AstKeyMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstKeyMapGlobals { AstKeyMapVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ AST__KEYMAP_GETATTRIB_BUFF_LEN + 1 ]; char *ConvertValue_Strings[ AST__KEYMAP_CONVERTVALUE_MAX_STRINGS ]; int ConvertValue_Istr; int ConvertValue_Init; char ConvertValue_Buff[ AST__KEYMAP_CONVERTVALUE_BUFF_LEN + 1 ]; char *MapKey_Strings[ AST__KEYMAP_MAPKEY_MAX_STRINGS ]; int MapKey_Istr; int MapKey_Init; } AstKeyMapGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(KeyMap) /* Check class membership */ astPROTO_ISA(KeyMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstKeyMap *astKeyMap_( const char *, int *, ...); #else AstKeyMap *astKeyMapId_( const char *, ... )__attribute__((format(printf,1,2))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstKeyMap *astInitKeyMap_( void *, size_t, int, AstKeyMapVtab *, const char *, int * ); /* Vtab initialiser. */ void astInitKeyMapVtab_( AstKeyMapVtab *, const char *, int * ); /* Loader. */ AstKeyMap *astLoadKeyMap_( void *, size_t, AstKeyMapVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitKeyMapGlobals_( AstKeyMapGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ #if defined(astCLASS) /* Protected */ int astMapGet0A_( AstKeyMap *, const char *, AstObject **, int * ); int astMapGet1A_( AstKeyMap *, const char *, int, int *, AstObject **, int * ); void astMapPut1A_( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * ); int astMapGetElemA_( AstKeyMap *, const char *, int, AstObject **, int * ); #else int astMapGet0AId_( AstKeyMap *, const char *, AstObject **, int * ); int astMapGet1AId_( AstKeyMap *, const char *, int, int *, AstObject **, int * ); void astMapPut1AId_( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * ); int astMapGetElemAId_( AstKeyMap *, const char *, int, AstObject **, int * ); #endif const char *astMapKey_( AstKeyMap *, int, int * ); int astMapGet0B_( AstKeyMap *, const char *, unsigned char *, int * ); int astMapGet0C_( AstKeyMap *, const char *, const char **, int * ); int astMapGet0D_( AstKeyMap *, const char *, double *, int * ); int astMapGet0F_( AstKeyMap *, const char *, float *, int * ); int astMapGet0I_( AstKeyMap *, const char *, int *, int * ); int astMapGet0P_( AstKeyMap *, const char *, void **, int * ); int astMapGet0S_( AstKeyMap *, const char *, short int *, int * ); int astMapGet1B_( AstKeyMap *, const char *, int, int *, unsigned char *, int * ); int astMapGet1C_( AstKeyMap *, const char *, int, int, int *, char *, int * ); int astMapGet1D_( AstKeyMap *, const char *, int, int *, double *, int * ); int astMapGet1F_( AstKeyMap *, const char *, int, int *, float *, int * ); int astMapGet1I_( AstKeyMap *, const char *, int, int *, int *, int * ); int astMapGet1P_( AstKeyMap *, const char *, int, int *, void **, int * ); int astMapGet1S_( AstKeyMap *, const char *, int, int *, short int *, int * ); int astMapGetElemB_( AstKeyMap *, const char *, int, unsigned char *, int * ); int astMapGetElemC_( AstKeyMap *, const char *, int, int, char *, int * ); int astMapGetElemD_( AstKeyMap *, const char *, int, double *, int * ); int astMapGetElemF_( AstKeyMap *, const char *, int, float *, int * ); int astMapGetElemI_( AstKeyMap *, const char *, int, int *, int * ); int astMapGetElemP_( AstKeyMap *, const char *, int, void **, int * ); int astMapGetElemS_( AstKeyMap *, const char *, int, short int *, int * ); int astMapHasKey_( AstKeyMap *, const char *, int * ); int astMapDefined_( AstKeyMap *, const char *, int * ); int astMapLenC_( AstKeyMap *, const char *, int * ); int astMapLength_( AstKeyMap *, const char *, int * ); int astMapSize_( AstKeyMap *, int * ); int astMapType_( AstKeyMap *, const char *, int * ); void astMapCopy_( AstKeyMap *, AstKeyMap *, int * ); void astMapPut0A_( AstKeyMap *, const char *, AstObject *, const char *, int * ); void astMapPut0B_( AstKeyMap *, const char *, unsigned char, const char *, int * ); void astMapPut0C_( AstKeyMap *, const char *, const char *, const char *, int * ); void astMapPut0D_( AstKeyMap *, const char *, double, const char *, int * ); void astMapPut0F_( AstKeyMap *, const char *, float, const char *, int * ); void astMapPut0I_( AstKeyMap *, const char *, int, const char *, int * ); void astMapPut0P_( AstKeyMap *, const char *, void *, const char *, int * ); void astMapPut0S_( AstKeyMap *, const char *, short int, const char *, int * ); void astMapPut1B_( AstKeyMap *, const char *, int, const unsigned char[], const char *, int * ); void astMapPut1C_( AstKeyMap *, const char *, int, const char *const [], const char *, int * ); void astMapPut1D_( AstKeyMap *, const char *, int, const double *, const char *, int * ); void astMapPut1F_( AstKeyMap *, const char *, int, const float *, const char *, int * ); void astMapPut1I_( AstKeyMap *, const char *, int, const int *, const char *, int * ); void astMapPut1P_( AstKeyMap *, const char *, int, void *const [], const char *, int * ); void astMapPut1S_( AstKeyMap *, const char *, int, const short int *, const char *, int * ); void astMapPutElemA_( AstKeyMap *, const char *, int, AstObject *, int * ); void astMapPutElemB_( AstKeyMap *, const char *, int, unsigned char, int * ); void astMapPutElemC_( AstKeyMap *, const char *, int, const char *, int * ); void astMapPutElemD_( AstKeyMap *, const char *, int, double, int * ); void astMapPutElemF_( AstKeyMap *, const char *, int, float, int * ); void astMapPutElemI_( AstKeyMap *, const char *, int, int, int * ); void astMapPutElemP_( AstKeyMap *, const char *, int, void *, int * ); void astMapPutElemS_( AstKeyMap *, const char *, int, short int, int * ); void astMapPutU_( AstKeyMap *, const char *, const char *, int * ); void astMapRemove_( AstKeyMap *, const char *, int * ); void astMapRename_( AstKeyMap *, const char *, const char *, int * ); #if defined(astCLASS) /* Protected */ const char *astMapIterate_( AstKeyMap *, int, int * ); int astGetSizeGuess_( AstKeyMap *, int * ); int astTestSizeGuess_( AstKeyMap *, int * ); void astSetSizeGuess_( AstKeyMap *, int, int * ); void astClearSizeGuess_( AstKeyMap *, int * ); int astGetKeyError_( AstKeyMap *, int * ); int astTestKeyError_( AstKeyMap *, int * ); void astSetKeyError_( AstKeyMap *, int, int * ); void astClearKeyError_( AstKeyMap *, int * ); int astGetKeyCase_( AstKeyMap *, int * ); int astTestKeyCase_( AstKeyMap *, int * ); void astSetKeyCase_( AstKeyMap *, int, int * ); void astClearKeyCase_( AstKeyMap *, int * ); int astGetSortBy_( AstKeyMap *, int * ); int astTestSortBy_( AstKeyMap *, int * ); void astSetSortBy_( AstKeyMap *, int, int * ); void astClearSortBy_( AstKeyMap *, int * ); int astGetMapLocked_( AstKeyMap *, int * ); int astTestMapLocked_( AstKeyMap *, int * ); void astSetMapLocked_( AstKeyMap *, int, int * ); void astClearMapLocked_( AstKeyMap *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckKeyMap(this) astINVOKE_CHECK(KeyMap,this,0) #define astVerifyKeyMap(this) astINVOKE_CHECK(KeyMap,this,1) /* Test class membership. */ #define astIsAKeyMap(this) astINVOKE_ISA(KeyMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astKeyMap astINVOKE(F,astKeyMap_) #else #define astKeyMap astINVOKE(F,astKeyMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitKeyMap(mem,size,init,vtab,name) astINVOKE(O,astInitKeyMap_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitKeyMapVtab(vtab,name) astINVOKE(V,astInitKeyMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadKeyMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadKeyMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckKeyMap to validate KeyMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astMapPutU(this,key,comment) astINVOKE(V,astMapPutU_(astCheckKeyMap(this),key,comment,STATUS_PTR)) #define astMapPut0I(this,key,value,comment) astINVOKE(V,astMapPut0I_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0B(this,key,value,comment) astINVOKE(V,astMapPut0B_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0S(this,key,value,comment) astINVOKE(V,astMapPut0S_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0D(this,key,value,comment) astINVOKE(V,astMapPut0D_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0F(this,key,value,comment) astINVOKE(V,astMapPut0F_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0C(this,key,value,comment) astINVOKE(V,astMapPut0C_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut0A(this,key,value,comment) astINVOKE(V,astMapPut0A_(astCheckKeyMap(this),key,astCheckObject(value),comment,STATUS_PTR)) #define astMapPut0P(this,key,value,comment) astINVOKE(V,astMapPut0P_(astCheckKeyMap(this),key,value,comment,STATUS_PTR)) #define astMapPut1I(this,key,size,value,comment) astINVOKE(V,astMapPut1I_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapPut1B(this,key,size,value,comment) astINVOKE(V,astMapPut1B_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapPut1S(this,key,size,value,comment) astINVOKE(V,astMapPut1S_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapPut1D(this,key,size,value,comment) astINVOKE(V,astMapPut1D_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapPut1F(this,key,size,value,comment) astINVOKE(V,astMapPut1F_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapPut1C(this,key,size,value,comment) astINVOKE(V,astMapPut1C_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapGet0I(this,key,value) astINVOKE(V,astMapGet0I_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet0B(this,key,value) astINVOKE(V,astMapGet0B_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet0S(this,key,value) astINVOKE(V,astMapGet0S_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet0D(this,key,value) astINVOKE(V,astMapGet0D_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet0F(this,key,value) astINVOKE(V,astMapGet0F_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet0C(this,key,value) astINVOKE(V,astMapGet0C_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet1I(this,key,mxval,nval,value) astINVOKE(V,astMapGet1I_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapGet1B(this,key,mxval,nval,value) astINVOKE(V,astMapGet1B_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapGet1S(this,key,mxval,nval,value) astINVOKE(V,astMapGet1S_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapGet1D(this,key,mxval,nval,value) astINVOKE(V,astMapGet1D_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapGet1F(this,key,mxval,nval,value) astINVOKE(V,astMapGet1F_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapGet1C(this,key,l,mxval,nval,value) astINVOKE(V,astMapGet1C_(astCheckKeyMap(this),key,l,mxval,nval,value,STATUS_PTR)) #define astMapGetElemI(this,key,elem,value) astINVOKE(V,astMapGetElemI_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapGetElemB(this,key,elem,value) astINVOKE(V,astMapGetElemB_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapGetElemS(this,key,elem,value) astINVOKE(V,astMapGetElemS_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapGetElemD(this,key,elem,value) astINVOKE(V,astMapGetElemD_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapGetElemF(this,key,elem,value) astINVOKE(V,astMapGetElemF_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapGetElemC(this,key,l,elem,value) astINVOKE(V,astMapGetElemC_(astCheckKeyMap(this),key,l,elem,value,STATUS_PTR)) #define astMapGetElemP(this,key,elem,value) astINVOKE(V,astMapGetElemP_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemA(this,key,elem,value) astINVOKE(V,astMapPutElemA_(astCheckKeyMap(this),key,elem,astCheckObject(value),STATUS_PTR)) #define astMapPutElemI(this,key,elem,value) astINVOKE(V,astMapPutElemI_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemB(this,key,elem,value) astINVOKE(V,astMapPutElemB_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemS(this,key,elem,value) astINVOKE(V,astMapPutElemS_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemD(this,key,elem,value) astINVOKE(V,astMapPutElemD_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemF(this,key,elem,value) astINVOKE(V,astMapPutElemF_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemC(this,key,elem,value) astINVOKE(V,astMapPutElemC_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapPutElemP(this,key,elem,value) astINVOKE(V,astMapPutElemP_(astCheckKeyMap(this),key,elem,value,STATUS_PTR)) #define astMapRemove(this,key) astINVOKE(V,astMapRemove_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapRename(this,oldkey,newkey) astINVOKE(V,astMapRename_(astCheckKeyMap(this),oldkey,newkey,STATUS_PTR)) #define astMapCopy(this,that) astINVOKE(V,astMapCopy_(astCheckKeyMap(this),astCheckKeyMap(that),STATUS_PTR)) #define astMapSize(this) astINVOKE(V,astMapSize_(astCheckKeyMap(this),STATUS_PTR)) #define astMapLength(this,key) astINVOKE(V,astMapLength_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapLenC(this,key) astINVOKE(V,astMapLenC_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapHasKey(this,key) astINVOKE(V,astMapHasKey_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapDefined(this,key) astINVOKE(V,astMapDefined_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapKey(this,index) astINVOKE(V,astMapKey_(astCheckKeyMap(this),index,STATUS_PTR)) #define astMapType(this,key) astINVOKE(V,astMapType_(astCheckKeyMap(this),key,STATUS_PTR)) #define astMapGet0P(this,key,value) astINVOKE(V,astMapGet0P_(astCheckKeyMap(this),key,value,STATUS_PTR)) #define astMapGet1P(this,key,mxval,nval,value) astINVOKE(V,astMapGet1P_(astCheckKeyMap(this),key,mxval,nval,value,STATUS_PTR)) #define astMapPut1P(this,key,size,value,comment) astINVOKE(V,astMapPut1P_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astMapGet0A(this,key,value) astINVOKE(V,astMapGet0A_(astCheckKeyMap(this),key,(AstObject **)(value),STATUS_PTR)) #define astMapGet1A(this,key,mxval,nval,value) astINVOKE(V,astMapGet1A_(astCheckKeyMap(this),key,mxval,nval,(AstObject **)(value),STATUS_PTR)) #define astMapPut1A(this,key,size,value,comment) astINVOKE(V,astMapPut1A_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapGetElemA(this,key,elem,value) astINVOKE(V,astMapGetElemA_(astCheckKeyMap(this),key,elem,(AstObject **)(value),STATUS_PTR)) #define astMapIterate(this,reset) astINVOKE(V,astMapIterate_(astCheckKeyMap(this),reset,STATUS_PTR)) #define astClearSizeGuess(this) \ astINVOKE(V,astClearSizeGuess_(astCheckKeyMap(this),STATUS_PTR)) #define astGetSizeGuess(this) \ astINVOKE(V,astGetSizeGuess_(astCheckKeyMap(this),STATUS_PTR)) #define astSetSizeGuess(this,sizeguess) \ astINVOKE(V,astSetSizeGuess_(astCheckKeyMap(this),sizeguess,STATUS_PTR)) #define astTestSizeGuess(this) \ astINVOKE(V,astTestSizeGuess_(astCheckKeyMap(this),STATUS_PTR)) #define astClearKeyError(this) \ astINVOKE(V,astClearKeyError_(astCheckKeyMap(this),STATUS_PTR)) #define astGetKeyError(this) \ astINVOKE(V,astGetKeyError_(astCheckKeyMap(this),STATUS_PTR)) #define astSetKeyError(this,keyerror) \ astINVOKE(V,astSetKeyError_(astCheckKeyMap(this),keyerror,STATUS_PTR)) #define astTestKeyError(this) \ astINVOKE(V,astTestKeyError_(astCheckKeyMap(this),STATUS_PTR)) #define astClearKeyCase(this) \ astINVOKE(V,astClearKeyCase_(astCheckKeyMap(this),STATUS_PTR)) #define astGetKeyCase(this) \ astINVOKE(V,astGetKeyCase_(astCheckKeyMap(this),STATUS_PTR)) #define astSetKeyCase(this,keycase) \ astINVOKE(V,astSetKeyCase_(astCheckKeyMap(this),keycase,STATUS_PTR)) #define astTestKeyCase(this) \ astINVOKE(V,astTestKeyCase_(astCheckKeyMap(this),STATUS_PTR)) #define astClearSortBy(this) \ astINVOKE(V,astClearSortBy_(astCheckKeyMap(this),STATUS_PTR)) #define astGetSortBy(this) \ astINVOKE(V,astGetSortBy_(astCheckKeyMap(this),STATUS_PTR)) #define astSetSortBy(this,sortby) \ astINVOKE(V,astSetSortBy_(astCheckKeyMap(this),sortby,STATUS_PTR)) #define astTestSortBy(this) \ astINVOKE(V,astTestSortBy_(astCheckKeyMap(this),STATUS_PTR)) #define astClearMapLocked(this) \ astINVOKE(V,astClearMapLocked_(astCheckKeyMap(this),STATUS_PTR)) #define astGetMapLocked(this) \ astINVOKE(V,astGetMapLocked_(astCheckKeyMap(this),STATUS_PTR)) #define astSetMapLocked(this,maplocked) \ astINVOKE(V,astSetMapLocked_(astCheckKeyMap(this),maplocked,STATUS_PTR)) #define astTestMapLocked(this) \ astINVOKE(V,astTestMapLocked_(astCheckKeyMap(this),STATUS_PTR)) #else #define astMapGet0A(this,key,value) astINVOKE(V,astMapGet0AId_(astCheckKeyMap(this),key,(AstObject **)(value),STATUS_PTR)) #define astMapGet1A(this,key,mxval,nval,value) astINVOKE(V,astMapGet1AId_(astCheckKeyMap(this),key,mxval,nval,(AstObject **)(value),STATUS_PTR)) #define astMapPut1A(this,key,size,value,comment) astINVOKE(V,astMapPut1AId_(astCheckKeyMap(this),key,size,value,comment,STATUS_PTR)) #define astMapGetElemA(this,key,elem,value) astINVOKE(V,astMapGetElemAId_(astCheckKeyMap(this),key,elem,(AstObject **)(value),STATUS_PTR)) #endif #endif ./ast-7.3.3/specframe.c0000644000175000017500000077226112262533650013272 0ustar olesoles/* *class++ * Name: * SpecFrame * Purpose: * Spectral coordinate system description. * Constructor Function: c astSpecFrame f AST_SPECFRAME * Description: * A SpecFrame is a specialised form of one-dimensional Frame which * represents various coordinate systems used to describe positions within * an electro-magnetic spectrum. The particular coordinate system to be * used is specified by setting the SpecFrame's System attribute (the * default is wavelength) qualified, as necessary, by other attributes * such as the rest frequency, the standard of rest, the epoch of * observation, units, etc (see the description of the System attribute * for details). * * By setting a value for thr SpecOrigin attribute, a SpecFrame can be made * to represent offsets from a given spectral position, rather than absolute * spectral values. * Inheritance: * The SpecFrame class inherits from the Frame class. * Attributes: * In addition to those attributes common to all Frames, every * SpecFrame also has the following attributes: * * - AlignSpecOffset: Align SpecFrames using the offset coordinate system? * - AlignStdOfRest: Standard of rest in which to align SpecFrames * - RefDec: Declination of the source (FK5 J2000) * - RefRA: Right ascension of the source (FK5 J2000) * - RestFreq: Rest frequency * - SourceSys: Source velocity spectral system * - SourceVel: Source velocity * - SourceVRF: Source velocity rest frame * - SpecOrigin: The zero point for SpecFrame axis values * - StdOfRest: Standard of rest * * Several of the Frame attributes inherited by the SpecFrame class * refer to a specific axis of the Frame (for instance Unit(axis), * Label(axis), etc). Since a SpecFrame is strictly one-dimensional, * it allows these attributes to be specified without an axis index. * So for instance, "Unit" is allowed in place of "Unit(1)". * Functions: c In addition to those functions applicable to all Frames, the c following functions may also be applied to all SpecFrames: f In addition to those routines applicable to all Frames, the f following routines may also be applied to all SpecFrames: * c - astSetRefPos: Set reference position in any celestial system f - AST_SETREFPOS: Set reference position in any celestial system c - astGetRefPos: Get reference position in any celestial system f - AST_GETREFPOS: Get reference position in any celestial system * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 4-NOV-2002 (DSB): * Original version. * 2-FEB-2005 (DSB): * - Avoid using astStore to allocate more storage than is supplied * in the "data" pointer. This can cause access violations since * astStore will then read beyond the end of the "data" area. * 22-MAR-2005 (DSB): * - Re-structure MakeSpecMapping in order to avoid unnecessary * access to SpecFrame attributes which may not be set, and to * check that all required attributes have been set if UseDefs is * zero. * 23-MAR-2005 (DSB): * - Added missing rest frames to SorEqual. * 12-AUG-2005 (DSB): * - Remove GeoLon and GeoLat attributes. Use the new ObsLon and * ObsLat attributes in the parent Frame class instead. Note, for * backward compatibility the public attribute accessors and the * astLoadSpecFrame functions still recogonise GeoLon and GeoLat, * but use the ObsLat/ObsLon attributes internally. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 1-MAR-2006 (DSB): * Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM. * 6-OCT-2006 (DSB): * Guard against annulling null pointers in subFrame. * 18-OCT-2006 (DSB): * Added SpecOrigin and AlignSpecOffset attributes. * 23-OCT-2006 (DSB): * Fix memory leak caused by addition of SpecOrigin and AlignSpecOffset * attributes. * 15-NOV-2006 (DSB): * Only write out SpecOrigin if it is not bad. * 8-JAN-2006 (DSB): * - SubFrame: Copy the SourceSystem and SourceStdOfRest attributes * to the System and StdOfRest attributes of the "align_frm" * SpecFrame before calling MakeSpecMapping. Previously, the * values assigned to SourceSystem and SourceStdOfRest were * ignored, and alignment was always performed in the templates System * and StdOfRest. * - MakeSpecMapping: Correct logic used to decide if steps 2 and 7 * can be cancelled. * - OriginSystem: Clear the AlignSpecOffset attributes before * finding the Mapping between the old and new Systems. * 16-JAN-2006 (DSB): * Fix bug in Dump that caused SrcVRF not to be written out. * 31-JAN-2007 (DSB): * Modified so that a SpecFrame can be used as a template to find a * SpecFrame contained within a CmpFrame. This involves changes in * Match and the removal of the local versions of SetMaxAxes and * SetMinAxes. * 8-AUG-2007 (DSB): * Changed Overlay to avoid the possibility of making permanent * changes to the supplied template Frame. * 3-SEP-2007 (DSB): * In SubFrame, since AlignSystem is extended by the SpecFrame class * it needs to be cleared before invoking the parent SubFrame * method in cases where the result Frame is not a SkyFrame. * 2-OCT-2007 (DSB): * In Overlay, clear AlignSystem as well as System before calling * the parent overlay method. * 4-SEP-2009 (DSB): * In MakeSpecMapping, in order to produce alignment that is not * affected by the epoch or reference position, make the alignment * frame adapt to the epoch and reference position of the target * and result Frames. * 14-SEP-2009 (DSB): * In MakeSpecMapping, extend the 4-SEP-2009 fix to cover other * attributes that define the available rest frames (e.g. * SourceVRF, SourceVel, ObsLat, ObsLon, ObsAlt). * 16-SEP-2009 (DSB): * In MakeSpecMapping, retain the original alignment frame attribute * values if we are restoring the integrity of a FrameSet. * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SpecFrame /* Define the first and last acceptable System values. */ #define FIRST_SYSTEM AST__FREQ #define LAST_SYSTEM AST__VREL /* Define the first and last acceptable StdOfRest values. */ #define FIRST_SOR AST__TPSOR #define LAST_SOR AST__SCSOR /* The supported spectral coordinate systems fall into two groups; "relative", and "absolute". The relative systems define each axis value with respect to the rest frequency, whereas the absolute systems have axis values which do not depend on the rest frequency. Define a macro which returns one if the specified system is absolute, and zero otherwise. */ #define ABS_SYSTEM(sys) \ ( ( sys == AST__ENERGY || \ sys == AST__WAVENUM || \ sys == AST__WAVELEN || \ sys == AST__AIRWAVE || \ sys == AST__FREQ ) ? 1 : 0 ) /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Define other numerical constants for use in this module. */ #define GETATTRIB_BUFF_LEN 50 #define GETLABEL_BUFF_LEN 200 #define GETSYMBOL_BUFF_LEN 20 #define GETTITLE_BUFF_LEN 200 /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "unit.h" /* Units management facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "specmap.h" /* Spectral coordinate Mappings */ #include "frame.h" /* Parent Frame class */ #include "skyframe.h" /* Celestial coordinate frames */ #include "specframe.h" /* Interface definition for this class */ #include "mapping.h" /* Coordinate Mappings */ #include "cmpmap.h" /* Compound Mappings */ #include "unitmap.h" /* Unit Mappings */ #include "pal.h" /* SlaLib interface */ #include "shiftmap.h" /* Change of origin */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are used or extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstSystemType (* parent_getalignsystem)( AstFrame *, int * ); static AstSystemType (* parent_getsystem)( AstFrame *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static const char *(* parent_getdomain)( AstFrame *, int * ); static const char *(* parent_getlabel)( AstFrame *, int, int * ); static const char *(* parent_getsymbol)( AstFrame *, int, int * ); static const char *(* parent_gettitle)( AstFrame *, int * ); static const char *(* parent_getunit)( AstFrame *, int, int * ); static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_setunit)( AstFrame *, int, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_setsystem)( AstFrame *, AstSystemType, int * ); static void (* parent_clearsystem)( AstFrame *, int * ); static void (* parent_clearunit)( AstFrame *, int, int * ); /* Define a variable to hold a SkyFrame which will be used for formatting and unformatting sky positions, etc. */ static AstSkyFrame *skyframe; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->GetLabel_Buff[ 0 ] = 0; \ globals->GetSymbol_Buff[ 0 ] = 0; \ globals->GetTitle_Buff[ 0 ] = 0; \ /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SpecFrame) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SpecFrame,Class_Init) #define class_vtab astGLOBAL(SpecFrame,Class_Vtab) #define getattrib_buff astGLOBAL(SpecFrame,GetAttrib_Buff) #define getlabel_buff astGLOBAL(SpecFrame,GetLabel_Buff) #define getsymbol_buff astGLOBAL(SpecFrame,GetSymbol_Buff) #define gettitle_buff astGLOBAL(SpecFrame,GetTitle_Buff) static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Buffer returned by GetAttrib. */ static char getattrib_buff[ 51 ]; /* Default GetLabel string buffer */ static char getlabel_buff[ 201 ]; /* Default GetSymbol buffer */ static char getsymbol_buff[ 21 ]; /* Default Title string buffer */ static char gettitle_buff[ 201 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSpecFrameVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #endif /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstStdOfRestType StdOfRestCode( const char *, int * ); static int GetObjSize( AstObject *, int * ); static AstSystemType GetAlignSystem( AstFrame *, int * ); static AstSystemType SystemCode( AstFrame *, const char *, int * ); static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * ); static const char *DefUnit( AstSystemType, const char *, const char *, int * ); static const char *GetDomain( AstFrame *, int * ); static const char *GetLabel( AstFrame *, int, int * ); static const char *GetSymbol( AstFrame *, int, int * ); static const char *GetTitle( AstFrame *, int * ); static const char *GetUnit( AstFrame *, int, int * ); static const char *SpecMapUnit( AstSystemType, const char *, const char *, int * ); static const char *StdOfRestString( AstStdOfRestType, int * ); static const char *SystemLabel( AstSystemType, int * ); static const char *SystemString( AstFrame *, AstSystemType, int * ); static double ConvertSourceVel( AstSpecFrame *, AstStdOfRestType, AstSystemType, int * ); static int EqualSor( AstSpecFrame *, AstSpecFrame *, int * ); static int GetActiveUnit( AstFrame *, int * ); static int MakeSpecMapping( AstSpecFrame *, AstSpecFrame *, AstSpecFrame *, int, AstMapping **, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int SorConvert( AstSpecFrame *, AstSpecFrame *, AstSpecMap *, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int TestActiveUnit( AstFrame *, int * ); static void ClearUnit( AstFrame *, int, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void GetRefPos( AstSpecFrame *, AstSkyFrame *, double *, double *, int * ); static void Overlay( AstFrame *, const int *, AstFrame *, int * ); static void SetRefPos( AstSpecFrame *, AstSkyFrame *, double, double, int * ); static void SetUnit( AstFrame *, int, const char *, int * ); static void VerifyAttrs( AstSpecFrame *, const char *, const char *, const char *, int * ); static double ToUnits( AstSpecFrame *, const char *, double, const char *, int * ); static void OriginStdOfRest( AstSpecFrame *, AstStdOfRestType, const char *, int * ); static void OriginSystem( AstSpecFrame *, AstSystemType, const char *, int * ); static AstSystemType GetSystem( AstFrame *, int * ); static void SetSystem( AstFrame *, AstSystemType, int * ); static void ClearSystem( AstFrame *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static AstStdOfRestType GetAlignStdOfRest( AstSpecFrame *, int * ); static int TestAlignStdOfRest( AstSpecFrame *, int * ); static void ClearAlignStdOfRest( AstSpecFrame *, int * ); static void SetAlignStdOfRest( AstSpecFrame *, AstStdOfRestType, int * ); static AstStdOfRestType GetStdOfRest( AstSpecFrame *, int * ); static int TestStdOfRest( AstSpecFrame *, int * ); static void ClearStdOfRest( AstSpecFrame *, int * ); static void SetStdOfRest( AstSpecFrame *, AstStdOfRestType, int * ); static double GetRestFreq( AstSpecFrame *, int * ); static int TestRestFreq( AstSpecFrame *, int * ); static void ClearRestFreq( AstSpecFrame *, int * ); static void SetRestFreq( AstSpecFrame *, double, int * ); static double GetSourceVel( AstSpecFrame *, int * ); static int TestSourceVel( AstSpecFrame *, int * ); static void ClearSourceVel( AstSpecFrame *, int * ); static void SetSourceVel( AstSpecFrame *, double, int * ); static double GetRefRA( AstSpecFrame *, int * ); static int TestRefRA( AstSpecFrame *, int * ); static void ClearRefRA( AstSpecFrame *, int * ); static void SetRefRA( AstSpecFrame *, double, int * ); static double GetRefDec( AstSpecFrame *, int * ); static int TestRefDec( AstSpecFrame *, int * ); static void ClearRefDec( AstSpecFrame *, int * ); static void SetRefDec( AstSpecFrame *, double, int * ); static AstStdOfRestType GetSourceVRF( AstSpecFrame *, int * ); static int TestSourceVRF( AstSpecFrame *, int * ); static void ClearSourceVRF( AstSpecFrame *, int * ); static void SetSourceVRF( AstSpecFrame *, AstStdOfRestType, int * ); static AstSystemType GetSourceSys( AstSpecFrame *, int * ); static int TestSourceSys( AstSpecFrame *, int * ); static void ClearSourceSys( AstSpecFrame *, int * ); static void SetSourceSys( AstSpecFrame *, AstSystemType, int * ); static double GetSpecOrigin( AstSpecFrame *, int * ); static int TestSpecOrigin( AstSpecFrame *, int * ); static void ClearSpecOrigin( AstSpecFrame *, int * ); static void SetSpecOrigin( AstSpecFrame *, double, int * ); static double GetSpecOriginCur( AstSpecFrame *, int * ); static int GetAlignSpecOffset( AstSpecFrame *, int * ); static int TestAlignSpecOffset( AstSpecFrame *, int * ); static void SetAlignSpecOffset( AstSpecFrame *, int, int * ); static void ClearAlignSpecOffset( AstSpecFrame *, int * ); /* Member functions. */ /* ================= */ static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SpecFrame member function (over-rides the astClearAttrib protected * method inherited from the Frame class). * Description: * This function clears the value of a specified attribute for a * SpecFrame, so that the default value will subsequently be used. * Parameters: * this * Pointer to the SpecFrame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ char *new_attrib; /* Pointer value to new attribute name */ int len; /* Length of attrib string */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* First look for axis attributes defined by the Frame class. Since a SpecFrame has only 1 axis, we allow these attributes to be specified without a trailing "(axis)" string. */ if ( !strcmp( attrib, "direction" ) || !strcmp( attrib, "bottom" ) || !strcmp( attrib, "top" ) || !strcmp( attrib, "format" ) || !strcmp( attrib, "label" ) || !strcmp( attrib, "symbol" ) || !strcmp( attrib, "unit" ) ) { /* Create a new attribute name from the original by appending the string "(1)" and then use the parent ClearAttrib method. */ new_attrib = astMalloc( len + 4 ); if( new_attrib ) { memcpy( new_attrib, attrib, len ); memcpy( new_attrib + len, "(1)", 4 ); (*parent_clearattrib)( this_object, new_attrib, status ); new_attrib = astFree( new_attrib ); } /* AlignStdOfRest. */ /* --------------- */ } else if ( !strcmp( attrib, "alignstdofrest" ) ) { astClearAlignStdOfRest( this ); /* GeoLat. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ } else if ( !strcmp( attrib, "geolat" ) ) { astClearAttrib( this, "obslat" ); /* GeoLon. */ /* ------- */ } else if ( !strcmp( attrib, "geolon" ) ) { astClearAttrib( this, "obslon" ); /* RefDec. */ /* ---------- */ } else if ( !strcmp( attrib, "refdec" ) ) { astClearRefDec( this ); /* RefRA. */ /* --------- */ } else if ( !strcmp( attrib, "refra" ) ) { astClearRefRA( this ); /* RestFreq. */ /* --------- */ } else if ( !strcmp( attrib, "restfreq" ) ) { astClearRestFreq( this ); /* SourceVel. */ /* ---------- */ } else if ( !strcmp( attrib, "sourcevel" ) ) { astClearSourceVel( this ); /* SpecOrigin. */ /* ---------- */ } else if ( !strcmp( attrib, "specorigin" ) ) { astClearSpecOrigin( this ); /* AlignSpecOffset. */ /* ---------------- */ } else if ( !strcmp( attrib, "alignspecoffset" ) ) { astClearAlignSpecOffset( this ); /* SourceVRF */ /* --------- */ } else if ( !strcmp( attrib, "sourcevrf" ) ) { astClearSourceVRF( this ); /* SourceSys */ /* --------- */ } else if ( !strcmp( attrib, "sourcesys" ) ) { astClearSourceSys( this ); /* StdOfRest. */ /* ---------- */ } else if ( !strcmp( attrib, "stdofrest" ) ) { astClearStdOfRest( this ); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static void ClearSystem( AstFrame *this_frame, int *status ) { /* * Name: * ClearSystem * Purpose: * Clear the System attribute for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void ClearSystem( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astClearSystem protected * method inherited from the Frame class). * Description: * This function clears the System attribute for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ AstSystemType newsys; /* System after clearing */ AstSystemType oldsys; /* System before clearing */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* Save the original system */ oldsys = astGetSystem( this_frame ); /* Use the parent ClearSystem method to clear the System value. */ (*parent_clearsystem)( this_frame, status ); /* Get the default System. */ newsys = astGetSystem( this_frame ); /* If the system has actually changed. */ if( newsys != oldsys ) { /* Changing the System value will in general require the Units to change as well. If the used has previously specified the units to be used with the new system, then re-instate them (they are stored in the "usedunits" array in the SpecFrame structure). Otherwise, clear the units so that the default units will eb used with the new System. */ if( (int) newsys < this->nuunits && this->usedunits && this->usedunits[ (int) newsys ] ) { astSetUnit( this, 0, this->usedunits[ (int) newsys ] ); } else { astClearUnit( this, 0 ); } /* Also, clear all attributes which have system-specific defaults. */ astClearLabel( this_frame, 0 ); astClearSymbol( this_frame, 0 ); astClearTitle( this_frame ); /* Modify the SpecOrigin value to use the new System */ OriginSystem( this, oldsys, "astClearSystem", status ); } } static void ClearStdOfRest( AstSpecFrame *this, int *status ) { /* *+ * Name: * astClearStdOfRest * Purpose: * Clear the StdOfRest attribute for a SpecFrame. * Type: * Protected function. * Synopsis: * #include "timeframe.h" * void astClearStdOfRest( AstSpecFrame *this ) * Class Membership: * SpecFrame virtual function * Description: * This function clears the StdOfRest attribute for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Modify the SpecOrigin value stored in the SpecFrame structure to refer to the default rest frame (heliocentric). */ OriginStdOfRest( this, AST__HLSOR, "astClearStdOfRest", status ); /* Store a bad value for the standard of rest in the SpecFrame structure. */ this->stdofrest = AST__BADSOR; } static void ClearUnit( AstFrame *this_frame, int axis, int *status ) { /* * Name: * ClearUnit * Purpose: * Clear the value of the Unit string for a SpecFrame's axis. * Type: * Private function. * Synopsis: * #include "specframe.h" * void ClearUnit( AstFrame *this_frame, int axis ) * Class Membership: * SpecFrame member function (over-rides the astClearUnit method inherited * from the Frame class). * Description: * This function clears the Unit string for a specified axis of a * SpecFrame. It also clears the UsedUnit item in the SpecFrame * structure corresponding to the current System. * Parameters: * this * Pointer to the SpecFrame. * axis * The number of the axis (zero-based). */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ int system; /* The SpecFrame's System value */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astClearUnit" ); /* Clear the UsedUnit item for the current System, if current set. */ system = (int) astGetSystem( this ); if( system < this->nuunits && this->usedunits ) { this->usedunits[ system ] = astFree( this->usedunits[ system ] ); } /* Use the parent method to clear the Unit attribute of the axis. */ (*parent_clearunit)( this_frame, axis, status ); } static double ConvertSourceVel( AstSpecFrame *this, AstStdOfRestType newsor, AstSystemType newsys, int *status ) { /* * Name: * ConvertSourceVel * Purpose: * Convert the SourceVel value to a specified rest frame and spectral * system. * Type: * Private function. * Synopsis: * #include "specframe.h" * double ConvertSourceVel( AstSpecFrame *this, AstStdOfRestType newsor, * AstSystemType newsys, int *status ) * Class Membership: * SpecFrame member function * Description: * This function convert the SourceVel value to a specified rest frame * and spectral system, and returns the new value. * Parameters: * this * Pointer to the SpecFrame. * newsor * The rest frame in which the source velocity is required. * newsys * The spectral system (AST__VREL or AST__REDSHIFT) in which the * source velocity is required. * status * Pointer to the inherited status variable. * Returned Value: * The converted source velocity (m/s), or redshift. * Notes: * - This function returns zero if an error occurs. */ /* Local Variables: */ AstSpecFrame *from; /* Pointer to a source SpecFrame */ AstSpecFrame *to; /* Pointer to a destination SpecFrame */ AstSpecMap *specmap; /* Pointer to a SpecMap */ AstStdOfRestType sor; /* Standard of rest in which SourceVel is defined */ AstSystemType sys; /* Spectral system in which SourceVel is defined */ double ret; /* The returned value */ double rf; /* Rest frequency (Hz) */ double temp; /* Temporary storage */ /* Initialise */ ret = 0.0; /* Check the global error status. */ if ( !astOK ) return ret; /* Get the value of the SourceVel attribute. This will be a velocity in m/s (relativistic, radio or optical), or unitless redshift or beta factor, depending on the current value of SourceSys. */ ret = astGetSourceVel( this ); /* Check it can be used (depends on whether a value has been set and whether the UseDefs attribute is zero). */ VerifyAttrs( this, "convert source velocity to a new standard of rest", "SourceVel", "astMatch", status ); /* Get the rest frame and spectral system to which value refers. */ sor = astGetSourceVRF( this ); sys = astGetSourceSys( this ); /* If necessary, convert to the requested rest frame and spectral system. */ if( sor != newsor || sys != newsys ) { /* Verify that usable value is available for the RestFreq attribute. An error is reported if not. */ VerifyAttrs( this, "convert source velocity to a new standard of rest", "RestFreq", "astMatch", status ); /* Take two copies of the supplied SpecFrame and set their StdOfRest attributes to the required values. */ from = astCopy( this ); astSetStdOfRest( from, sor ); to = astCopy( this ); astSetStdOfRest( to, newsor ); /* Initialise a new SpecMap to describe the conversion. The new SpecMap initially represents a UnitMap. */ specmap = astSpecMap( 1, 0, "", status ); /* Add a conversion from the spectral system in which the SourceVEl value is stored, to relativistic velocity. */ if( sys == AST__VRADIO ) { astSpecAdd( specmap, "VRTOVL", NULL ); } else if( sys == AST__VOPTICAL ) { astSpecAdd( specmap, "VOTOVL", NULL ); } else if( sys == AST__REDSHIFT ) { astSpecAdd( specmap, "ZOTOVL", NULL ); } else if( sys == AST__BETA ) { astSpecAdd( specmap, "BTTOVL", NULL ); } /* Add a conversion from velocity to frequency since SorConvert converts frequencies. */ rf = astGetRestFreq( this ); astSpecAdd( specmap, "VLTOFR", &rf ); /* Now add a conversion from frequency in the SourveVRF standard of rest to frequency in the required rest frame. */ SorConvert( from, to, specmap, status ); /* Add a conversion from frequency back to velocity. Note, the value of the rest frequency does not affect the overall conversion. */ astSpecAdd( specmap, "FRTOVL", &rf ); /* Add a conversion from relativistic velocity to the required spectral system, if needed. */ if( newsys == AST__VRADIO ) { astSpecAdd( specmap, "VLTOVR", NULL ); } else if( newsys == AST__VOPTICAL ) { astSpecAdd( specmap, "VLTOVO", NULL ); } else if( newsys == AST__REDSHIFT ) { astSpecAdd( specmap, "VLTOZO", NULL ); } else if( newsys == AST__BETA ) { astSpecAdd( specmap, "VLTOBT", NULL ); } /* Use the SpecMap to convert the source velocity in the SourceVRF standard of rest and SourceSys spectral system to the required rest frame and spectral system. */ temp = ret; astTran1( specmap, 1, &temp, 1, &ret ); /* Free resources */ specmap = astAnnul( specmap ); to = astAnnul( to ); from = astAnnul( from ); } /* Return zero if an error has occurred. */ if( !astOK ) ret = 0.0; /* Return the answer. */ return ret; } static const char *DefUnit( AstSystemType system, const char *method, const char *class, int *status ){ /* * Name: * DefUnit * Purpose: * Return the default units for a spectral coordinate system type. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *DefUnit( AstSystemType system, const char *method, * const char *class, int *status ) * Class Membership: * SpecFrame member function. * Description: * This function returns a textual representation of the default * units associated with the specified spectral coordinate system. * Parameters: * system * The spectral coordinate system. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * As tring describing the default units. This string follows the * units syntax described in FITS WCS paper I "Representations of world * coordinates in FITS" (Greisen & Calabretta). * Notes: * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ const char *result; /* Value to return */ /* Initialize */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get an identifier for the default units. */ if( system == AST__FREQ ) { result = "GHz"; } else if( system == AST__ENERGY ) { result = "J"; } else if( system == AST__WAVENUM ) { result = "1/m"; } else if( system == AST__WAVELEN ) { result = "Angstrom"; } else if( system == AST__AIRWAVE ) { result = "Angstrom"; } else if( system == AST__VRADIO ) { result = "km/s"; } else if( system == AST__VOPTICAL ) { result = "km/s"; } else if( system == AST__REDSHIFT ) { result = ""; } else if( system == AST__BETA ) { result = ""; } else if( system == AST__VREL ) { result = "km/s"; /* Report an error if the coordinate system was not recognised. */ } else { astError( AST__SCSIN, "%s(%s): Corrupt %s contains illegal System " "identification code (%d).", status, method, class, class, (int) system ); } /* Return the result. */ return result; } static int EqualSor( AstSpecFrame *this, AstSpecFrame *that, int *status ) { /* * Name: * EqualSor * Purpose: * Do two SpecFrames use the same standard of rest? * Type: * Private function. * Synopsis: * #include "specframe.h" * int EqualSor( AstSpecFrame *this, AstSpecFrame *that, int *status ) * Class Membership: * SpecFrame member function * Description: * This function returns non-zero if the two supplied SpecFrames use * the same standard of rest. * Parameters: * this * Pointer to the first SpecFrame. * that * Pointer to the second SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the two SpecFrames use the same standard of rest. Zero * otherwise. */ /* Local Variables: */ AstStdOfRestType sor; /* Standard of rest */ int result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ result = 1; /* Compare StdOfRest attributes. */ sor = astGetStdOfRest( this ); if( astGetStdOfRest( that ) != sor ) { result = 0; /* If the standards of rest are equal we need to check the the attributes which specify the precise rest frame. */ } else { /* The reference RA and Dec need to be equal */ if( !EQUAL( astGetRefRA( this ), astGetRefRA( that ) ) || !EQUAL( astGetRefDec( this ), astGetRefDec( that ) ) ) { result = 0; /* For source rest frame, the source velocities, rest frames and systems must be equal */ } else if( sor == AST__SCSOR ){ if( !EQUAL( astGetSourceVel( this ), astGetSourceVel( that ) ) || astGetSourceVRF( this ) != astGetSourceVRF( that ) || astGetSourceSys( this ) != astGetSourceSys( that ) ) { result = 0; } /* For geocentric, barycentric and heliocentric rest frames, the epochs must be the same */ } else if( sor == AST__GESOR || sor == AST__BYSOR || sor == AST__HLSOR ){ if( !EQUAL( astGetEpoch( this ), astGetEpoch( that ) ) ) result = 0; /* For topocentric rest frame, the epoch and position of the observer must be the same */ } else if( sor == AST__TPSOR ){ if( !EQUAL( astGetEpoch( this ), astGetEpoch( that ) ) || !EQUAL( astGetObsAlt( this ), astGetObsAlt( that ) ) || !EQUAL( astGetObsLon( this ), astGetObsLon( that ) ) || !EQUAL( astGetObsLat( this ), astGetObsLat( that ) ) ) result = 0; } else if( sor != AST__LKSOR && sor != AST__LDSOR && sor != AST__GLSOR && sor != AST__LGSOR && astOK ) { astError( AST__INTER, "SorEqual(SpecFrame): Function SorEqual " "does not yet support rest frame %d (AST internal " "programming error)", status, sor ); } } /* Return the result */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "specframe.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied SpecFrame, * in bytes. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ int result; /* Result value to return */ int i; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); if( this->usedunits ) { for( i = 0; i < this->nuunits; i++ ) { result += astTSizeOf( this->usedunits[ i ] ); } result += astTSizeOf( this->usedunits ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetActiveUnit( AstFrame *this_frame, int *status ) { /* * Name: * GetActiveUnit * Purpose: * Obtain the value of the ActiveUnit flag for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * int GetActiveUnit( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetActiveUnit protected * method inherited from the Frame class). * Description: * This function returns the value of the ActiveUnit flag for a * SpecFrame, which is always 1. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The value to use for the ActiveUnit flag (1). */ return 1; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SpecFrame member function (over-rides the protected astGetAttrib * method inherited from the Frame class). * Description: * This function returns a pointer to the value of a specified * attribute for a SpecFrame, formatted as a character string. * Parameters: * this * Pointer to the SpecFrame. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - The returned string pointer may point at memory allocated * within the SpecFrame, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the SpecFrame. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ AstStdOfRestType sor; /* Standard of rest */ AstSystemType sys; /* Spectral system */ char *new_attrib; /* Pointer value to new attribute name */ const char *result; /* Pointer value to return */ double dval; /* Attribute value */ int ival; /* Attribute value */ int len; /* Length of attrib string */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Create an FK5 J2000 SkyFrame which will be used for formatting and unformatting sky positions, etc. */ LOCK_MUTEX2 if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); astEndPM; } UNLOCK_MUTEX2 /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* First look for axis attributes defined by the Frame class. Since a SpecFrame has only 1 axis, we allow these attributes to be specified without a trailing "(axis)" string. */ if ( !strcmp( attrib, "direction" ) || !strcmp( attrib, "bottom" ) || !strcmp( attrib, "top" ) || !strcmp( attrib, "format" ) || !strcmp( attrib, "label" ) || !strcmp( attrib, "symbol" ) || !strcmp( attrib, "unit" ) ) { /* Create a new attribute name from the original by appending the string "(1)" and then use the parent GetAttrib method. */ new_attrib = astMalloc( len + 4 ); if( new_attrib ) { memcpy( new_attrib, attrib, len ); memcpy( new_attrib + len, "(1)", 4 ); result = (*parent_getattrib)( this_object, new_attrib, status ); new_attrib = astFree( new_attrib ); } /* AlignStdOfRest. */ /* --------------- */ /* Obtain the AlignStdOfRest code and convert to a string. */ } else if ( !strcmp( attrib, "alignstdofrest" ) ) { sor = astGetAlignStdOfRest( this ); if ( astOK ) { result = StdOfRestString( sor, status ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid AlignStdOfRest " "identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) sor ); } } /* AlignSpecOffset */ /* --------------- */ } else if ( !strcmp( attrib, "alignspecoffset" ) ) { ival = astGetAlignSpecOffset( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* GeoLat. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ } else if ( !strcmp( attrib, "geolat" ) ) { result = astGetAttrib( this, "obslat" ); /* GeoLon. */ /* ------- */ } else if ( !strcmp( attrib, "geolon" ) ) { result = astGetAttrib( this, "obslon" ); /* RefDec. */ /* ------- */ /* Convert to a string using the SkyFrame Format method. */ } else if ( !strcmp( attrib, "refdec" ) ) { dval = astGetRefDec( this ); if ( astOK ) { result = astFormat( skyframe, 1, dval ); } /* RefRA. */ /* ------ */ /* Convert to a string using the SkyFrame Format method. */ } else if ( !strcmp( attrib, "refra" ) ) { dval = astGetRefRA( this ); if ( astOK ) { result = astFormat( skyframe, 0, dval ); } /* RestFreq. */ /* --------- */ } else if ( !strcmp( attrib, "restfreq" ) ) { dval = astGetRestFreq( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval*1.0E-9 ); result = getattrib_buff; } /* SourceVel */ /* --------- */ } else if ( !strcmp( attrib, "sourcevel" ) ) { dval = astGetSourceVel( this ); if ( astOK ) { /* Convert from m/s to km/s if the SourceVel value is a velocity. . */ if( astGetSourceSys( this ) == AST__VREL || astGetSourceSys( this ) == AST__VRADIO || astGetSourceSys( this ) == AST__VOPTICAL ) dval *= 1.0E-3; /* Format */ (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* SpecOrigin. */ /* ----------- */ } else if ( !strcmp( attrib, "specorigin" ) ) { dval = GetSpecOriginCur( this, status ); if( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* SourceVRF */ /* ----------*/ } else if ( !strcmp( attrib, "sourcevrf" ) ) { sor = astGetSourceVRF( this ); if ( astOK ) { result = StdOfRestString( sor, status ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid SourceVRF " "identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) sor ); } } /* SourceSys */ /* ----------*/ } else if ( !strcmp( attrib, "sourcesys" ) ) { sys = astGetSourceSys( this ); if ( astOK ) { result = SystemString( (AstFrame *) this, sys, status ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid SourceSys " "identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) sys ); } } /* StdOfRest. */ /* ---------- */ /* Obtain the StdOfRest code and convert to a string. */ } else if ( !strcmp( attrib, "stdofrest" ) ) { sor = astGetStdOfRest( this ); if ( astOK ) { result = StdOfRestString( sor, status ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid StdOfRest " "identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) sor ); } } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static const char *GetDomain( AstFrame *this_frame, int *status ) { /* * Name: * GetDomain * Purpose: * Obtain a pointer to the Domain attribute string for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetDomain( AstFrame *this, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetDomain protected * method inherited from the Frame class). * Description: * This function returns a pointer to the Domain attribute string * for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a constant null-terminated string containing the * Domain value. * Notes: * - The returned pointer or the string it refers to may become * invalid following further invocation of this function or * modification of the SpecFrame. * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* If a Domain attribute string has been set, invoke the parent method to obtain a pointer to it. */ if ( astTestDomain( this ) ) { result = (*parent_getdomain)( this_frame, status ); /* Otherwise, provide a pointer to a suitable default string. */ } else { result = "SPECTRUM"; } /* Return the result. */ return result; } static const char *GetLabel( AstFrame *this, int axis, int *status ) { /* * Name: * GetLabel * Purpose: * Access the Label string for a SpecFrame axis. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetLabel( AstFrame *this, int axis, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetLabel method inherited * from the Frame class). * Description: * This function returns a pointer to the Label string for a specified axis * of a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated character string containing the * requested information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstMapping *map; /* Mapping between units */ AstSystemType system; /* Code identifying type of spectral coordinates */ char *new_lab; /* Modified label string */ const char *result; /* Pointer to label string */ double orig; /* Spec origin */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise. */ result = NULL; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astGetLabel" ); /* Check if a value has been set for the required axis label string. If so, invoke the parent astGetLabel method to obtain a pointer to it. */ if ( astTestLabel( this, axis ) ) { result = (*parent_getlabel)( this, axis, status ); /* Otherwise, identify the spectral coordinate system described by the SpecFrame. */ } else { system = astGetSystem( this ); /* If OK, supply a pointer to a suitable default label string. */ if ( astOK ) { result = strcpy( getlabel_buff, SystemLabel( system, status ) ); getlabel_buff[ 0 ] = toupper( getlabel_buff[ 0 ] ); /* If a non-zero SpecOrigin has been specified, include the offset now. */ orig = GetSpecOriginCur( (AstSpecFrame *) this, status ); if( orig != 0.0 ) { sprintf( getlabel_buff + strlen( getlabel_buff ), " offset from %s", astFormat( this, 0, orig ) ); } /* Modify this default to take account of the current value of the Unit attribute, if set. */ if( astTestUnit( this, axis ) ) { /* Find a Mapping from the default Units for the current System, to the units indicated by the Unit attribute. This Mapping is used to modify the existing default label appropriately. For instance, if the default units is "Hz" and the actual units is "log(Hz)", then the default label of "Frequency" is changed to "log( frequency )". */ map = astUnitMapper( DefUnit( system, "astGetLabel", astGetClass( this ), status ), astGetUnit( this, axis ), result, &new_lab ); if( new_lab ) { result = strcpy( getlabel_buff, new_lab ); new_lab = astFree( new_lab ); } /* Annul the unused Mapping. */ if( map ) map = astAnnul( map ); } } } /* Return the result. */ return result; } static void GetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double *lon, double *lat, int *status ){ /* *++ * Name: c astGetRefPos f AST_GETREFPOS * Purpose: * Return the reference position in a specified celestial coordinate system. * Type: * Public virtual function. * Synopsis: c #include "specframe.h" c void astGetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double *lon, c double *lat ) f CALL AST_GETREFPOS( THIS, FRM, LON, LAT, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * returns the reference position (specified by attributes RefRA and * RefDec) converted to the celestial coordinate system represented by * a supplied SkyFrame. The celestial longitude and latitude values * are returned in radians. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the SpecFrame. c frm f FRM = INTEGER (Given) * Pointer to the SkyFrame which defines the required celestial * coordinate system. c If NULL f If AST__NULL * is supplied, then the longitude and latitude values are returned * as FK5 J2000 RA and Dec values. c lon f LON = DOUBLE PRECISION (Returned) c A pointer to a double in which to store the f The * longitude of the reference point, in the coordinate system * represented by the supplied SkyFrame (radians). c lat f LAT = DOUBLE PRECISION (Returned) c A pointer to a double in which to store the f The * latitude of the reference point, in the coordinate system * represented by the supplied SkyFrame (radians). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Values of AST__BAD will be returned if this function is c invoked with the AST error status set, or if it should fail for f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- */ /* Local Variables: */ AstFrameSet *fs; /* Conversion FrameSet */ AstFrame *fb; /* Base Frame */ AstFrame *fc; /* Current Frame */ double xin[ 1 ]; /* Axis 1 values */ double yin[ 1 ]; /* Axis 2 values */ double xout[ 1 ]; /* Axis 1 values */ double yout[ 1 ]; /* Axis 2 values */ /* Initialise. */ if( lon ) *lon = AST__BAD; if( lat ) *lat = AST__BAD; /* Check the global error status. */ if ( !astOK ) return; /* If no SkyFrame was supplied, just return the stored RefRA and RefDec values. */ if( !frm ) { if( lon ) *lon = astGetRefRA( this ); if( lat ) *lat = astGetRefDec( this ); /* Otherwise, convert the stored values to the requested system. */ } else { /* Create an FK5 J2000 SkyFrame which will be used for formatting and unformatting sky positions, etc. */ LOCK_MUTEX2 if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); astEndPM; } UNLOCK_MUTEX2 /* Find the Mapping from the SkyFrame which describes the internal format in which the RefRA and RefDec attribute values are stored, to the supplied Frame. */ fs = astFindFrame( skyframe, frm, "" ); /* If alignment was possible, use the Mapping to transform the internal RefRA and RefDec values. Check for axis permutatuion. */ if( fs ) { fb = astGetFrame( fs, AST__BASE ); if( astGetLonAxis( fb ) == 0 ) { xin[ 0 ] = astGetRefRA( this ); yin[ 0 ] = astGetRefDec( this ); } else { yin[ 0 ] = astGetRefRA( this ); xin[ 0 ] = astGetRefDec( this ); } astTran2( fs, 1, xin, yin, 1, xout, yout ); /* Store the returned values, checking to see if the axes of the supplied SkyFrame have been permuted. */ fc = astGetFrame( fs, AST__CURRENT ); if( astGetLonAxis( fc ) == 0 ) { if( lon ) *lon = xout[ 0 ]; if( lat ) *lat = yout[ 0 ]; } else { if( lon ) *lon = yout[ 0 ]; if( lat ) *lat = xout[ 0 ]; } /* Annul object references. */ fc = astAnnul( fc ); fb = astAnnul( fb ); fs = astAnnul( fs ); } } } static const char *GetSymbol( AstFrame *this, int axis, int *status ) { /* * Name: * GetSymbol * Purpose: * Obtain a pointer to the Symbol string for a SpecFrame axis. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetSymbol( AstFrame *this, int axis, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetSymbol method inherited * from the Frame class). * Description: * This function returns a pointer to the Symbol string for a specified axis * of a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated character string containing the * requested information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstMapping *map; /* Mapping between units */ AstSystemType system; /* Code identifying type of sky coordinates */ char *new_sym; /* Modified symbol string */ const char *result; /* Pointer to symbol string */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise. */ result = NULL; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astGetSymbol" ); /* Check if a value has been set for the required axis symbol string. If so, invoke the parent astGetSymbol method to obtain a pointer to it. */ if ( astTestSymbol( this, axis ) ) { result = (*parent_getsymbol)( this, axis, status ); /* Otherwise, identify the sky coordinate system described by the SpecFrame. */ } else { system = astGetSystem( this ); /* If OK, supply a pointer to a suitable default Symbol string. */ if ( astOK ) { if( system == AST__FREQ ) { result = "FREQ"; } else if( system == AST__ENERGY ) { result = "ENER"; } else if( system == AST__WAVENUM ) { result = "WAVN"; } else if( system == AST__WAVELEN ) { result = "WAVE"; } else if( system == AST__AIRWAVE ) { result = "AWAV"; } else if( system == AST__VRADIO ) { result = "VRAD"; } else if( system == AST__VOPTICAL ) { result = "VOPT"; } else if( system == AST__REDSHIFT ) { result = "ZOPT"; } else if( system == AST__BETA ) { result = "BETA"; } else if( system == AST__VREL ) { result = "VELO"; /* Report an error if the coordinate system was not recognised. */ } else { astError( AST__SCSIN, "astGetSymbol(%s): Corrupt %s contains " "invalid System identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); } /* Modify this default to take account of the current value of the Unit attribute, if set. */ if( astTestUnit( this, axis ) ) { /* Find a Mapping from the default Units for the current System, to the units indicated by the Unit attribute. This Mapping is used to modify the existing default symbol appropriately. For instance, if the default units is "Hz" and the actual units is "log(Hz)", then the default symbol of "nu" is changed to "log( nu )". */ map = astUnitMapper( DefUnit( system, "astGetSymbol", astGetClass( this ), status ), astGetUnit( this, axis ), result, &new_sym ); if( new_sym ) { result = strcpy( getsymbol_buff, new_sym ); new_sym = astFree( new_sym ); } /* Annul the unused Mapping. */ if( map ) map = astAnnul( map ); } } } /* Return the result. */ return result; } static AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) { /* * Name: * GetAlignSystem * Purpose: * Obtain the AlignSystem attribute for a SpecFrame. * Type: * Private function. * Synopsis: * #include "Specframe.h" * AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetAlignSystem protected * method inherited from the Frame class). * Description: * This function returns the AlignSystem attribute for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The AlignSystem value. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ AstSystemType result; /* Value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* If a AlignSystem attribute has been set, invoke the parent method to obtain it. */ if ( astTestAlignSystem( this ) ) { result = (*parent_getalignsystem)( this_frame, status ); /* Otherwise, provide a suitable default. */ } else { result = AST__WAVELEN; } /* Return the result. */ return result; } static AstSystemType GetSystem( AstFrame *this_frame, int *status ) { /* * Name: * GetSystem * Purpose: * Obtain the System attribute for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * AstSystemType GetSystem( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetSystem protected * method inherited from the Frame class). * Description: * This function returns the System attribute for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The System value. * Notes: * - AST__BADSYSTEM is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ AstSystemType result; /* Value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* If a System attribute has been set, invoke the parent method to obtain it. */ if ( astTestSystem( this ) ) { result = (*parent_getsystem)( this_frame, status ); /* Otherwise, provide a suitable default. */ } else { result = AST__WAVELEN; } /* Return the result. */ return result; } static const char *GetTitle( AstFrame *this_frame, int *status ) { /* * Name: * GetTitle * Purpose: * Obtain a pointer to the Title string for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetTitle( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astGetTitle method inherited * from the Frame class). * Description: * This function returns a pointer to the Title string for a SpecFrame. * A pointer to a suitable default string is returned if no Title value has * previously been set. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a null-terminated character string containing the requested * information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ AstStdOfRestType sor; /* Code identifying standard of rest */ AstSystemType system; /* Code identifying type of coordinates */ const char *sor_string; /* Pointer to SOR description */ const char *result; /* Pointer to result string */ double rf; /* Rest frequency */ int nc; /* No. of characters added */ int pos; /* Buffer position to enter text */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_frame); /* Initialise. */ result = NULL; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* See if a Title string has been set. If so, use the parent astGetTitle method to obtain a pointer to it. */ if ( astTestTitle( this ) ) { result = (*parent_gettitle)( this_frame, status ); /* Otherwise, we will generate a default Title string. Obtain the values of the SpecFrame's attributes that determine what this string will be. */ } else { system = astGetSystem( this ); sor = astGetStdOfRest( this ); sor_string = StdOfRestString( sor, status ); rf = astGetRestFreq( this ); /* Classify the coordinate system type and create an appropriate Title string. (Note that when invoking the astFmtDecimalYr function we must use a separate sprintf on each occasion so as not to over-write its internal buffer before the result string has been used.) */ if ( astOK ) { result = gettitle_buff; /* Begin with the system's default label. */ pos = sprintf( gettitle_buff, "%s", SystemLabel( system, status ) ); gettitle_buff[ 0 ] = toupper( gettitle_buff[ 0 ] ); /* Append the standard of rest in parentheses, if set. */ if( astTestStdOfRest( this ) ) { nc = sprintf( gettitle_buff+pos, " (%s)", sor_string ); pos += nc; } /* Append the rest frequency if relevant. */ if( !ABS_SYSTEM(system) && ( astTestRestFreq( this ) || astGetUseDefs( this ) ) ) { pos += sprintf( gettitle_buff+pos, ", rest frequency = %g GHz", rf*1.0E-9 ); } } } /* If an error occurred, clear the returned pointer value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static double GetSpecOriginCur( AstSpecFrame *this, int *status ) { /* * Name: * GetSpecOriginCur * Purpose: * Obtain the SpecOrigin attribute for a SpecFrame in current units. * Type: * Private function. * Synopsis: * #include "timeframe.h" * double GetSpecOriginCur( AstSpecFrame *this, int *status ) * Class Membership: * SpecFrame virtual function * Description: * This function returns the SpecOrigin attribute for a SpecFrame, in * the current units of the SpecFrame. The protected astGetSpecOrigin * method can be used to obtain the time origin in the default units of * the SpecFrame's System. * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The SpecOrigin value, in the units, system and rest frame specified * by the current values of the Unit, System and StdOfRest attributes * within "this". * Notes: * - AST__BAD is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstMapping *map; const char *cur; const char *def; double result; double defval; /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Get the value in the default units */ result = astGetSpecOrigin( this ); /* If SpecOrigin is non-zero and non-BAD we convert it to the current units.*/ if( result != 0.0 && result != AST__BAD ) { /* Get the default units for the SpecFrame's System. */ def = DefUnit( astGetSystem( this ), "astGetSpecOrigin", "SpecFrame", status ); /* Get the current units from the SpecFrame. */ cur = astGetUnit( this, 0 ); /* If the units differ, get a Mapping from default to current units. */ if( cur && def ){ if( strcmp( cur, def ) ) { map = astUnitMapper( def, cur, NULL, NULL ); /* Report an error if the units are incompatible. */ if( !map ) { astError( AST__BADUN, "%s(%s): The current units (%s) are not suitable " "for a SpecFrame.", status, "astGetSpecOrigin", astGetClass( this ), cur ); /* Otherwise, transform the stored origin value.*/ } else { defval = result; astTran1( map, 1, &defval, 1, &result ); map = astAnnul( map ); } } } } /* Return the result. */ return result; } static const char *GetUnit( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetUnit * Purpose: * Obtain a pointer to the Unit string for a SpecFrame's axis. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *GetUnit( AstFrame *this_frame, int axis ) * Class Membership: * SpecFrame member function (over-rides the astGetUnit method inherited * from the Frame class). * Description: * This function returns a pointer to the Unit string for a specified axis * of a SpecFrame. If the Unit attribute has not been set for the axis, a * pointer to a suitable default string is returned instead. * Parameters: * this * Pointer to the SpecFrame. * axis * The number of the axis (zero-based) for which information is required. * Returned Value: * A pointer to a null-terminated string containing the Unit value. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ AstSystemType system; /* The SpecFrame's System value */ const char *result; /* Pointer value to return */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astGetUnit" ); /* If a value has been set for the Unit attribute, use the parent GetUnit method to return a pointer to the required Unit string. */ if( astTestUnit( this, axis ) ){ result = (*parent_getunit)( this_frame, axis, status ); /* Otherwise, identify the spectral coordinate system described by the SpecFrame. */ } else { system = astGetSystem( this ); /* Return a string describing the default units. */ result = DefUnit( system, "astGetUnit", astGetClass( this ), status ); } /* If an error occurred, clear the returned value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } void astInitSpecFrameVtab_( AstSpecFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSpecFrameVtab * Purpose: * Initialise a virtual function table for a SpecFrame. * Type: * Protected function. * Synopsis: * #include "specframe.h" * void astInitSpecFrameVtab( AstSpecFrameVtab *vtab, const char *name ) * Class Membership: * SpecFrame vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SpecFrame class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitFrameVtab( (AstFrameVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASpecFrame) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstFrameVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->GetRefPos = GetRefPos; vtab->SetRefPos = SetRefPos; vtab->ClearAlignStdOfRest = ClearAlignStdOfRest; vtab->TestAlignStdOfRest = TestAlignStdOfRest; vtab->GetAlignStdOfRest = GetAlignStdOfRest; vtab->SetAlignStdOfRest = SetAlignStdOfRest; vtab->ClearSourceVRF = ClearSourceVRF; vtab->TestSourceVRF = TestSourceVRF; vtab->GetSourceVRF = GetSourceVRF; vtab->SetSourceVRF = SetSourceVRF; vtab->ClearSourceSys = ClearSourceSys; vtab->TestSourceSys = TestSourceSys; vtab->GetSourceSys = GetSourceSys; vtab->SetSourceSys = SetSourceSys; vtab->ClearRefDec = ClearRefDec; vtab->TestRefDec = TestRefDec; vtab->GetRefDec = GetRefDec; vtab->SetRefDec = SetRefDec; vtab->ClearRefRA = ClearRefRA; vtab->TestRefRA = TestRefRA; vtab->GetRefRA = GetRefRA; vtab->SetRefRA = SetRefRA; vtab->ClearRestFreq = ClearRestFreq; vtab->TestRestFreq = TestRestFreq; vtab->GetRestFreq = GetRestFreq; vtab->SetRestFreq = SetRestFreq; vtab->ClearStdOfRest = ClearStdOfRest; vtab->TestStdOfRest = TestStdOfRest; vtab->GetStdOfRest = GetStdOfRest; vtab->SetStdOfRest = SetStdOfRest; vtab->ClearSourceVel = ClearSourceVel; vtab->TestSourceVel = TestSourceVel; vtab->GetSourceVel = GetSourceVel; vtab->SetSourceVel = SetSourceVel; vtab->ClearSpecOrigin = ClearSpecOrigin; vtab->TestSpecOrigin = TestSpecOrigin; vtab->GetSpecOrigin = GetSpecOrigin; vtab->SetSpecOrigin = SetSpecOrigin; vtab->TestAlignSpecOffset = TestAlignSpecOffset; vtab->SetAlignSpecOffset = SetAlignSpecOffset; vtab->GetAlignSpecOffset = GetAlignSpecOffset; vtab->ClearAlignSpecOffset = ClearAlignSpecOffset; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; frame = (AstFrameVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_getdomain = frame->GetDomain; frame->GetDomain = GetDomain; parent_getsystem = frame->GetSystem; frame->GetSystem = GetSystem; parent_setsystem = frame->SetSystem; frame->SetSystem = SetSystem; parent_clearsystem = frame->ClearSystem; frame->ClearSystem = ClearSystem; parent_getalignsystem = frame->GetAlignSystem; frame->GetAlignSystem = GetAlignSystem; parent_getlabel = frame->GetLabel; frame->GetLabel = GetLabel; parent_getsymbol = frame->GetSymbol; frame->GetSymbol = GetSymbol; parent_gettitle = frame->GetTitle; frame->GetTitle = GetTitle; parent_clearunit = frame->ClearUnit; frame->ClearUnit = ClearUnit; parent_getunit = frame->GetUnit; frame->GetUnit = GetUnit; parent_setunit = frame->SetUnit; frame->SetUnit = SetUnit; parent_match = frame->Match; frame->Match = Match; parent_overlay = frame->Overlay; frame->Overlay = Overlay; parent_subframe = frame->SubFrame; frame->SubFrame = SubFrame; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ frame->GetActiveUnit = GetActiveUnit; frame->TestActiveUnit = TestActiveUnit; frame->ValidateSystem = ValidateSystem; frame->SystemString = SystemString; frame->SystemCode = SystemCode; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "SpecFrame", "Description of spectral coordinate system" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MakeSpecMapping( AstSpecFrame *target, AstSpecFrame *result, AstSpecFrame *align_frm, int report, AstMapping **map, int *status ) { /* * Name: * MakeSpecMapping * Purpose: * Generate a Mapping between two SpecFrames. * Type: * Private function. * Synopsis: * #include "specframe.h" * int MakeSpecMapping( AstSpecFrame *target, AstSpecFrame *result, * AstSpecFrame *align_frm, int report, * AstMapping **map, int *status ) { * Class Membership: * SpecFrame member function. * Description: * This function takes two SpecFrames and generates a Mapping that * converts between them, taking account of differences in their * coordinate systems, rest frequency, standard of rest, etc. * * In order to cut down the number of transformations to be considered, * the scheme works by first converting from the target frame to an * "alignment" Frame, using the attributes of the target to define the * transformation. A transformation is then found from the alignment * frame to the required result Frame, using the attributes of the * result to define the transformation. The alignment Frame is * described by the AlignSystem and AlignStdOfRest attributes of the * "align_frm" SpecFrame. * * Thus, different forms of alignment can be obtained by suitable * choice of the attributes of "align_frm". For instance, to compare the * radio velocity dispersion of two lines at different rest frequencies, * you would set "system=radio velocity" and (probably) "stdofrest=local * group" in "align_frm". On the other hand if you wanted to re-calibrate * an existing radio velocity Frame within a FrameSet to use a different * rest frequency, you would make the SpecFrame the current Frame and then * set the rest frequency attribute for the FrameSet. The "integrity * checking" system in the FrameSet class would then get the Mapping * between the original and the modified SpecFrames. In this case, the * "alignment system" needs to be "frequency" since you want the original * and modified SpecFrames to be aligned in frequency, not radio velocity. * Parameters: * target * Pointer to the first SpecFrame. * result * Pointer to the second SpecFrame. * align_frm * A SpecFrame defining the system and standard of rest in which to * align the target and result SpecFrames. * report * Should errors be reported if no match is possible? These reports * will describe why no match was possible. * map * Pointer to a location which is to receive a pointer to the * returned Mapping. The forward transformation of this Mapping * will convert from "target" coordinates to "result" * coordinates, and the inverse transformation will convert in * the opposite direction (all coordinate values in radians). * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Mapping could be generated, or zero if the two * SpecFrames are sufficiently un-related that no meaningful Mapping * can be produced (albeit an "unmeaningful" Mapping will be returned * in this case, which will need to be annulled). * Notes: * A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Constants: */ #define MAX_ARGS 1 /* Max arguments for an SpecMap conversion */ /* Local Variables: */ AstMapping *map1; /* Intermediate Mapping */ AstMapping *map2; /* Intermediate Mapping */ AstMapping *umap1; /* First Units Mapping */ AstMapping *umap2; /* Second Units Mapping */ AstSpecMap *specmap; /* Pointer to SpecMap */ AstShiftMap *sm; /* ShiftMap pointer */ AstSpecFrame *align_target; /* Alignment Frame with target properties */ AstSpecFrame *align_result; /* Alignment Frame with result properties */ AstSystemType serr; /* Erroneous system */ AstSystemType align_system; /* Code to identify alignment system */ AstSystemType target_system; /* Code to identify target system */ AstSystemType result_system; /* Code to identify result system */ const char *uerr; /* Erroneous units */ const char *ures; /* Results units */ const char *utarg; /* Target units */ const char *vmess; /* Text for use in error messages */ double args[ MAX_ARGS ]; /* Conversion argument array */ double target_rf; /* Target rest frequency (Hz) */ double result_rf; /* Result rest frequency (Hz) */ double target_origin; /* Target origin */ double result_origin; /* Result origin */ int match; /* Mapping can be generated? */ int step2; /* Perform the 2nd step in the Mapping? */ int step3; /* Perform the 3rd step in the Mapping? */ int step4; /* Perform the 4th step in the Mapping? */ int step5; /* Perform the 5th step in the Mapping? */ int step6; /* Perform the 6th step in the Mapping? */ int step7; /* Perform the 7th step in the Mapping? */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise the returned values. */ match = 1; *map = NULL; /* Create an initial (null) SpecMap. This is a 1D Mapping which converts spectral axis values between different systems and standard of rest. The axis units used by the SpecMap class match the default units used by this class. Any discrepancy between units is taken into account at the end of this function, once the total SpecMap has been created. */ specmap = astSpecMap( 1, 0, "", status ); /* Define local macros as shorthand for adding spectral coordinate conversions to this SpecMap. Each macro simply stores details of the additional arguments in the "args" array and then calls astSpecAdd. The macros differ in the number of additional argument values. */ #define TRANSFORM_0(cvt) \ astSpecAdd( specmap, cvt, NULL ); #define TRANSFORM_1(cvt,arg0) \ args[ 0 ] = arg0; \ astSpecAdd( specmap, cvt, args ); /* Get all the necessary attributes from the result, target and alignment Frames. */ target_rf = astGetRestFreq( target ); result_rf = astGetRestFreq( result ); target_system = astGetSystem( target ); result_system = astGetSystem( result ); align_system = astGetSystem( align_frm ); /* Define text for error messages.*/ vmess = "convert between spectral systems"; /* Verify that values for the standard of rest have been set if required (i.e if the UseDefs attribute of either SpecFrame is false). */ VerifyAttrs( result, vmess, "StdOfRest", "astMatch", status ); VerifyAttrs( target, vmess, "StdOfRest", "astMatch", status ); /* There are two different strategies for alignment. I'll use the Source rest frame as an example, although the same argument applies to other rest frames. In the first strategy, all "Source" rest frames are considered equal. That is, if two SpecFrames respresent (for example) frequencies in the source frame, then the SpecFrames are aligned using a UnitMap even if the details of the two source rest frames differ. This is usually what users want to see when (for instance) aligning plots of two spectra which both represent source frequencies but where the source frames details differ. In the second strategy, "Source" rest frames are aligned using a SpecMap that takes into account any differences in the properties of the source rest frames. This is what should happen when changes are made to the properties of a SpecFrame within a FrameSet. For instance, if the user changes the SourceVel attribute of the current Frame (assumed here to be a SpecFrame) in a FrameSet, then the process of restoring the integrity of the FrameSet (see frameset.c for details of integrity restoration) should cause the base->current Mapping in the FrameSet to be modified to reflect the new SourceVel value. So if the current call to this function is part of the process of restoring a FrameSet's integrity following changes to the FrameSet's current Frame, then we want to retain the properties of the supplied alignment Frame. So we use clones of the supplied alignment Frame. */ if( astGetFrameFlags( target ) & AST__INTFLAG ) { align_target = astClone( align_frm ); align_result = astClone( align_frm ); /* Buf if we are not restoring the integrity of a FrameSet, we want to ignore any differences in the properties that define the available rest frames. So create copies of the alignment Frame in which the properies defining the available rest frames are the same as in the target and result Frames. */ } else { align_target = astCopy( align_frm ); astSetEpoch( align_target, astGetEpoch( target ) ); astSetRefRA( align_target, astGetRefRA( target ) ); astSetRefDec( align_target, astGetRefDec( target ) ); astSetSourceVRF( align_target, astGetSourceVRF( target ) ); astSetSourceVel( align_target, astGetSourceVel( target ) ); astSetObsLat( align_target, astGetObsLat( target ) ); astSetObsLon( align_target, astGetObsLon( target ) ); astSetObsAlt( align_target, astGetObsAlt( target ) ); align_result = astCopy( align_frm ); astSetEpoch( align_result, astGetEpoch( result ) ); astSetRefRA( align_result, astGetRefRA( result ) ); astSetRefDec( align_result, astGetRefDec( result ) ); astSetSourceVRF( align_result, astGetSourceVRF( result ) ); astSetSourceVel( align_result, astGetSourceVel( result ) ); astSetObsLat( align_result, astGetObsLat( result ) ); astSetObsLon( align_result, astGetObsLon( result ) ); astSetObsAlt( align_result, astGetObsAlt( result ) ); } /* The supported spectral coordinate systems fall into two groups; "relative", and "absolute". The relative systems define each axis value with respect to the rest frequency, whereas the absolute systems have axis values which do not depend on the rest frequency. In order to convert an axis value from a system in one group to a system in the other group, the rest frequency must be known. However, the rest frequency is not necessary in order to convert axis values between two systems belonging to the same group. Determine if the alignment system is absolute or relative. If absolute, we ignore the system of the supplied "align_frm" and align in frequency, since aligning in any absolute system will automatically ensure that all the other absolute systems are aligned. Similarly, aligning in any relative system will automatically ensure that all the other relative systems are aligned. Doing this cuts down the complexity of the conversion process since we do not need to check every possible alignment system. */ align_system = ( ABS_SYSTEM( align_system ) ) ? AST__FREQ : AST__VREL; /* The total Mapping is made up of the following steps in series: 0) Convert from an offset value to an absolute value (if SpecOrigin set) 1) Convert target units to default units for the targets system 2) Convert from target system in target SOR to frequency in target SOR 3) Convert from freq in target SOR to freq in alignment SOR 4) Convert from freq in alignment SOR to alignment system in alignment SOR 5) Convert from alignment system in alignment SOR to freq in alignment SOR 6) Convert from freq in alignment SOR to freq in result SOR 7) Convert from freq in result SOR to result system in result SOR 8) Convert default units for the result system to results unit 9) Convert from an absolute value to an offset value (if SpecOrigin set) Steps 1,2,3,4 are performed using the attributes of the target (rest frequency, reference farem, etc), whilst steps 5,6,7,8 are performed using the attributes of the target (rest frequency, reference frame, etc). It is necessary to go from target system to alignment system via frequency because SOR conversion can only be performed in the frequency domain. Some of these steps may not be necessary. Initially assume all steps are necessary (we leave steps 0, 1, 8 and 9 out of this process and implement them once all other steps have been done). */ step2 = 1; step3 = 1; step4 = 1; step5 = 1; step6 = 1; step7 = 1; /* Step 2 is not necessary if the target system is frequency. */ if( target_system == AST__FREQ ) step2 = 0; /* Step 3 is not necessary if the alignment SOR is the same as the target SOR. */ if( EqualSor( target, align_target, status ) ) step3 = 0; /* Step 6 is not necessary if the alignment SOR is the same as the result SOR. */ if( EqualSor( result, align_result, status ) ) step6 = 0; /* Step 7 is not necessary if the result system is frequency. */ if( result_system == AST__FREQ ) step7 = 0; /* Steps 4 and 5 are not necessary if the alignment system is frequency, or if the target and result rest frequencies are equal. */ if( align_system == AST__FREQ || result_rf == target_rf ) step4 = step5 = 0; /* Steps 3 and 6 are not necessary if steps 4 and 5 are not necessary, and the target sor equals the result sor. */ if( !step4 && !step5 && EqualSor( target, result, status ) ) step3 = step6 = 0; /* Steps 2 and 7 are not necessary if steps 3, 4, 5 and 6 are not necessary, and the target sor equals the result sor, and the target and results systems are equal (if the systems are relative they must also have equal rest frequencies). */ if( !step3 && !step4 && !step5 && !step6 && EqualSor( target, result, status ) && target_system == result_system ) { if( !ABS_SYSTEM( target_system ) && result_rf == target_rf ) step2 = step7 = 0; } /* Now we know which steps are needed, let's do them (we delay unit conversion to the end)... */ /* Step 2: target system in target rest frame to frequency in target rest frame. */ if( step2 ) { if( target_system != AST__FREQ ) { /* If the target system is absolute, we can convert directly to frequency. */ if ( target_system == AST__ENERGY ) { TRANSFORM_0( "ENTOFR" ) } else if ( target_system == AST__WAVENUM ) { TRANSFORM_0( "WNTOFR" ) } else if ( target_system == AST__WAVELEN ) { TRANSFORM_0( "WVTOFR" ) } else if ( target_system == AST__AIRWAVE ) { TRANSFORM_0( "AWTOFR" ) /* If the target target_system is relative, we first need to convert to apparent radial velocity, and then to frequency using the rest frequency. */ } else { if ( target_system == AST__VRADIO ) { TRANSFORM_0( "VRTOVL" ) } else if ( target_system == AST__VOPTICAL ) { TRANSFORM_0( "VOTOVL" ) } else if ( target_system == AST__REDSHIFT ) { TRANSFORM_0( "ZOTOVL" ) } else if ( target_system == AST__BETA ) { TRANSFORM_0( "BTTOVL" ) } VerifyAttrs( target, vmess, "RestFreq", "astMatch", status ); TRANSFORM_1( "VLTOFR", target_rf ) } } } /* Step 3: frequency in target rest frame to frequency in alignment rest frame. */ if( step3 ) match = SorConvert( target, align_target, specmap, status ); /* Step 4: frequency in alignment rest frame to alignment system in alignment rest frame. The alignment will be either relativistic velocity or frequency. */ if( step4 ) { if( align_system == AST__VREL ) { VerifyAttrs( target, vmess, "RestFreq", "astMatch", status ); TRANSFORM_1( "FRTOVL", target_rf ) } } /* Step 5: Alignment system in alignment rest frame to frequency in alignment rest frame (from now on use the attributes of the result SpecFrame to define the conversion parameters). */ if( step5 ) { if( align_system == AST__VREL ) { VerifyAttrs( result, vmess, "RestFreq", "astMatch", status ); TRANSFORM_1( "VLTOFR", result_rf ) } } /* Step 6: frequency in alignment rest frame to frequency in result rest frame. */ if( step6 ) match = SorConvert( align_result, result, specmap, status ); /* Step 7: frequency in result rest frame to result system in result rest frame. */ if( step7 ) { if( result_system != AST__FREQ ) { /* If the results system is absolute, we can convert directly. */ if ( result_system == AST__ENERGY ) { TRANSFORM_0( "FRTOEN" ) } else if ( result_system == AST__WAVENUM ) { TRANSFORM_0( "FRTOWN" ) } else if ( result_system == AST__WAVELEN ) { TRANSFORM_0( "FRTOWV" ) } else if ( result_system == AST__AIRWAVE ) { TRANSFORM_0( "FRTOAW" ) /* If the result system is relative, we first need to convert to apparent radial velocity from frequency using the rest frequency. Report an error if the rest frequency is undefined. */ } else { VerifyAttrs( result, vmess, "RestFreq", "astMatch", status ); TRANSFORM_1( "FRTOVL", result_rf ) /* Now convert from apparent radial velocity to the required result system. */ if ( result_system == AST__VRADIO ) { TRANSFORM_0( "VLTOVR" ) } else if ( result_system == AST__VOPTICAL ) { TRANSFORM_0( "VLTOVO" ) } else if ( result_system == AST__REDSHIFT ) { TRANSFORM_0( "VLTOZO" ) } else if ( result_system == AST__BETA ) { TRANSFORM_0( "VLTOBT" ) } } } } /* The SpecMap created above class assumes that the axis values supplied to its Transform method are in units which correspond to the default units for its class (the returned values also use these units). However, the Unit attributes of the supplied Frames may have been set to some non-default value, and so we need to add Mappings before and after the SpecMap which convert to and from the default units. Find the Mapping from the target Frame Units to the default Units for the target's system. */ utarg = astGetUnit( target, 0 ); umap1 = astUnitMapper( utarg, SpecMapUnit( target_system, "MakeSpecMap", "SpecFrame", status ), NULL, NULL ); /* Find the Mapping from the default Units for the result's system to the Units of the result Frame. */ ures = astGetUnit( result, 0 ); umap2 = astUnitMapper( SpecMapUnit( result_system, "MakeSpecMap", "SpecFrame", status ), ures, NULL, NULL ); /* If both units Mappings were created OK, sandwich the SpecMap between them. */ if( umap1 && umap2 ) { map1 = (AstMapping *) astCmpMap( umap1, specmap, 1, "", status ); map2 = (AstMapping *) astCmpMap( map1, umap2, 1, "", status ); map1 = astAnnul( map1 ); /* If the simplified SpecMap is a UnitMap, and the target and result units are the same, we do not need to know the mapping between units. Otherwise, report an error and indicate that we cannot convert between the Frames. */ } else { map2 = astSimplify( specmap ); if( !astIsAUnitMap( map2 ) || strcmp( ures, utarg ) ) { match = 0; if( astOK && report ) { if( !umap1 ) { uerr = utarg; serr = astGetSystem( target ); } else { uerr = ures; serr = astGetSystem( result ); } astError( AST__BADUN, "astMatch(SpecFrame): Inappropriate units (%s) " "specified for a %s axis.", status, uerr, SystemLabel( serr, status ) ); } } } /* Step 0: offset to absolute value in target system. Prepend the Maping created above with a ShiftMap that does the required shift of origin. */ target_origin = GetSpecOriginCur( target, status ); if( target_origin != 0.0 ) { sm = astShiftMap( 1, &target_origin, "", status ); map1 = (AstMapping *) astCmpMap( sm, map2, 1, "", status ); sm = astAnnul( sm ); } else { map1 = astClone( map2 ); } map2 = astAnnul( map2 ); /* Step 9: absolute value to offset in result system. If we are aligning in the offset system, use the transformed target origin as the new zero point. Otherwise use the origin from the result frame. First get the origin for the result system. */ if( astGetAlignSpecOffset( target ) && astGetAlignSpecOffset( result ) ) { result_origin = 0.0; astTran1( map1, 1, &result_origin, 1, &result_origin ); } else { result_origin = GetSpecOriginCur( result, status ); } /* Now create the ShiftMap and apend it to the end of the Maping. */ if( result_origin != 0.0 ) { result_origin = -result_origin; sm = astShiftMap( 1, &result_origin, "", status ); map2 = (AstMapping *) astCmpMap( map1, sm, 1, "", status ); sm = astAnnul( sm ); } else { map2 = astClone( map1 ); } map1 = astAnnul( map1 ); /* Return the simplified Mapping. */ *map = astSimplify( map2 ); /* Annul remaining resources. */ map2 = astAnnul( map2 ); specmap = astAnnul( specmap ); if( umap1 ) umap1 = astAnnul( umap1 ); if( umap2 ) umap2 = astAnnul( umap2 ); align_result = astAnnul( align_result ); align_target = astAnnul( align_target ); /* If an error occurred, annul the returned Mapping and clear the returned values. */ if ( !astOK ) { *map = astAnnul( *map ); match = 0; } /* Return the result. */ return match; /* Undefine macros local to this function. */ #undef MAX_ARGS #undef TRANSFORM_0 #undef TRANSFORM_1 } static int Match( AstFrame *template_frame, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * Match * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Private function. * Synopsis: * #include "specframe.h" * int Match( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * SpecFrame member function (over-rides the protected astMatch method * inherited from the Frame class). * Description: * This function matches a "template" SpecFrame to a "target" Frame and * determines whether it is possible to convert coordinates between them. * If it is, a mapping that performs the transformation is returned along * with a new Frame that describes the coordinate system that results when * this mapping is applied to the "target" coordinate system. In addition, * information is returned to allow the axes in this "result" Frame to be * associated with the corresponding axes in the "target" and "template" * Frames from which they are derived. * Parameters: * template * Pointer to the template SpecFrame. This describes the coordinate * system (or set of possible coordinate systems) into which we wish to * convert our coordinates. * target * Pointer to the target Frame. This describes the coordinate system in * which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case. * template_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the template SpecFrame axis from * which it is derived. If it is not derived from any template * SpecFrame axis, a value of -1 will be returned instead. * target_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the target Frame axis from which it * is derived. If it is not derived from any target Frame axis, a value * of -1 will be returned instead. * map * Address of a location where a pointer to a new Mapping will be * returned if the requested coordinate conversion is possible. If * returned, the forward transformation of this Mapping may be used to * convert coordinates between the "target" Frame and the "result" * Frame (see below) and the inverse transformation will convert in the * opposite direction. * result * Address of a location where a pointer to a new Frame will be returned * if the requested coordinate conversion is possible. If returned, this * Frame describes the coordinate system that results from applying the * returned Mapping (above) to the "target" coordinate system. In * general, this Frame will combine attributes from (and will therefore * be more specific than) both the target and the template Frames. In * particular, when the template allows the possibility of transformaing * to any one of a set of alternative coordinate systems, the "result" * Frame will indicate which of the alternatives was used. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the requested coordinate conversion is * possible. Otherwise zero is returned (this will not in itself result in * an error condition). * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * This implementation addresses the matching of a SpecFrame class * object to any other class of Frame. A SpecFrame will match any class * of SpecFrame (i.e. possibly from a derived class) but will not match * a less specialised class of Frame. */ /* Local Variables: */ AstFrame *frame0; /* Pointer to Frame underlying axis 0 */ AstSpecFrame *template; /* Pointer to template SpecFrame structure */ int iaxis0; /* Axis index underlying axis 0 */ int iaxis; /* Axis index */ int match; /* Coordinate conversion possible? */ int target_axis0; /* Index of SpecFrame axis in the target */ int target_naxes; /* Number of target axes */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain a pointer to the template SpecFrame structure. */ template = (AstSpecFrame *) template_frame; /* Obtain the number of axes in the target Frame. */ target_naxes = astGetNaxes( target ); /* The first criterion for a match is that the template matches as a Frame class object. This ensures that the number of axes (1) and domain, etc. of the target Frame are suitable. Invoke the parent "astMatch" method to verify this. */ match = (*parent_match)( template_frame, target, matchsub, template_axes, target_axes, map, result, status ); /* If a match was found, annul the returned objects, which are not needed, but keep the memory allocated for the axis association arrays, which we will re-use. */ if ( astOK && match ) { *map = astAnnul( *map ); *result = astAnnul( *result ); } /* If OK so far, obtain pointers to the primary Frames which underlie all target axes. Stop when a SpecFrame axis is found. */ if ( match && astOK ) { match = 0; for( iaxis = 0; iaxis < target_naxes; iaxis++ ) { astPrimaryFrame( target, iaxis, &frame0, &iaxis0 ); if( astIsASpecFrame( frame0 ) ) { frame0 = astAnnul( frame0 ); target_axis0 = iaxis; match = 1; break; } else { frame0 = astAnnul( frame0 ); } } } /* Check at least one SpecFrame axis was found it the target. Store the axis associataions. */ if( match && astOK ) { (*template_axes)[ 0 ] = 0; (*target_axes)[ 0 ] = target_axis0; /* Use the target's "astSubFrame" method to create a new Frame (the result Frame) with copies of the target axes in the required order. This process also overlays the template attributes on to the target Frame and returns a Mapping between the target and result Frames which effects the required coordinate conversion. */ match = astSubFrame( target, template, 1, *target_axes, *template_axes, map, result ); } /* If an error occurred, or conversion to the result Frame's coordinate system was not possible, then free all memory, annul the returned objects, and reset the returned value. */ if ( !astOK || !match ) { *template_axes = astFree( *template_axes ); *target_axes = astFree( *target_axes ); if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } static void OriginStdOfRest( AstSpecFrame *this, AstStdOfRestType newsor, const char *method, int *status ){ /* * Name: * OriginStdOfRest * Purpose: * Convert the SpecOrigin in a SpecFrame to a new rest frame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void OriginStdOfRest( AstSpecFrame *this, AstStdOfRestType newsor, * const char *method, int *status ) * Class Membership: * SpecFrame member function * Description: * This function converts the value of the SpecOrigin attribute stored * within a supplied SpecFrame from the rest frame currently associated * with the SpecFrame, to the new rest frame indicated by "newsor". * Parameters: * this * Point to the SpecFrame. On entry, the SpecOrigin value is * assumed to refer to the re st frame given by the astGetStdOfRest * method. On exit, the SpecOrigin value refers to the rest frame * supplied in "newsor". The StdOfRest attribute of the SpecFrame * should then be modified in order to keep things consistent. * newsor * The rest frame to which the SpecOrigin value stored within "this" * should refer on exit. * method * Pointer to a string holding the name of the method to be * included in any error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFrame *sf; AstFrameSet *fs; double origin; double neworigin; /* Check the global error status. */ if ( !astOK ) return; /* Do nothing if the SpecOrigin attribute has not been assigned a value. */ if( astTestSpecOrigin( this ) ) { /* Do nothing if the rest frame will not change. */ if( newsor != astGetStdOfRest( this ) ) { /* Save the original SpecOrigin value (in the current SpecFrame units) and then clear it. */ origin = GetSpecOriginCur( this, status ); astClearSpecOrigin( this ); /* Take a copy of the SpecFrame and set the new StdOfRest. */ sf = astCopy( this ); astSetStdOfRest( sf, newsor ); /* Create a Mapping to perform the rest frame change, then use it to convert the value to the new rest frame. */ fs = astConvert( this, sf, "" ); neworigin = AST__BAD; if( fs ) { astTran1( fs, 1, &origin, 1, &neworigin ); fs = astAnnul( fs ); } /* If succesful, convert from the current units to the default units, and store in "this". */ if( neworigin != AST__BAD ) { astSetSpecOrigin( this, ToUnits( this, astGetUnit( this, 0 ), neworigin, method, status ) ); } else if( astOK ) { astError( AST__ATSER, "%s(%s): Cannot convert the SpecOrigin " "value to a different rest frame.", status, method, astGetClass( this ) ); } } } } static void OriginSystem( AstSpecFrame *this, AstSystemType oldsys, const char *method, int *status ){ /* * Name: * OriginSystem * Purpose: * Convert the SpecOrigin in a SpecFrame to a new System. * Type: * Private function. * Synopsis: * #include "specframe.h" * void OriginSystem( AstSpecFrame *this, AstSystemType oldsys, * const char *method, int *status ) * Class Membership: * SpecFrame member function * Description: * This function converts the value of the SpecOrigin attribute stored * within a supplied SpecFrame from its original System, etc, to the * System, etc, currently associated with the SpecFrame. * Parameters: * this * Point to the SpecFrame. On entry, the SpecOrigin value is * assumed to refer to the System given by "oldsys", etc. On exit, the * SpecOrigin value refers to the System returned by the astGetSystem * method, etc. * oldsys * The System to which the SpecOrigin value stored within "this" * refers on entry. * method * A string containing the method name for error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFrame *sf1; AstSpecFrame *sf2; AstFrameSet *fs; double origin; double neworigin; /* Check the global error status. */ if ( !astOK ) return; /* Do nothing if the SpecOrigin attribute has not been assigned a value. */ if( astTestSpecOrigin( this ) ) { /* Do nothing if the System will not change. */ if( oldsys != astGetSystem( this ) ) { /* Note the original SpecOrigin value, in the SpecFrame's default units. */ origin = astGetSpecOrigin( this ); /* Take a copy of the original SpecFrame and ensure the Units, SpecOrigin and AlignSpecOffset attributes are cleared. */ sf1 = astCopy( this ); astClearUnit( sf1, 0 ); astClearSpecOrigin( sf1 ); astClearAlignSpecOffset( sf1 ); /* Take another copy of the SpecFrame and set the old system. */ sf2 = astCopy( sf1 ); astSetSystem( sf2, oldsys ); /* Create a Mapping to perform the rest frame change, then use it to convert the value to the current system. */ fs = astConvert( sf2, sf1, "" ); neworigin = AST__BAD; if( fs ) { astTran1( fs, 1, &origin, 1, &neworigin ); fs = astAnnul( fs ); } /* Free resources */ sf1 = astAnnul( sf1 ); sf2 = astAnnul( sf2 ); /* If succesful, store it in "this". */ if( neworigin != AST__BAD ) { astSetSpecOrigin( this, neworigin ); } else if( astOK ) { astError( AST__ATSER, "%s(%s): Cannot convert the SpecOrigin " "value to a different spectral system.", status, method, astGetClass( this ) ); } } } } static void Overlay( AstFrame *template, const int *template_axes, AstFrame *result, int *status ) { /* * Name: * Overlay * Purpose: * Overlay the attributes of a template SpecFrame on to another Frame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void Overlay( AstFrame *template, const int *template_axes, * AstFrame *result, int *status ) * Class Membership: * SpecFrame member function (over-rides the protected astOverlay method * inherited from the Frame class). * Description: * This function overlays attributes of a SpecFrame (the "template") on to * another Frame, so as to over-ride selected attributes of that second * Frame. Normally only those attributes which have been specifically set * in the template will be transferred. This implements a form of * defaulting, in which a Frame acquires attributes from the template, but * retains its original attributes (as the default) if new values have not * previously been explicitly set in the template. * * Note that if the result Frame is a SpecFrame and a change of spectral * coordinate system occurs as a result of overlaying its System * attribute, then some of its original attribute values may no * longer be appropriate (e.g. the Title, or attributes describing * its axes). In this case, these will be cleared before overlaying * any new values. * Parameters: * template * Pointer to the template SpecFrame, for which values should have been * explicitly set for any attribute which is to be transferred. * template_axes * Pointer to an array of int, with one element for each axis of the * "result" Frame (see below). For each axis in the result frame, the * corresponding element of this array should contain the (zero-based) * index of the template axis to which it corresponds. This array is used * to establish from which template axis any axis-dependent attributes * should be obtained. * * If any axis in the result Frame is not associated with a template * axis, the corresponding element of this array should be set to -1. * * If a NULL pointer is supplied, the template and result axis * indicies are assumed to be identical. * result * Pointer to the Frame which is to receive the new attribute values. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - In general, if the result Frame is not from the same class as the * template SpecFrame, or from a class derived from it, then attributes may * exist in the template SpecFrame which do not exist in the result Frame. * In this case, these attributes will not be transferred. */ /* Local Variables: */ AstFrame *templt; /* Copy of supplied template Frame */ AstSystemType new_system; /* Code identifying new cordinates */ AstSystemType old_system; /* Code identifying old coordinates */ const char *method; /* Pointer to method string */ const char *new_class; /* Pointer to template class string */ const char *old_class; /* Pointer to result class string */ int specframe; /* Result Frame is a SpecFrame? */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise strings used in error messages. */ new_class = astGetClass( template ); old_class = astGetClass( result ); method = "astOverlay"; /* Get the old and new systems. */ old_system = astGetSystem( result ); new_system = astGetSystem( template ); /* It may be necessary to make temporary changes to the template Frame below. In order to ensure that we make no permanent changes to the supplied frame, we will, if necessary, take a deep copy of the supplied Frame, storing a pointer to the copy in "templt". If it is not necessary to make any changes to the template, we still want "templt" to hold a usable pointer, so we initialise it now to hold a clone of the supplied pointer. This pointer will be replaced by a pointer to a deep copy (if required) below. */ templt = astClone( template ); /* If the result Frame is a SpecFrame, we must test to see if overlaying its System attribute will change the type of coordinate system it describes. Determine the value of this attribute for the result and template SpecFrames. */ specframe = astIsASpecFrame( result ); if( specframe ) { /* If the coordinate system will change, any value already set for the result SpecFrame's Title will no longer be appropriate, so clear it. */ if ( new_system != old_system ) { astClearTitle( result ); /* If the systems have the same default units, we can retain the current Unit value. */ if( strcmp( DefUnit( new_system, method, new_class, status ), DefUnit( old_system, method, old_class, status ) ) ) { astClearUnit( result, 0 ); } /* If necessary, clear inappropriate values for all those axis attributes whose access functions are over-ridden by this class (these access functions will then provide suitable defaults appropriate to the new coordinate system instead). */ astClearLabel( result, 0 ); astClearSymbol( result, 0 ); } /* If the result Frame is not a SpecFrame, we must temporarily clear the System and AlignSystem values since the values used by this class are only appropriate to this class. Use a deep copy to avoid the danger of making any permanent changes to the suppied Frame. */ } else { if( astTestSystem( template ) ) { templt = astAnnul( templt ); templt = astCopy( template ); astClearSystem( templt ); astClearAlignSystem( templt ); } } /* Invoke the parent class astOverlay method to transfer attributes inherited from the parent class. */ (*parent_overlay)( templt, template_axes, result, status ); /* Check if the result Frame is a SpecFrame or from a class derived from SpecFrame. If not, we cannot transfer SpecFrame attributes to it as it is insufficiently specialised. In this case simply omit these attributes. */ if ( specframe && astOK ) { /* Define macros that test whether an attribute is set in the template and, if so, transfers its value to the result. */ #define OVERLAY(attribute) \ if ( astTest##attribute( template ) ) { \ astSet##attribute( result, astGet##attribute( template ) ); \ } /* Use the macro to transfer each SpecFrame attribute in turn. Note, SourceVRF must be overlayed before SourceVel. Otherwise the stored value for SourceVel would be changed from the default SourceVRF to the specified SourceVRF when SourceVRF was overlayed. */ OVERLAY(AlignStdOfRest) OVERLAY(AlignSpecOffset); OVERLAY(RefDec) OVERLAY(RefRA) OVERLAY(RestFreq) OVERLAY(SourceSys) OVERLAY(SourceVRF) OVERLAY(SourceVel) OVERLAY(StdOfRest) OVERLAY(SpecOrigin) } /* Free resources */ templt = astAnnul( templt ); /* Undefine macros local to this function. */ #undef OVERLAY } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * SpecFrame member function (extends the astSetAttrib method inherited from * the Mapping class). * Description: * This function assigns an attribute value for a SpecFrame, the attribute * and its value being specified by means of a string of the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in lower * case with no white space present. The value to the right of the "=" * should be a suitable textual representation of the value to be assigned * and this will be interpreted according to the attribute's data type. * White space surrounding the value is only significant for string * attributes. * Parameters: * this * Pointer to the SpecFrame. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This protected method is intended to be invoked by the Object astSet * method and makes additional attributes accessible to it. */ /* Local Vaiables: */ AstMapping *umap; /* Mapping between units */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ AstStdOfRestType sor; /* Standard of rest type code */ AstSystemType sys; /* Spectral system type code */ char *a; /* Pointer to next character */ char *new_setting; /* Pointer value to new attribute setting */ double dval; /* Double atribute value */ double dtemp; /* Temporary double atribute value */ int ival; /* Integer attribute value */ int len; /* Length of setting string */ int ulen; /* Used length of setting string */ int namelen; /* Length of attribute name in setting */ int nc; /* Number of characters read by astSscanf */ int off; /* Offset of attribute value */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Create an FK5 J2000 SkyFrame which will be used for formatting and unformatting sky positions, etc. */ LOCK_MUTEX2 if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); astEndPM; } UNLOCK_MUTEX2 /* Obtain the length of the setting string. */ len = strlen( setting ); /* Obtain the used length of the setting string. */ ulen = astChrLen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* First look for axis attributes defined by the Frame class. Since a SpecFrame has only 1 axis, we allow these attributes to be specified without a trailing "(axis)" string. */ if ( !strncmp( setting, "direction=", 10 ) || !strncmp( setting, "bottom=", 7 ) || !strncmp( setting, "top=", 4 ) || !strncmp( setting, "format=", 7 ) || !strncmp( setting, "label=", 6 ) || !strncmp( setting, "symbol=", 7 ) || !strncmp( setting, "unit=", 5 ) ) { /* Create a new setting string from the original by appending the string "(1)" to the end of the attribute name and then use the parent SetAttrib method. */ new_setting = astMalloc( len + 4 ); if( new_setting ) { memcpy( new_setting, setting, len + 1 ); a = strchr( new_setting, '=' ); namelen = a - new_setting; memcpy( a, "(1)", 4 ); a += 3; strcpy( a, setting + namelen ); (*parent_setattrib)( this_object, new_setting, status ); new_setting = astFree( new_setting ); } /* AlignStdOfRest. */ /* --------------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "alignstdofrest=%n%*s %n", &off, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a StdOfRest code before use. */ sor = StdOfRestCode( setting + off, status ); if ( sor != AST__BADSOR ) { astSetAlignStdOfRest( this, sor ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " "description \"%s\".", status, astGetClass( this ), setting+off ); } /* GeoLat. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ } else if ( nc = 0, ( 0 == astSscanf( setting, "geolat=%n%*s %n", &off, &nc ) ) && ( nc >= 7 ) ) { new_setting = astStore( NULL, setting, len + 1 ); new_setting[ 0 ] = 'o'; new_setting[ 1 ] = 'b'; new_setting[ 2 ] = 's'; astSetAttrib( this, new_setting ); new_setting = astFree( new_setting ); /* GeoLon. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "geolon=%n%*s %n", &off, &nc ) ) && ( nc >= 7 ) ) { new_setting = astStore( NULL, setting, len + 1 ); new_setting[ 0 ] = 'o'; new_setting[ 1 ] = 'b'; new_setting[ 2 ] = 's'; astSetAttrib( this, new_setting ); new_setting = astFree( new_setting ); /* RefDec. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "refdec=%n%*s %n", &off, &nc ) ) && ( nc >= 7 ) ) { /* Convert the string to a radians value before use. */ ival = astUnformat( skyframe, 1, setting + off, &dval ); if ( ival == ulen - off ) { astSetRefDec( this, dval ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid reference " "declination \"%s\".", status, astGetClass( this ), setting + off ); } /* RefRA. */ /* ------ */ } else if ( nc = 0, ( 0 == astSscanf( setting, "refra=%n%*s %n", &off, &nc ) ) && ( nc >= 6 ) ) { /* Convert the string to a radians value before use. */ ival = astUnformat( skyframe, 0, setting + off, &dval ); if ( ival == ulen - off ) { astSetRefRA( this, dval ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid reference right " "ascension \"%s\".", status, astGetClass( this ), setting + off ); } /* AlignSpecOffset. */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "alignspecoffset= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetAlignSpecOffset( this, ival ); /* RestFreq. */ /* --------- */ /* Without any units indication - assume GHz. Convert to Hz for storage. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "restfreq= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetRestFreq( this, dval*1.0E9 ); /* With units indication. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "restfreq= %lg %n%*s %n", &dval, &off, &nc ) ) && ( nc >= len ) ) { /* Is there a Mapping from the supplied units to Hz? If so, use the Mapping to convert the supplied value to Hz. */ if( ( umap = astUnitMapper( setting + off, "Hz", NULL, NULL ) ) ) { astTran1( umap, 1, &dval, 1, &dtemp ); umap = astAnnul( umap ); /* Otherwise, if there is a Mapping from the supplied units to metre, assume the supplied unit is a vacuum wavelength. */ } else if( ( umap = astUnitMapper( setting + off, "m", NULL, NULL ) ) ) { /* Convert the supplied wavelength to metres. */ astTran1( umap, 1, &dval, 1, &dtemp ); umap = astAnnul( umap ); /* Convert the wavelength (m) to frequency (Hz). */ if( dtemp != AST__BAD && dtemp != 0.0 ) { dtemp = AST__C/dtemp; } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): Invalid rest wavelength " "\"%g %s\" supplied.", status, astGetClass( this ), dval, setting + off ); } /* Otherwise, if there is a Mapping from the supplied units to Joule, assume the supplied unit is an energy. */ } else if( ( umap = astUnitMapper( setting + off, "J", NULL, NULL ) ) ) { /* Convert the supplied energy to Joules. */ astTran1( umap, 1, &dval, 1, &dtemp ); umap = astAnnul( umap ); /* Convert the energy (J) to frequency (Hz). */ if( dtemp != AST__BAD ) { dtemp *= 1.0/AST__H; } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): Invalid rest energy " "\"%g %s\" supplied.", status, astGetClass( this ), dval, setting + off ); } /* Otherwise report an error. */ } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): Rest frequency given in an " "unsupported system of units \"%g %s\".", status, astGetClass( this ), dval, setting + off ); } /* Set the rest frequency. */ astSetRestFreq( this, dtemp ); /* SourceVel. */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "sourcevel= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { /* Convert from km/s to m/s if the SourceVel value is a velocity. */ if( astGetSourceSys( this ) == AST__VREL || astGetSourceSys( this ) == AST__VRADIO || astGetSourceSys( this ) == AST__VOPTICAL ) dval *= 1.0E3; /* Store the value */ astSetSourceVel( this, dval ); /* SourceVRF */ /* --------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "sourcevrf=%n%*s %n", &off, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a StdOfRest code before use. */ sor = StdOfRestCode( setting + off, status ); if ( sor != AST__BADSOR ) { astSetSourceVRF( this, sor ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " "description \"%s\".", status, astGetClass( this ), setting+off ); } /* SourceSys */ /* --------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "sourcesys=%n%*s %n", &off, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a System code before use. */ sys = SystemCode( (AstFrame *) this, setting + off, status ); astSetSourceSys( this, sys ); /* StdOfRest. */ /* ---------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "stdofrest=%n%*s %n", &off, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a StdOfRest code before use. */ sor = StdOfRestCode( setting + off, status ); if ( sor != AST__BADSOR ) { astSetStdOfRest( this, sor ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " "description \"%s\".", status, astGetClass( this ), setting + off ); } /* SpecOrigin */ /* ---------- */ /* Floating-point without any units indication - assume the current Unit value. Convert from current units to default units for current system. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "specorigin= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetSpecOrigin( this, ToUnits( this, astGetUnit( this, 0 ), dval, "astSetSpecOrigin", status ) ); /* Floating-point with units. Convert the supplied value to the default units for the SpecFrame's System. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "specorigin= %lg %n%*s %n", &dval, &off, &nc ) ) && ( nc >= len ) ) { astSetSpecOrigin( this, ToUnits( this, setting + off, dval, "astSetSpecOrigin", status ) ); /* Pass any unrecognised setting to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static void SetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double lon, double lat, int *status ){ /* *++ * Name: c astSetRefPos f AST_SETREFPOS * Purpose: * Set the reference position in a specified celestial coordinate system. * Type: * Public virtual function. * Synopsis: c #include "specframe.h" c void astSetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double lon, c double lat ) f CALL AST_SETREFPOS( THIS, FRM, LON, LAT, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * sets the reference position (see attributes RefRA and RefDec) using * axis values (in radians) supplied within the celestial coordinate * system represented by a supplied SkyFrame. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the SpecFrame. c frm f FRM = INTEGER (Given) * Pointer to the SkyFrame which defines the celestial coordinate * system in which the longitude and latitude values are supplied. c If NULL f If AST__NULL * is supplied, then the supplied longitude and latitude values are * assumed to be FK5 J2000 RA and Dec values. c lon f LON = DOUBLE PRECISION (Given) * The longitude of the reference point, in the coordinate system * represented by the supplied SkyFrame (radians). c lat f LAT = DOUBLE PRECISION (Given) * The latitude of the reference point, in the coordinate system * represented by the supplied SkyFrame (radians). f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstFrameSet *fs; /* Conversion FrameSet */ AstFrame *fb; /* Base Frame */ AstFrame *fc; /* Current Frame */ double xin[ 1 ]; /* Axis 1 values */ double yin[ 1 ]; /* Axis 2 values */ double xout[ 1 ]; /* Axis 1 values */ double yout[ 1 ]; /* Axis 2 values */ /* Check the global error status. */ if ( !astOK ) return; /* If no SkyFrame was supplied, just store the supplied RefRA and RefDec values. */ if( !frm ) { astSetRefRA( this, lon ); astSetRefDec( this, lat ); /* Otherwise, convert the supplied values from the requested system. */ } else { /* Create an FK5 J2000 SkyFrame which will be used for formatting and unformatting sky positions, etc. */ LOCK_MUTEX2 if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); astEndPM; } UNLOCK_MUTEX2 /* Find the Mapping from the supplied SkyFrame, to the SkyFrame which describes the internal format in which the RefRA and RefDec attribute values are stored. */ fs = astFindFrame( frm, skyframe, "" ); /* If alignment was possible, use the Mapping to transform the supplied axis values, checking to see if the axes of the supplied SkyFrame have been permuted. */ if( fs ) { /* Find the longitude axis in the Base Frame, and store the supplied longitude and latitude values. */ fb = astGetFrame( fs, AST__BASE ); if( astGetLonAxis( fb ) == 0 ) { xin[ 0 ] = lon; yin[ 0 ] = lat; } else { xin[ 0 ] = lat; yin[ 0 ] = lon; } astTran2( fs, 1, xin, yin, 1, xout, yout ); /* Store the corresponding RefRA and RefDec values. */ fc = astGetFrame( fs, AST__CURRENT ); if( astGetLonAxis( fc ) == 0 ) { astSetRefRA( this, xout[ 0 ] ); astSetRefDec( this, yout[ 0 ] ); } else { astSetRefRA( this, yout[ 0 ] ); astSetRefDec( this, xout[ 0 ] ); } /* Annul object references. */ fc = astAnnul( fc ); fb = astAnnul( fb ); fs = astAnnul( fs ); } } } static void SetStdOfRest( AstSpecFrame *this, AstStdOfRestType value, int *status ) { /* *+ * Name: * astSetStdOfRest * Purpose: * Set the StdOfRest attribute for a SpecFrame. * Type: * Protected function. * Synopsis: * #include "specframe.h" * void astSetStdOfRest( AstSpecFrame *this, AstStdOfRestType value ) * Class Membership: * SpecFrame virtual function * Description: * This function set a new value for the StdOfRest attribute for a * SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * value * The new value. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the StdOfRest value being set and report an error if necessary. */ if( value < FIRST_SOR || value > LAST_SOR ) { astError( AST__ATTIN, "%s(%s): Bad value (%d) given for StdOfRest attribute.", status, "astSetStdOfRest", astGetClass( this ), (int) value ); /* Otherwise set the new StdOfRest */ } else { /* Modify the SpecOrigin value stored in the SpecFrame structure to refer to the new rest frame. */ OriginStdOfRest( this, value, "astSetStdOfRest", status ); /* Store the new value for the rest frame in the SpecFrame structure. */ this->stdofrest = value; } } static void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status ) { /* * Name: * SetSystem * Purpose: * Set the System attribute for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status ) * Class Membership: * SpecFrame member function (over-rides the astSetSystem protected * method inherited from the Frame class). * Description: * This function sets the System attribute for a SpecFrame. * Parameters: * this * Pointer to the SpecFrame. * newsys * The new System value to be stored. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to SpecFrame structure */ AstSystemType oldsys; /* Original System value */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* Save the original System value */ oldsys = astGetSystem( this_frame ); /* Use the parent SetSystem method to store the new System value. */ (*parent_setsystem)( this_frame, newsys, status ); /* If the system has changed... */ if( oldsys != newsys ) { /* Changing the System value will in general require the Units to change as well. If the user has previously specified the units to be used with the new system, then re-instate them (they are stored in the "usedunits" array in the SpecFrame structure). Otherwise, clear the units so that the default units will eb used with the new System. */ if( (int) newsys < this->nuunits && this->usedunits && this->usedunits[ (int) newsys ] ) { astSetUnit( this, 0, this->usedunits[ (int) newsys ] ); } else { astClearUnit( this, 0 ); } /* Modify the stored SpecOrigin. */ OriginSystem( this, oldsys, "astSetSystem", status ); /* Also, clear all attributes which have system-specific defaults. */ astClearLabel( this_frame, 0 ); astClearSymbol( this_frame, 0 ); astClearTitle( this_frame ); } } static void SetUnit( AstFrame *this_frame, int axis, const char *value, int *status ) { /* * Name: * SetUnit * Purpose: * Set a pointer to the Unit string for a SpecFrame's axis. * Type: * Private function. * Synopsis: * #include "specframe.h" * void SetUnit( AstFrame *this_frame, int axis, const char *value ) * Class Membership: * SpecFrame member function (over-rides the astSetUnit method inherited * from the Frame class). * Description: * This function stores a pointer to the Unit string for a specified axis * of a SpecFrame. It also stores the string in the "usedunits" array * in the SpecFrame structure, in the element associated with the * current System. * Parameters: * this * Pointer to the SpecFrame. * axis * The number of the axis (zero-based) for which information is required. * unit * The new string to store. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ int i; /* Loop counter */ int system; /* The SpecFrame's System value */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_frame; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astSetUnit" ); /* Store the supplied value as the UsedUnit for the current System. First ensure the array is big enough. Free any previous value stored for the current system. */ system = (int) astGetSystem( this ); if( system >= this->nuunits ) { this->usedunits = astGrow( this->usedunits, system + 1, sizeof(char *) ); if( astOK ) { for( i = this->nuunits; i < system + 1; i++ ) this->usedunits[ i ] = NULL; this->nuunits = system + 1; } } /* Now store a copy of the value, if it is different to the stored string. */ if( astOK && ( !this->usedunits[ system ] || strcmp( this->usedunits[ system ], value ) ) ) { this->usedunits[ system ] = astStore( this->usedunits[ system ], value, strlen( value ) + 1 ); } /* Now use the parent SetUnit method to store the value in the Axis structure */ (*parent_setunit)( this_frame, axis, value, status ); } static int SorConvert( AstSpecFrame *this, AstSpecFrame *that, AstSpecMap *specmap, int *status ) { /* * Name: * SorConvert * Purpose: * Add a conversion to a SpecMap which transforms between two * standards of rest. * Type: * Private function. * Synopsis: * #include "specframe.h" * int SorConvert( AstSpecFrame *this, AstSpecFrame *that, * AstSpecMap *specmap, int *status ) * Class Membership: * SpecFrame member function. * Description: * This function adds a conversion to a SpecMap which transforms * frequencies from the standard of rest specified by "this" to * the standard of rest specified by "that". Note the conversion is * always between frequency in the two rest frames no matter what the * System attributes of the two SpecFrames may be (which are ignored). * Parameters: * this * The SpecFrame which defines the input rest frame. * that * The SpecFrame which defines the output rest frame. * specmap * The SpecMap to which the conversion is to be added. * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the conversion could not be performed. One is * returned otherwise. */ /* Local Constants: */ #define MAX_ARGS 7 /* Max arguments for an SpecMap conversion */ /* Local Variables: */ AstStdOfRestType from; /* Input standard of rest */ AstStdOfRestType to; /* Output standard of rest */ const char *vmess; /* Text for use in error messages */ double args[ MAX_ARGS ]; /* Conversion argument array */ double dec; /* DEC of source (radians, FK5 J2000) */ double epoch; /* Epoch of observation (MJD) */ double alt; /* Observers geodetic altitude (radians) */ double lat; /* Observers geodetic latitude (radians) */ double lon; /* Observers geodetic longitude (radians) */ double ra; /* RA of source (radians, FK5 J2000) */ int result; /* Returned value */ /* Initialise */ result = 1; /* Check the global error status. */ if ( !astOK ) return result; /* No conversion is required if the rest frames are equal. */ if( !EqualSor( this, that, status ) ) { /* Define local macros as shorthand for adding spectral coordinate conversions to the SpecMap. Each macro simply stores details of the additional arguments in the "args" array and then calls astSpecAdd. The macros differ in the number of additional argument values. */ #define TRANSFORM_2(cvt,arg0,arg1) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ astSpecAdd( specmap, cvt, args ); #define TRANSFORM_3(cvt,arg0,arg1,arg2) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ args[ 2 ] = arg2; \ astSpecAdd( specmap, cvt, args ); #define TRANSFORM_6(cvt,arg0,arg1,arg2,arg3,arg4,arg5) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ args[ 2 ] = arg2; \ args[ 3 ] = arg3; \ args[ 4 ] = arg4; \ args[ 5 ] = arg5; \ astSpecAdd( specmap, cvt, args ); /* A string for use in error messages. */ vmess = "convert between different standards of rest"; /* Get the required values from "this". */ from = astGetStdOfRest( this ); ra = astGetRefRA( this ); dec = astGetRefDec( this ); lon = astGetObsLon( this ); lat = astGetObsLat( this ); alt = astGetObsAlt( this ); epoch = astGetEpoch( this ); /* Verify that the reference RA and DEC can be used (they are needed by all the conversions used below). */ VerifyAttrs( this, vmess, "RefRA RefDec", "astMatch", status ); /* Convert from the "this" rest frame to heliographic. */ if( from == AST__TPSOR ) { VerifyAttrs( this, vmess, "ObsLon ObsLat ObsAlt Epoch", "astMatch", status ); TRANSFORM_6( "TPF2HL", lon, lat, alt, epoch, ra, dec ) } else if( from == AST__GESOR ) { VerifyAttrs( this, vmess, "Epoch", "astMatch", status ); TRANSFORM_3( "GEF2HL", epoch, ra, dec ) } else if( from == AST__BYSOR ) { VerifyAttrs( this, vmess, "Epoch", "astMatch", status ); TRANSFORM_3( "BYF2HL", epoch, ra, dec ) } else if( from == AST__LKSOR ) { TRANSFORM_2( "LKF2HL", ra, dec ) } else if( from == AST__LDSOR ) { TRANSFORM_2( "LDF2HL", ra, dec ) } else if( from == AST__LGSOR ) { TRANSFORM_2( "LGF2HL", ra, dec ) } else if( from == AST__GLSOR ) { TRANSFORM_2( "GLF2HL", ra, dec ) } else if( from == AST__SCSOR ) { TRANSFORM_3( "USF2HL", ConvertSourceVel( this, AST__HLSOR, AST__VREL, status ), ra, dec ) } /* Now go from heliocentric to the "to" frame. */ to = astGetStdOfRest( that ); ra = astGetRefRA( that ); dec = astGetRefDec( that ); lon = astGetObsLon( that ); lat = astGetObsLat( that ); alt = astGetObsAlt( that ); epoch = astGetEpoch( that ); VerifyAttrs( that, vmess, "RefRA RefDec", "astMatch", status ); if( to == AST__TPSOR ) { VerifyAttrs( that, vmess, "ObsLon ObsLat ObsAlt Epoch", "astMatch", status ); TRANSFORM_6( "HLF2TP", lon, lat, alt, epoch, ra, dec ) } else if( to == AST__GESOR ) { VerifyAttrs( that, vmess, "Epoch", "astMatch", status ); TRANSFORM_3( "HLF2GE", epoch, ra, dec ) } else if( to == AST__BYSOR ) { VerifyAttrs( that, vmess, "Epoch", "astMatch", status ); TRANSFORM_3( "HLF2BY", epoch, ra, dec ) } else if( to == AST__LKSOR ) { TRANSFORM_2( "HLF2LK", ra, dec ) } else if( to == AST__LDSOR ) { TRANSFORM_2( "HLF2LD", ra, dec ) } else if( to == AST__LGSOR ) { TRANSFORM_2( "HLF2LG", ra, dec ) } else if( to == AST__GLSOR ) { TRANSFORM_2( "HLF2GL", ra, dec ) } else if( to == AST__SCSOR ) { TRANSFORM_3( "HLF2US", ConvertSourceVel( that, AST__HLSOR, AST__VREL, status ), ra, dec ) } } /* Return the result. */ return result; /* Undefine macros local to this function. */ #undef MAX_ARGS #undef TRANSFORM_2 #undef TRANSFORM_3 #undef TRANSFORM_6 } static const char *SpecMapUnit( AstSystemType system, const char *method, const char *class, int *status ){ /* * Name: * SpecMapUnit * Purpose: * Return the default units for a spectral coordinate system type used * by the SpecMap class. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *SpecMapUnit( AstSystemType system, const char *method, * const char *class, int *status ) * Class Membership: * SpecFrame member function. * Description: * This function returns a textual representation of the * units used by the SpecMap class for the specified spectral * coordinate system. In general, the SpecMap class uses SI units * (m/s, Hz, m, etc), but this class (SpecFrame) has default units * more appropriate to astronomers (km/s, GHz, Angstroms, etc). * Parameters: * system * The spectral coordinate system. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A string describing the default units. This string follows the * units syntax described in FITS WCS paper I "Representations of world * coordinates in FITS" (Greisen & Calabretta). * Notes: * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ const char *result; /* Value to return */ /* Initialize */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get an identifier for the default units. */ if( system == AST__FREQ ) { result = "Hz"; } else if( system == AST__ENERGY ) { result = "J"; } else if( system == AST__WAVENUM ) { result = "1/m"; } else if( system == AST__WAVELEN ) { result = "m"; } else if( system == AST__AIRWAVE ) { result = "m"; } else if( system == AST__VRADIO ) { result = "m/s"; } else if( system == AST__VOPTICAL ) { result = "m/s"; } else if( system == AST__REDSHIFT ) { result = ""; } else if( system == AST__BETA ) { result = ""; } else if( system == AST__VREL ) { result = "m/s"; /* Report an error if the coordinate system was not recognised. */ } else { astError( AST__SCSIN, "%s(%s): Corrupt %s contains illegal System " "identification code (%d).", status, method, class, class, (int) system ); } /* Return the result. */ return result; } static AstStdOfRestType StdOfRestCode( const char *sor, int *status ) { /* * Name: * StdOfRestCode * Purpose: * Convert a string into a standard of rest type code. * Type: * Private function. * Synopsis: * #include "specframe.h" * AstStdOfRestType StdOfRestCode( const char *sor ) * Class Membership: * SpecFrame member function. * Description: * This function converts a string used for the external description of * a standard of rest into a SpecFrame standard of rest type code * (StdOfRest attribute value). It is the inverse of the * StdOfRestString function. * Parameters: * sor * Pointer to a constant null-terminated string containing the * external description of the standard of rest. * Returned Value: * The StdOfRest type code. * Notes: * - A value of AST__BADSOR is returned if the standard of rest * description was not recognised. This does not produce an error. * - A value of AST__BADSOR is also returned if this function * is invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ AstStdOfRestType result; /* Result value to return */ /* Initialise. */ result = AST__BADSOR; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "sor" string against each possibility and assign the result. */ if ( astChrMatch( "TOPO", sor ) || astChrMatch( "TOPOCENT", sor ) || astChrMatch( "TOPOCENTRIC", sor ) ) { result = AST__TPSOR; } else if ( astChrMatch( "GEO", sor ) || astChrMatch( "GEOCENTR", sor ) || astChrMatch( "GEOCENTRIC", sor ) ) { result = AST__GESOR; } else if ( astChrMatch( "BARY", sor ) || astChrMatch( "BARYCENT", sor ) || astChrMatch( "BARYCENTRIC", sor ) ) { result = AST__BYSOR; } else if ( astChrMatch( "HELIO", sor ) || astChrMatch( "HELIOCEN", sor ) || astChrMatch( "HELIOCENTRIC", sor ) ) { result = AST__HLSOR; } else if ( astChrMatch( "LSRK", sor ) || astChrMatch( "LSR", sor ) ) { result = AST__LKSOR; } else if ( astChrMatch( "LSRD", sor ) ) { result = AST__LDSOR; } else if ( astChrMatch( "GAL", sor ) || astChrMatch( "GALACTOC", sor ) || astChrMatch( "GALACTIC", sor ) ) { result = AST__GLSOR; } else if ( astChrMatch( "LG", sor ) || astChrMatch( "LOCALGRP", sor ) || astChrMatch( "LOCAL_GROUP", sor ) || astChrMatch( "LOCAL-GROUP", sor ) ) { result = AST__LGSOR; } else if ( astChrMatch( "SOURCE", sor ) || astChrMatch( "SRC", sor ) ) { result = AST__SCSOR; } /* Return the result. */ return result; } static const char *StdOfRestString( AstStdOfRestType sor, int *status ) { /* * Name: * StdOfRestString * Purpose: * Convert a standard of rest type code into a string. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *StdOfRestString( AstStdOfRestType sor, int *status ) * Class Membership: * SpecFrame member function. * Description: * This function converts a SpecFrame standard of rest type code * (StdOfRest attribute value) into a string suitable for use as an * external representation of the standard of rest type. * Parameters: * sor * The standard of rest type code. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the standard of rest * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "sor" value against each possibility and convert to a string pointer. (Where possible, return the same string as would be used in the FITS WCS representation of the standard of rest). */ switch ( sor ) { case AST__TPSOR: result = "Topocentric"; break; case AST__GESOR: result = "Geocentric"; break; case AST__BYSOR: result = "Barycentric"; break; case AST__HLSOR: result = "Heliocentric"; break; case AST__LDSOR: result = "LSRD"; break; case AST__LKSOR: result = "LSRK"; break; case AST__LGSOR: result = "Local_group"; break; case AST__GLSOR: result = "Galactic"; break; case AST__SCSOR: result = "Source"; break; } /* Return the result pointer. */ return result; } static int SubFrame( AstFrame *target_frame, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * SubFrame * Purpose: * Select axes from a SpecFrame and convert to the new coordinate * system. * Type: * Private function. * Synopsis: * #include "specframe.h" * int SubFrame( AstFrame *target, AstFrame *template, * int result_naxes, const int *target_axes, * const int *template_axes, AstMapping **map, * AstFrame **result, int *status ) * Class Membership: * SpecFrame member function (over-rides the protected astSubFrame * method inherited from the Frame class). * Description: * This function selects a requested sub-set (or super-set) of the axes * from a "target" SpecFrame and creates a new Frame with copies of * the selected axes assembled in the requested order. It then * optionally overlays the attributes of a "template" Frame on to the * result. It returns both the resulting Frame and a Mapping that * describes how to convert between the coordinate systems described by * the target and result Frames. If necessary, this Mapping takes * account of any differences in the Frames' attributes due to the * influence of the template. * Parameters: * target * Pointer to the target SpecFrame, from which axes are to be * selected. * template * Pointer to the template Frame, from which new attributes for the * result Frame are to be obtained. Optionally, this may be NULL, in * which case no overlaying of template attributes will be performed. * result_naxes * Number of axes to be selected from the target Frame. This number may * be greater than or less than the number of axes in this Frame (or * equal). * target_axes * Pointer to an array of int with result_naxes elements, giving a list * of the (zero-based) axis indices of the axes to be selected from the * target SpecFrame. The order in which these are given determines * the order in which the axes appear in the result Frame. If any of the * values in this array is set to -1, the corresponding result axis will * not be derived from the target Frame, but will be assigned default * attributes instead. * template_axes * Pointer to an array of int with result_naxes elements. This should * contain a list of the template axes (given as zero-based axis indices) * with which the axes of the result Frame are to be associated. This * array determines which axes are used when overlaying axis-dependent * attributes of the template on to the result. If any element of this * array is set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not used and * a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned Mapping. * The forward transformation of this Mapping will describe how to * convert coordinates from the coordinate system described by the target * SpecFrame to that described by the result Frame. The inverse * transformation will convert in the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if coordinate conversion is possible * between the target and the result Frame. Otherwise zero is returned and * *map and *result are returned as NULL (but this will not in itself * result in an error condition). In general, coordinate conversion should * always be possible if no template Frame is supplied but may not always * be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * - This implementation addresses the selection of axes from a * SpecFrame object. This results in another object of the same class * only if the single SpecFrame axis is selected exactly once. * Otherwise, the result is a Frame class object which inherits the * SpecFrame's axis information (if appropriate) but none of the other * properties of a SpecFrame. * - In the event that a SpecFrame results, the returned Mapping will * take proper account of the relationship between the target and result * coordinate systems. * - In the event that a Frame class object results, the returned Mapping * will only represent a selection/permutation of axes. * Implementation Deficiencies: * - Any axis selection is currently permitted. Probably this should be * restricted so that each axis can only be selected once. The * astValidateAxisSelection method will do this but currently there are bugs * in the CmpFrame class that cause axis selections which will not pass this * test. Install the validation when these are fixed. */ /* Local Variables: */ AstSpecFrame *target; /* Pointer to the SpecFrame structure */ AstSpecFrame *temp; /* Pointer to copy of target SpecFrame */ AstSpecFrame *align_frm; /* Frame in which to align the SpecFrames */ int match; /* Coordinate conversion is possible? */ int report; /* Report errors if SpecFrames cannot be aligned? */ /* Initialise the returned values. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain a pointer to the target SpecFrame structure. */ target = (AstSpecFrame *) target_frame; /* Result is a SpecFrame. */ /* -------------------------- */ /* Check if the result Frame is to have one axis obtained by selecting the single target SpecFrame axis. If so, the result will also be a SpecFrame. */ if ( ( result_naxes == 1 ) && ( target_axes[ 0 ] == 0 ) ) { /* Form the result from a copy of the target. */ *result = astCopy( target ); /* Initialise a flag to indicate that MakeSpecMapping should not report errors if no Mapping can be created. */ report = 0; /* If required, overlay the template attributes on to the result SpecFrame. Also get the system and standard of rest in which to align the two SpecFrames. These are the values from the template (if there is a template). */ if ( template ) { astOverlay( template, template_axes, *result ); if( astIsASpecFrame( template ) ) { align_frm = astCopy( template ); /* Since we now know that both the template and target are SpecFrames, it should usually be possible to convert betwen them. If conversion is *not* possible (fpr instance if no rest frequency is availalbe, etc) then the user will probably be interested in knowing the reason why conversion is not possible. Therefore, indicate that MakeSpecMapping should report errors if no Mapping can be created. */ report = 1; } else { align_frm = astCopy( target ); } /* If no template was supplied, align in the System and StdOfRest of the target. */ } else { VerifyAttrs( target, "convert between different spectral systems", "StdOfRest", "astMatch", status ); align_frm = astCopy( target ); } /* The MakeSpecMapping function uses the System and StdOfRest attributes to define the alignment frame. But the AlignSystem and AlignStdOfRest attributes should be used for this purpose. Therefore, copy the values of the AlignSystem and AlignStdOfRest attributes to the System and StdOfRest attribute. */ astSetSystem( align_frm, astGetAlignSystem( align_frm ) ); astSetStdOfRest( align_frm, astGetAlignStdOfRest( align_frm ) ); /* Generate a Mapping that takes account of changes in the sky coordinate system (equinox, epoch, etc.) between the target SpecFrame and the result SpecFrame. If this Mapping can be generated, set "match" to indicate that coordinate conversion is possible. If the template is a specframe, report errors if a match is not possible. */ match = ( MakeSpecMapping( target, (AstSpecFrame *) *result, align_frm, report, map, status ) != 0 ); /* Free resources. */ align_frm = astAnnul( align_frm ); /* Result is not a SpecFrame. */ /* ------------------------------ */ /* In this case, we select axes as if the target were from the Frame class. However, since the resulting data will then be separated from their enclosing SpecFrame, default attribute values may differ if the methods for obtaining them were over-ridden by the SpecFrame class. To overcome this, we ensure that these values are explicitly set for the result Frame (rather than relying on their defaults). */ } else { /* Make a temporary copy of the target SpecFrame. We will explicitly set the attribute values in this copy so as not to modify the original. */ temp = astCopy( target ); /* Define a macro to test if an attribute is set. If not, set it explicitly to its default value. */ #define SET(attribute) \ if ( !astTest##attribute( temp ) ) { \ astSet##attribute( temp, astGet##attribute( temp ) ); \ } /* Set attribute values which apply to the Frame as a whole and which we want to retain, but whose defaults are over-ridden by the SpecFrame class. */ SET(Domain) SET(Title) /* Define a macro to test if an attribute is set for axis zero (the only axis of a SpecFrame). If not, set it explicitly to its default value. */ #define SET_AXIS(attribute) \ if ( !astTest##attribute( temp, 0 ) ) { \ astSet##attribute( temp, 0, \ astGet##attribute( temp, 0 ) ); \ } /* Use this macro to set explicit values for all the axis attributes for which the SpecFrame class over-rides the default value. */ SET_AXIS(Label) SET_AXIS(Symbol) SET_AXIS(Unit) /* Clear attributes which have an extended range of values allowed by this class. */ astClearSystem( temp ); astClearAlignSystem( temp ); /* Invoke the astSubFrame method inherited from the Frame class to produce the result Frame by selecting the required set of axes and overlaying the template Frame's attributes. */ match = (*parent_subframe)( (AstFrame *) temp, template, result_naxes, target_axes, template_axes, map, result, status ); /* Delete the temporary copy of the target SpecFrame. */ temp = astDelete( temp ); } /* If an error occurred or no match was found, annul the returned objects and reset the returned result. */ if ( !astOK || !match ) { if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; /* Undefine macros local to this function. */ #undef SET #undef SET_AXIS } static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) { /* * Name: * SystemCode * Purpose: * Convert a string into a coordinate system type code. * Type: * Private function. * Synopsis: * #include "specframe.h" * AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) * Class Membership: * SpecFrame member function (over-rides the astSystemCode method * inherited from the Frame class). * Description: * This function converts a string used for the external * description of a coordinate system into a SpecFrame * coordinate system type code (System attribute value). It is the * inverse of the astSystemString function. * Parameters: * this * The Frame. * system * Pointer to a constant null-terminated string containing the * external description of the sky coordinate system. * status * Pointer to the inherited status variable. * Returned Value: * The System type code. * Notes: * - A value of AST__BADSYSTEM is returned if the sky coordinate * system description was not recognised. This does not produce an * error. * - A value of AST__BADSYSTEM is also returned if this function * is invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ AstSystemType result; /* Result value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" string against each possibility and assign the result. */ if ( astChrMatch( "FREQ", system ) ) { result = AST__FREQ; } else if ( astChrMatch( "ENER", system ) || astChrMatch( "ENERGY", system ) ) { result = AST__ENERGY; } else if ( astChrMatch( "WAVN", system ) || astChrMatch( "WAVENUM", system ) ) { result = AST__WAVENUM; } else if ( astChrMatch( "WAVE", system ) || astChrMatch( "WAVELEN", system ) ) { result = AST__WAVELEN; } else if ( astChrMatch( "AWAV", system ) || astChrMatch( "AIRWAVE", system ) ) { result = AST__AIRWAVE; } else if ( astChrMatch( "VRAD", system ) || astChrMatch( "VRADIO", system ) ) { result = AST__VRADIO; } else if ( astChrMatch( "VOPT", system ) || astChrMatch( "VOPTICAL", system ) ) { result = AST__VOPTICAL; } else if ( astChrMatch( "ZOPT", system ) || astChrMatch( "REDSHIFT", system ) ) { result = AST__REDSHIFT; } else if ( astChrMatch( "BETA", system ) ) { result = AST__BETA; } else if ( astChrMatch( "VELO", system ) || astChrMatch( "VREL", system ) ) { result = AST__VREL; } /* Return the result. */ return result; } static const char *SystemLabel( AstSystemType system, int *status ) { /* * Name: * SystemLabel * Purpose: * Return a label for a coordinate system type code. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *SystemLabel( AstSystemType system, int *status ) * Class Membership: * SpecFrame member function. * Description: * This function converts a SpecFrame coordinate system type code * (System attribute value) into a descriptive string for human readers. * Parameters: * system * The coordinate system type code. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the sky coordinate system * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" value against each possibility and convert to a string pointer. */ switch ( system ) { case AST__FREQ: result = "frequency"; break; case AST__ENERGY: result = "energy"; break; case AST__WAVENUM: result = "wave-number"; break; case AST__WAVELEN: result = "wavelength"; break; case AST__AIRWAVE: result = "wavelength in air"; break; case AST__VRADIO: result = "radio velocity"; break; case AST__VOPTICAL: result = "optical velocity"; break; case AST__REDSHIFT: result = "redshift"; break; case AST__BETA: result = "beta factor"; break; case AST__VREL: result = "apparent radial velocity"; break; } /* Return the result pointer. */ return result; } static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) { /* * Name: * SystemString * Purpose: * Convert a coordinate system type code into a string. * Type: * Private function. * Synopsis: * #include "specframe.h" * const char *SystemString( AstFrame *this, AstSystemType system, int *status ) * Class Membership: * SpecFrame member function (over-rides the astSystemString method * inherited from the Frame class). * Description: * This function converts a SpecFrame coordinate system type code * (System attribute value) into a string suitable for use as an * external representation of the coordinate system type. * Parameters: * this * The Frame. * system * The coordinate system type code. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the sky coordinate system * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" value against each possibility and convert to a string pointer. (Where possible, return the same string as would be used in the FITS WCS representation of the coordinate system). */ switch ( system ) { case AST__FREQ: result = "FREQ"; break; case AST__ENERGY: result = "ENER"; break; case AST__WAVENUM: result = "WAVN"; break; case AST__WAVELEN: result = "WAVE"; break; case AST__AIRWAVE: result = "AWAV"; break; case AST__VRADIO: result = "VRAD"; break; case AST__VOPTICAL: result = "VOPT"; break; case AST__REDSHIFT: result = "ZOPT"; break; case AST__BETA: result = "BETA"; break; case AST__VREL: result = "VELO"; break; } /* Return the result pointer. */ return result; } static int TestActiveUnit( AstFrame *this_frame, int *status ) { /* * Name: * TestActiveUnit * Purpose: * Test the ActiveUnit flag for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * int TestActiveUnit( AstFrame *this_frame, int *status ) * Class Membership: * SpecFrame member function (over-rides the astTestActiveUnit protected * method inherited from the Frame class). * Description: * This function test the value of the ActiveUnit flag for a SpecFrame, * which is always "unset". * Parameters: * this * Pointer to the SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * The result of the test (0). */ return 0; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a SpecFrame. * Type: * Private function. * Synopsis: * #include "specframe.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SpecFrame member function (over-rides the astTestAttrib protected * method inherited from the Frame class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a SpecFrame's attributes. * Parameters: * this * Pointer to the SpecFrame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ char *new_attrib; /* Pointer value to new attribute name */ int len; /* Length of attrib string */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* First look for axis attributes defined by the Frame class. Since a SpecFrame has only 1 axis, we allow these attributes to be specified without a trailing "(axis)" string. */ if ( !strcmp( attrib, "direction" ) || !strcmp( attrib, "bottom" ) || !strcmp( attrib, "top" ) || !strcmp( attrib, "format" ) || !strcmp( attrib, "label" ) || !strcmp( attrib, "symbol" ) || !strcmp( attrib, "unit" ) ) { /* Create a new attribute name from the original by appending the string "(1)" and then use the parent TestAttrib method. */ new_attrib = astMalloc( len + 4 ); if( new_attrib ) { memcpy( new_attrib, attrib, len ); memcpy( new_attrib + len, "(1)", 4 ); result = (*parent_testattrib)( this_object, new_attrib, status ); new_attrib = astFree( new_attrib ); } /* AlignStdOfRest. */ /* --------------- */ } else if ( !strcmp( attrib, "alignstdofrest" ) ) { result = astTestAlignStdOfRest( this ); /* GeoLat. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ } else if ( !strcmp( attrib, "geolat" ) ) { result = astTestAttrib( this, "obslat" ); /* GeoLon. */ /* ------- */ } else if ( !strcmp( attrib, "geolon" ) ) { result = astTestAttrib( this, "obslon" ); /* RefDec. */ /* ------- */ } else if ( !strcmp( attrib, "refdec" ) ) { result = astTestRefDec( this ); /* RefRA. */ /* ------ */ } else if ( !strcmp( attrib, "refra" ) ) { result = astTestRefRA( this ); /* RestFreq. */ /* --------- */ } else if ( !strcmp( attrib, "restfreq" ) ) { result = astTestRestFreq( this ); /* SourceVel. */ /* ---------- */ } else if ( !strcmp( attrib, "sourcevel" ) ) { result = astTestSourceVel( this ); /* SourceVRF */ /* --------- */ } else if ( !strcmp( attrib, "sourcevrf" ) ) { result = astTestSourceVRF( this ); /* SourceSys */ /* --------- */ } else if ( !strcmp( attrib, "sourcesys" ) ) { result = astTestSourceSys( this ); /* StdOfRest. */ /* ---------- */ } else if ( !strcmp( attrib, "stdofrest" ) ) { result = astTestStdOfRest( this ); /* SpecOrigin. */ /* --------- */ } else if ( !strcmp( attrib, "specorigin" ) ) { result = astTestSpecOrigin( this ); /* AlignSpecOffset */ /* --------------- */ } else if ( !strcmp( attrib, "alignspecoffset" ) ) { result = astTestAlignSpecOffset( this ); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static double ToUnits( AstSpecFrame *this, const char *oldunit, double oldval, const char *method, int *status ){ /* * * Name: * ToUnits * Purpose: * Convert a supplied spectral value to the default units of the supplied * SpecFrame. * Type: * Private function. * Synopsis: * #include "timeframe.h" * double ToUnits( AstSpecFrame *this, const char *oldunit, double oldval, * const char *method, int *status ) * Class Membership: * SpecFrame member function * Description: * This function converts the supplied value from the supplied units to * the default units associated with the supplied SpecFrame's System. * Parameters: * this * Pointer to the SpecFrame. * oldunit * The units in which "oldval" is supplied. * oldval * The value to be converted. * method * Pointer to a string holding the name of the method to be * included in any error messages. * status * Pointer to the inherited status variable. * Returned Value: * The converted value. */ /* Local Variables: */ AstMapping *map; const char *defunit; double result; /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Get default units associated with the System attribute of the supplied SpecFrame, and find a Mapping from the old units to the default. */ defunit = DefUnit( astGetSystem( this ), method, "SpecFrame", status ); map = astUnitMapper( oldunit, defunit, NULL, NULL ); if( map ) { /* Use the Mapping to convert the supplied value. */ astTran1( map, 1, &oldval, 1, &result ); /* Free resources. */ map = astAnnul( map ); /* Report an error if no conversion is possible. */ } else if( astOK ){ astError( AST__BADUN, "%s(%s): Cannot convert the supplied attribute " "value from units of %s to %s.", status, method, astGetClass( this ), oldunit, defunit ); } /* Return the result */ return result; } static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) { /* * * Name: * ValidateSystem * Purpose: * Validate a value for a Frame's System attribute. * Type: * Protected virtual function. * Synopsis: * #include "specframe.h" * int ValidateSystem( AstFrame *this, AstSystemType system, * const char *method, int *status ) * Class Membership: * SpecFrame member function (over-rides the astValidateSystem method * inherited from the Frame class). * Description: * This function checks the validity of the supplied system value. * If the value is valid, it is returned unchanged. Otherwise, an * error is reported and a value of AST__BADSYSTEM is returned. * Parameters: * this * Pointer to the Frame. * system * The system value to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The validated system value. * Notes: * - A value of AST__BADSYSTEM will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstSystemType result; /* Validated system value */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* If the value is out of bounds, report an error. */ if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) { astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System " "or AlignSystem attribute of a %s.", status, method, astGetClass( this ), (int) system, astGetClass( this ) ); /* Otherwise, return the supplied value. */ } else { result = system; } /* Return the result. */ return result; } static void VerifyAttrs( AstSpecFrame *this, const char *purp, const char *attrs, const char *method, int *status ) { /* * Name: * VerifyAttrs * Purpose: * Verify that usable attribute values are available. * Type: * Private function. * Synopsis: * #include "specframe.h" * void VerifyAttrs( AstSpecFrame *this, const char *purp, * const char *attrs, const char *method, int *status ) * Class Membership: * SpecFrame member function * Description: * This function tests each attribute listed in "attrs". It returns * without action if 1) an explicit value has been set for each attribute * or 2) the UseDefs attribute of the supplied SpecFrame is non-zero. * * If UseDefs is zero (indicating that default values should not be * used for attributes), and any of the named attributes does not have * an explicitly set value, then an error is reported. * Parameters: * this * Pointer to the SpecFrame. * purp * Pointer to a text string containing a message which will be * included in any error report. This shouldindicate the purpose * for which the attribute value is required. * attrs * A string holding a space separated list of attribute names. * method * A string holding the name of the calling method for use in error * messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ const char *a; const char *desc; const char *p; int len; int set; int state; /* Check inherited status */ if( !astOK ) return; /* If the SpecFrame has a non-zero value for its UseDefs attribute, then all attributes are assumed to have usable values, since the defaults will be used if no explicit value has been set. So we only need to do any checks if UseDefs is zero. */ if( !astGetUseDefs( this ) ) { /* Stop compiler warnings about uninitialised variables */ a = NULL; desc = NULL; len = 0; set = 0; /* Loop round the "attrs" string identifying the start and length of each non-blank word in the string. */ state = 0; p = attrs; while( 1 ) { if( state == 0 ) { if( !isspace( *p ) ) { a = p; len = 1; state = 1; } } else { if( isspace( *p ) || !*p ) { /* The end of a word has just been reached. Compare it to each known attribute value. Get a flag indicating if the attribute has a set value, and a string describing the attribute.*/ if( len > 0 ) { if( !strncmp( "ObsLat", a, len ) ) { set = astTestObsLat( this ); desc = "observer's latitude"; } else if( !strncmp( "ObsLon", a, len ) ) { set = astTestObsLon( this ); desc = "observer's longitude"; } else if( !strncmp( "ObsAlt", a, len ) ) { set = astTestObsAlt( this ); desc = "observer's altitude"; } else if( !strncmp( "RefRA", a, len ) ) { set = astTestRefRA( this ); desc = "source RA"; } else if( !strncmp( "RefDec", a, len ) ) { set = astTestRefDec( this ); desc = "source Dec"; } else if( !strncmp( "RestFreq", a, len ) ) { set = astTestRestFreq( this ); desc = "rest frequency"; } else if( !strncmp( "SourceVel", a, len ) ) { set = astTestSourceVel( this ); desc = "source velocity"; } else if( !strncmp( "StdOfRest", a, len ) ) { set = astTestStdOfRest( this ); desc = "spectral standard of rest"; } else if( !strncmp( "Epoch", a, len ) ) { set = astTestEpoch( this ); desc = "epoch of observation"; } else { astError( AST__INTER, "VerifyAttrs(SpecFrame): " "Unknown attribute name \"%.*s\" supplied (AST " "internal programming error).", status, len, a ); } /* If the attribute does not have a set value, report an error. */ if( !set && astOK ) { astError( AST__NOVAL, "%s(%s): Cannot %s.", status, method, astGetClass( this ), purp ); astError( AST__NOVAL, "No value has been set for " "the AST \"%.*s\" attribute (%s).", status, len, a, desc ); } /* Continue the word search algorithm. */ } len = 0; state = 0; } else { len++; } } if( !*(p++) ) break; } } } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* *att++ * Name: * AlignSpecOffset * Purpose: * Align SpecFrames using the offset coordinate system? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which controls how a SpecFrame * behaves when it is used (by c astFindFrame or astConvert) as a template to match another (target) f AST_FINDFRAME or AST_CONVERT) as a template to match another (target) * SpecFrame. It determines whether alignment occurs between the offset * values defined by the current value of the SpecOffset attribute, or * between the corresponding absolute spectral values. * * The default value of zero results in the two SpecFrames being aligned * so that a given absolute spectral value in one is mapped to the same * absolute value in the other. A non-zero value results in the SpecFrames * being aligned so that a given offset value in one is mapped to the same * offset value in the other. * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ astMAKE_CLEAR(SpecFrame,AlignSpecOffset,alignspecoffset,-INT_MAX) astMAKE_GET(SpecFrame,AlignSpecOffset,int,0,( ( this->alignspecoffset != -INT_MAX ) ? this->alignspecoffset : 0 )) astMAKE_SET(SpecFrame,AlignSpecOffset,int,alignspecoffset,( value != 0 )) astMAKE_TEST(SpecFrame,AlignSpecOffset,( this->alignspecoffset != -INT_MAX )) /* *att++ * Name: * AlignStdOfRest * Purpose: * Standard of rest to use when aligning SpecFrames. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute controls how a SpecFrame behaves when it is used (by c astFindFrame or astConvert) as a template to match another (target) f AST_FINDFRAME or AST_CONVERT) as a template to match another (target) * SpecFrame. It identifies the standard of rest in which alignment is * to occur. See the StdOfRest attribute for a desription of the values * which may be assigned to this attribute. The default AlignStdOfRest * value is "Helio" (heliographic). * c When astFindFrame or astConvert is used on two SpecFrames (potentially f When AST_FindFrame or AST_CONVERT is used on two SpecFrames (potentially * describing different spectral coordinate systems), it returns a Mapping * which can be used to transform a position in one SpecFrame into the * corresponding position in the other. The Mapping is made up of the * following steps in the indicated order: * * - Map values from the system used by the target (wavelength, * apparent radial velocity, etc) to the system specified by the * AlignSystem attribute, using the target's rest frequency if necessary. * * - Map these values from the target's standard of rest to the standard of * rest specified by the AlignStdOfRest attribute, using the Epoch, ObsLat, * ObsLon, ObsAlt, RefDec and RefRA attributes of the target to define the * two standards of rest. * * - Map these values from the standard of rest specified by the * AlignStdOfRest attribute, to the template's standard of rest, using the * Epoch, ObsLat, ObsLon, ObsAlt, RefDec and RefRA attributes of the * template to define the two standards of rest. * * - Map these values from the system specified by the AlignSystem * attribute, to the system used by the template, using the template's * rest frequency if necessary. * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The AlignStdOfRest value has a value of AST__BADSOR when not set yielding a default of AST__HLSOR. */ astMAKE_TEST(SpecFrame,AlignStdOfRest,( this->alignstdofrest != AST__BADSOR )) astMAKE_CLEAR(SpecFrame,AlignStdOfRest,alignstdofrest,AST__BADSOR) astMAKE_GET(SpecFrame,AlignStdOfRest,AstStdOfRestType,AST__BADSOR,( ( this->alignstdofrest == AST__BADSOR ) ? AST__HLSOR : this->alignstdofrest ) ) /* Validate the AlignStdOfRest value being set and report an error if necessary. */ astMAKE_SET(SpecFrame,AlignStdOfRest,AstStdOfRestType,alignstdofrest,( ( ( value >= FIRST_SOR ) && ( value <= LAST_SOR ) ) ? value : ( astError( AST__ATTIN, "%s(%s): Bad value (%d) " "given for AlignStdOfRest attribute.", status, "astSetAlignStdOfRest", astGetClass( this ), (int) value ), /* Leave the value unchanged on error. */ this->alignstdofrest ) ) ) /* *att++ * Name: * RefDec * Purpose: * The declination of the reference point * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the FK5 J2000.0 declination of a reference * point on the sky. See the description of attribute RefRA for details. * The default RefDec is "0:0:0". * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The reference declination (FK5 J2000, radians). Clear the RefDec value by setting it to AST__BAD, which results in a default value of zero. Any value is acceptable. */ astMAKE_CLEAR(SpecFrame,RefDec,refdec,AST__BAD) astMAKE_GET(SpecFrame,RefDec,double,0.0,((this->refdec!=AST__BAD)?this->refdec:0.0)) astMAKE_SET(SpecFrame,RefDec,double,refdec,value) astMAKE_TEST(SpecFrame,RefDec,( this->refdec != AST__BAD )) /* *att++ * Name: * RefRA * Purpose: * The right ascension of the reference point * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute, together with the RefDec attribute, specifies the FK5 * J2000.0 coordinates of a reference point on the sky. For 1-dimensional * spectra, this should normally be the position of the source. For * spectral data with spatial coverage (spectral cubes, etc), this should * be close to centre of the spatial coverage. It is used to define the * correction for Doppler shift to be applied when using the c astFindFrame or astConvert f AST_FINDFRAME or AST_CONVERT * method to convert between different standards of rest. * * The SpecFrame class assumes this velocity correction is spatially * invariant. If a single SpecFrame is used (for instance, as a * component of a CmpFrame) to describe spectral values at different * points on the sky, then it is assumes that the doppler shift at any * spatial position is the same as at the reference position. The * maximum velocity error introduced by this assumption is of the order * of V*SIN(FOV), where FOV is the angular field of view, and V is the * relative velocity of the two standards of rest. As an example, when * correcting from the observers rest frame (i.e. the topocentric rest * frame) to the kinematic local standard of rest the maximum value of V * is about 20 km/s, so for 5 arc-minute field of view the maximum velocity * error introduced by the correction will be about 0.03 km/s. As another * example, the maximum error when correcting from the observers rest frame * to the local group is about 5 km/s over a 1 degree field of view. * * The RefRA and RefDec attributes are stored internally in radians, but * are converted to and from a string for access. The format "hh:mm:ss.ss" * is used for RefRA, and "dd:mm:ss.s" is used for RefDec. The methods c astSetRefPos and astGetRefPos may be used to access the values of f AST_SETREFPOS and AST_GETREFPOS may be used to access the value of * these attributes directly as unformatted values in radians. * * The default for RefRA is "0:0:0". * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The reference right ascension (FK5 J2000, radians). Clear the RefRA value by setting it to AST__BAD, which gives a default value of 0.0. Any value is acceptable. */ astMAKE_CLEAR(SpecFrame,RefRA,refra,AST__BAD) astMAKE_GET(SpecFrame,RefRA,double,0.0,((this->refra!=AST__BAD)?this->refra:0.0)) astMAKE_SET(SpecFrame,RefRA,double,refra,value) astMAKE_TEST(SpecFrame,RefRA,( this->refra != AST__BAD )) /* *att++ * Name: * RestFreq * Purpose: * The rest frequency. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute specifies the frequency corresponding to zero * velocity. It is used when converting between between velocity-based * coordinate systems and and other coordinate systems (such as frequency, * wavelength, energy, etc). The default value is 1.0E5 GHz. * * When setting a new value for this attribute, the new value can be * supplied either directly as a frequency, or indirectly as a wavelength * or energy, in which case the supplied value is converted to a frequency * before being stored. The nature of the supplied value is indicated by * appending text to the end of the numerical value indicating the units in * which the value is supplied. If the units are not specified, then the * supplied value is assumed to be a frequency in units of GHz. If the * supplied unit is a unit of frequency, the supplied value is assumed to * be a frequency in the given units. If the supplied unit is a unit of * length, the supplied value is assumed to be a (vacuum) wavelength. If * the supplied unit is a unit of energy, the supplied value is assumed to * be an energy. For instance, the following strings all result in * a rest frequency of around 1.4E14 Hz being used: "1.4E5", "1.4E14 Hz", * "1.4E14 s**-1", "1.4E5 GHz", "2.14E-6 m", "21400 Angstrom", "9.28E-20 J", * "9.28E-13 erg", "0.58 eV", etc. * * When getting the value of this attribute, the returned value is * always a frequency in units of GHz. * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The rest frequency (Hz). Clear the RestFreq value by setting it to AST__BAD, which gives 1.0E14 as the default value. Any value is acceptable. */ astMAKE_CLEAR(SpecFrame,RestFreq,restfreq,AST__BAD) astMAKE_GET(SpecFrame,RestFreq,double,1.0E14,((this->restfreq!=AST__BAD)?this->restfreq:1.0E14)) astMAKE_SET(SpecFrame,RestFreq,double,restfreq,value) astMAKE_TEST(SpecFrame,RestFreq,( this->restfreq != AST__BAD )) /* *att++ * Name: * SourceVel * Purpose: * The source velocity. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute (together with SourceSys, SourceVRF, RefRA and RefDec) * defines the "Source" standard of rest (see attribute StdOfRest). This is * a rest frame which is moving towards the position given by RefRA and * RefDec at a velocity given by SourceVel. A positive value means * the source is moving away from the observer. When a new value is * assigned to this attribute, the supplied value is assumed to refer * to the spectral system specified by the SourceSys attribute. For * instance, the SourceVel value may be supplied as a radio velocity, a * redshift, a beta factor, etc. Similarly, when the current value of * the SourceVel attribute is obtained, the returned value will refer * to the spectral system specified by the SourceSys value. If the * SourceSys value is changed, any value previously stored for the SourceVel * attribute will be changed automatically from the old spectral system * to the new spectral system. * * When setting a value for SourceVel, the value should be supplied in the * rest frame specified by the SourceVRF attribute. Likewise, when getting * the value of SourceVel, it will be returned in the rest frame specified * by the SourceVRF attribute. * * The default SourceVel value is zero. * Applicability: * SpecFrame * All SpecFrames have this attribute. * Notes: * - It is important to set an appropriate value for SourceVRF and * SourceSys before setting a value for SourceVel. If a new value is later * set for SourceVRF or SourceSys, the value stored for SourceVel will * simultaneously be changed to the new standard of rest or spectral * system. *att-- */ /* The source velocity (velocities are stored internally in m/s). Clear it by setting it to AST__BAD, which returns a default value of zero. Any value is acceptable. */ astMAKE_CLEAR(SpecFrame,SourceVel,sourcevel,AST__BAD) astMAKE_SET(SpecFrame,SourceVel,double,sourcevel,value) astMAKE_TEST(SpecFrame,SourceVel,( this->sourcevel != AST__BAD )) astMAKE_GET(SpecFrame,SourceVel,double,0.0,((this->sourcevel!=AST__BAD)?this->sourcevel:0.0)) /* *att++ * Name: * SourceVRF * Purpose: * Rest frame in which the source velocity is stored. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute identifies the rest frame in which the source * velocity or redshift is stored (the source velocity or redshift is * accessed using attribute SourceVel). When setting a new value for the * SourceVel attribute, the source velocity or redshift should be supplied * in the rest frame indicated by this attribute. Likewise, when getting * the value of the SourceVel attribute, the velocity or redshift will be * returned in this rest frame. * * If the value of SourceVRF is changed, the value stored for SourceVel * will be converted from the old to the new rest frame. * * The values which can be supplied are the same as for the StdOfRest * attribute (except that SourceVRF cannot be set to "Source"). The * default value is "Helio". * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The SourceVRF value has a value of AST__BADSOR when not set yielding a default of AST__HLSOR. */ astMAKE_TEST(SpecFrame,SourceVRF,( this->sourcevrf != AST__BADSOR )) astMAKE_GET(SpecFrame,SourceVRF,AstStdOfRestType,AST__BADSOR,( ( this->sourcevrf == AST__BADSOR ) ? AST__HLSOR : this->sourcevrf ) ) /* When clearing SourceVRF, convert the SourceVel value to heliocentric (but only if set)*/ astMAKE_CLEAR(SpecFrame,SourceVRF,sourcevrf,((astTestSourceVel( this )? astSetSourceVel( this, ConvertSourceVel( this, AST__HLSOR, astGetSourceSys( this ), status ) ),NULL:NULL),AST__BADSOR)) /* Validate the SourceVRF value being set and report an error if necessary. If OK, convert the stored SourceVel value into the new rest frame (but only if set)*/ astMAKE_SET(SpecFrame,SourceVRF,AstStdOfRestType,sourcevrf,( ( ( value >= FIRST_SOR ) && ( value <= LAST_SOR ) && value != AST__SCSOR ) ? (astTestSourceVel( this )? astSetSourceVel( this, ConvertSourceVel( this, value, astGetSourceSys( this ), status )),NULL:NULL), value: ( astError( AST__ATTIN, "%s(%s): Bad value (%d) " "given for SourceVRF attribute.", status, "astSetSourceVRF", astGetClass( this ), (int) value ), /* Leave the value unchanged on error. */ this->sourcevrf ) ) ) /* *att++ * Name: * SourceSys * Purpose: * Spectral system in which the source velocity is stored. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute identifies the spectral system in which the * SourceVel attribute value (the source velocity) is supplied and * returned. It can be one of the following: * * - "VRAD" or "VRADIO": Radio velocity (km/s) * - "VOPT" or "VOPTICAL": Optical velocity (km/s) * - "ZOPT" or "REDSHIFT": Redshift (dimensionless) * - "BETA": Beta factor (dimensionless) * - "VELO" or "VREL": Apparent radial ("relativistic") velocity (km/s) * * When setting a new value for the SourceVel attribute, the source * velocity should be supplied in the spectral system indicated * by this attribute. Likewise, when getting the value of the SourceVel * attribute, the velocity will be returned in this spectral system. * * If the value of SourceSys is changed, the value stored for SourceVel * will be converted from the old to the new spectral systems. * * The default value is "VELO" (apparent radial velocity). * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The SourceSys value has a value of AST__BADSYS when not set yielding a default of AST__VREL. */ astMAKE_TEST(SpecFrame,SourceSys,( this->sourcesys != AST__BADSYSTEM )) astMAKE_GET(SpecFrame,SourceSys,AstSystemType,AST__BADSYSTEM,( ( this->sourcesys == AST__BADSYSTEM ) ? AST__VREL : this->sourcesys ) ) /* When clearing SourceSys, convert the SourceVel value to relativistic velocity (but only if set) */ astMAKE_CLEAR(SpecFrame,SourceSys,sourcesys,((astTestSourceVel( this )? astSetSourceVel( this, ConvertSourceVel( this, astGetSourceVRF( this ), AST__VREL, status ) ),NULL:NULL),AST__BADSYSTEM)) /* Validate the SourceSys value being set and report an error if necessary. If OK, convert the stored SourceVel value into the new rest frame (but only if set)*/ astMAKE_SET(SpecFrame,SourceSys,AstSystemType,sourcesys,( ( ( value == AST__VREL ) || ( value == AST__BETA ) || ( value == AST__VRADIO ) || ( value == AST__REDSHIFT ) || ( value == AST__VOPTICAL ) ) ? (astTestSourceVel( this )? astSetSourceVel( this, ConvertSourceVel( this, astGetSourceVRF( this ), value, status )),NULL:NULL), value: ( astError( AST__ATTIN, "%s(%s): Bad value (%d) " "given for SourceSys attribute.", status, "astSetSourceSys", astGetClass( this ), (int) value ), /* Leave the value unchanged on error. */ this->sourcesys ) ) ) /* *att++ * Name: * StdOfRest * Purpose: * Standard of rest. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute identifies the standard of rest to which the spectral * axis values of a SpecFrame refer, and may take any of the values * listed in the "Standards of Rest" section (below). * * The default StdOfRest value is "Helio". * Applicability: * SpecFrame * All SpecFrames have this attribute. * Standards of Rest: * The SpecFrame class supports the following StdOfRest values (all are * case-insensitive): * * - "Topocentric", "Topocent" or "Topo": The observers rest-frame (assumed * to be on the surface of the earth). Spectra recorded in this standard of * rest suffer a Doppler shift which varies over the course of a day * because of the rotation of the observer around the axis of the earth. * This standard of rest must be qualified using the ObsLat, ObsLon, * ObsAlt, Epoch, RefRA and RefDec attributes. * * - "Geocentric", "Geocentr" or "Geo": The rest-frame of the earth centre. * Spectra recorded in this standard of rest suffer a Doppler shift which * varies over the course of a year because of the rotation of the earth * around the Sun. This standard of rest must be qualified using the Epoch, * RefRA and RefDec attributes. * * - "Barycentric", "Barycent" or "Bary": The rest-frame of the solar-system * barycentre. Spectra recorded in this standard of rest suffer a Doppler * shift which depends both on the velocity of the Sun through the Local * Standard of Rest, and on the movement of the planets through the solar * system. This standard of rest must be qualified using the Epoch, RefRA * and RefDec attributes. * * - "Heliocentric", "Heliocen" or "Helio": The rest-frame of the Sun. * Spectra recorded in this standard of rest suffer a Doppler shift which * depends on the velocity of the Sun through the Local Standard of Rest. * This standard of rest must be qualified using the RefRA and RefDec * attributes. * * - "LSRK", "LSR": The rest-frame of the kinematical Local Standard of * Rest. Spectra recorded in this standard of rest suffer a Doppler shift * which depends on the velocity of the kinematical Local Standard of Rest * through the galaxy. This standard of rest must be qualified using the * RefRA and RefDec attributes. * * - "LSRD": The rest-frame of the dynamical Local Standard of Rest. Spectra * recorded in this standard of rest suffer a Doppler shift which depends * on the velocity of the dynamical Local Standard of Rest through the * galaxy. This standard of rest must be qualified using the RefRA and * RefDec attributes. * * - "Galactic", "Galactoc" or "Gal": The rest-frame of the galactic centre. * Spectra recorded in this standard of rest suffer a Doppler shift which * depends on the velocity of the galactic centre through the local group. * This standard of rest must be qualified using the RefRA and RefDec * attributes. * * - "Local_group", "Localgrp" or "LG": The rest-frame of the local group. * This standard of rest must be qualified using the RefRA and RefDec * attributes. * * - "Source", or "src": The rest-frame of the source. This standard of * rest must be qualified using the RefRA, RefDec and SourceVel attributes. * * Where more than one alternative System value is shown above, the * first of these will be returned when an enquiry is made. *att-- */ /* The StdOfRest value has a value of AST__BADSOR when not set yielding a default of AST__HLSOR. */ astMAKE_TEST(SpecFrame,StdOfRest,( this->stdofrest != AST__BADSOR )) astMAKE_GET(SpecFrame,StdOfRest,AstStdOfRestType,AST__BADSOR,( ( this->stdofrest == AST__BADSOR ) ? AST__HLSOR : this->stdofrest ) ) /* *att++ * Name: * SpecOrigin * Purpose: * The zero point for SpecFrame axis values * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This specifies the origin from which all spectral values are measured. * The default value (zero) results in the SpecFrame describing * absolute spectral values in the system given by the System attribute * (e.g. frequency, velocity, etc). If a SpecFrame is to be used to * describe offset from some origin, the SpecOrigin attribute * should be set to hold the required origin value. The SpecOrigin value * stored inside the SpecFrame structure is modified whenever SpecFrame * attribute values are changed so that it refers to the original spectral * position. * * When setting a new value for this attribute, the supplied value is assumed * to be in the system, units and standard of rest described by the SpecFrame. * Likewise, when getting the value of this attribute, the value is returned * in the system, units and standard of rest described by the SpecFrame. If * any of these attributes are changed, then any previously stored SpecOrigin * value will also be changed so that refers to the new system, units or * standard of rest. * Applicability: * SpecFrame * All SpecFrames have this attribute. *att-- */ /* The spec origin, stored internally in the default units associated with the current System value. Clear the SpecOrigin value by setting it to AST__BAD, which gives 0.0 as the default value. Any value is acceptable. */ astMAKE_CLEAR(SpecFrame,SpecOrigin,specorigin,AST__BAD) astMAKE_GET(SpecFrame,SpecOrigin,double,0.0,((this->specorigin!=AST__BAD)?this->specorigin:0.0)) astMAKE_SET(SpecFrame,SpecOrigin,double,specorigin,value) astMAKE_TEST(SpecFrame,SpecOrigin,( this->specorigin != AST__BAD )) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for SpecFrame objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for SpecFrame objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstSpecFrame *in; /* Pointer to input SpecFrame */ AstSpecFrame *out; /* Pointer to output SpecFrame */ char *usedunit; /* Pointer to an element of usedunits array */ int i; /* Loop count */ int nused; /* Size of "usedunits" array */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output SpecFrames. */ in = (AstSpecFrame *) objin; out = (AstSpecFrame *) objout; /* Nullify the pointers stored in the output object since these will currently be pointing at the input data (since the output is a simple byte-for-byte copy of the input). Otherwise, the input data could be freed by accidient if the output object is deleted due to an error occuring in this function. */ out->usedunits = NULL; /* Store the last used units in the output SpecMap. */ if( in && in->usedunits ) { nused = in->nuunits; out->usedunits = astMalloc( nused*sizeof( char * ) ); if( out->usedunits ) { for( i = 0; i < nused; i++ ) { usedunit = in->usedunits[ i ]; if( usedunit ) { out->usedunits[ i ] = astStore( NULL, usedunit, strlen( usedunit ) + 1 ); } else { out->usedunits[ i ] = NULL; } } } } /* If an error has occurred, free the output resources. */ if( !astOK ) Delete( (AstObject *) out, status ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for SpecFrame objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for SpecFrame objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstSpecFrame *this; int i; /* Release the memory referred to in the SpecFrame structure. */ this = (AstSpecFrame *) obj; if( this && this->usedunits ) { for( i = 0; i < this->nuunits; i++ ) { this->usedunits[ i ] = astFree( this->usedunits[ i ] ); } this->usedunits = astFree( this->usedunits ); } } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SpecFrame objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the SpecFrame class to an output Channel. * Parameters: * this * Pointer to the SpecFrame whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFrame *this; /* Pointer to the SpecFrame structure */ AstStdOfRestType sor; /* StdOfRest attribute value */ AstSystemType sys; /* Spectral system value */ char buff[ 20 ]; /* Buffer for item name */ char comm[ 50 ]; /* Buffer for comment */ const char *sval; /* Pointer to string value */ double dval; /* Double value */ int i; /* Loop count */ int ival; /* int value */ int j; /* Loop count */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFrame structure. */ this = (AstSpecFrame *) this_object; /* Write out values representing the instance variables for the SpecFrame class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* StdOfRest. */ /* ---------- */ set = TestStdOfRest( this, status ); sor = set ? GetStdOfRest( this, status ) : astGetStdOfRest( this ); /* If set, convert explicitly to a string for the external representation. */ sval = ""; if ( set ) { if ( astOK ) { sval = StdOfRestString( sor, status ); /* Report an error if the StdOfRest value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "%s(%s): Corrupt %s contains invalid standard of rest " "identification code (%d).", status, "astWrite", astGetClass( channel ), astGetClass( this ), (int) sor ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "stdofrest" ); } /* Write out the value. */ astWriteString( channel, "SoR", set, 1, sval, "Standard of rest" ); /* AlignStdOfRest. */ /* --------------- */ set = TestAlignStdOfRest( this, status ); sor = set ? GetAlignStdOfRest( this, status ) : astGetAlignStdOfRest( this ); /* If set, convert explicitly to a string for the external representation. */ if ( set ) { if ( astOK ) { sval = StdOfRestString( sor, status ); /* Report an error if the StdOfRest value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "%s(%s): Corrupt %s contains invalid alignment standard " "of rest identification code (%d).", status, "astWrite", astGetClass( channel ), astGetClass( this ), (int) sor ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "alignstdofrest" ); } /* Write out the value. */ astWriteString( channel, "AlSoR", set, 0, sval, "Alignment standard of rest" ); /* RefRA. */ /* ------ */ set = TestRefRA( this, status ); dval = set ? GetRefRA( this, status ) : astGetRefRA( this ); astWriteDouble( channel, "RefRA", set, 0, dval, "Reference RA (rads, FK5 J2000)" ); /* RefDec. */ /* ------- */ set = TestRefDec( this, status ); dval = set ? GetRefDec( this, status ) : astGetRefDec( this ); astWriteDouble( channel, "RefDec", set, 0, dval, "Reference Dec (rads, FK5 J2000)" ); /* RestFreq. */ /* --------- */ set = TestRestFreq( this, status ); dval = set ? GetRestFreq( this, status ) : astGetRestFreq( this ); astWriteDouble( channel, "RstFrq", set, 0, dval, "Rest frequency (Hz)" ); /* SourceVel. */ /* ---------- */ set = TestSourceVel( this, status ); dval = set ? GetSourceVel( this, status ) : astGetSourceVel( this ); astWriteDouble( channel, "SrcVel", set, 0, dval, "Source velocity (m/s)" ); /* SourceVRF. */ /* ---------- */ set = TestSourceVRF( this, status ); sor = set ? GetSourceVRF( this, status ) : astGetSourceVRF( this ); /* If set, convert explicitly to a string for the external representation. */ if ( set ) { if ( astOK ) { sval = StdOfRestString( sor, status ); /* Report an error if the value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "%s(%s): Corrupt %s contains invalid source velocity " "rest frame identification code (%d).", status, "astWrite", astGetClass( channel ), astGetClass( this ), (int) sor ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "sourcevrf" ); } /* Write out the value. */ astWriteString( channel, "SrcVRF", set, 0, sval, "Source velocity rest frame" ); /* SourceSys. */ /* ---------- */ set = TestSourceSys( this, status ); sys = set ? GetSourceSys( this, status ) : astGetSourceSys( this ); /* If set, convert explicitly to a string for the external representation. */ if ( set ) { if ( astOK ) { sval = SystemString( (AstFrame *) this, sys, status ); /* Report an error if the value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "%s(%s): Corrupt %s contains invalid source velocity " "spectral system identification code (%d).", status, "astWrite", astGetClass( channel ), astGetClass( this ), (int) sys ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "sourcesys" ); } /* Write out the value. */ astWriteString( channel, "SrcSys", set, 0, sval, "Source velocity spectral system" ); /* AlignSpecOffset. */ /* ---------------- */ set = TestAlignSpecOffset( this, status ); ival = set ? GetAlignSpecOffset( this, status ) : astGetAlignSpecOffset( this ); astWriteInt( channel, "AlSpOf", set, 0, ival, ival ? "Align in offset coords" : "Align in system coords" ); /* UsedUnits */ /* --------- */ if( this->usedunits ) { for( i = 0; i < this->nuunits; i++ ) { if( this->usedunits[ i ] ) { sprintf( buff, "U%s", astSystemString( this, (AstSystemType) i )); for( j = 2; j < strlen( buff ); j++ ) buff[ j ] = tolower( buff[ j ] ); sprintf( comm, "Preferred units for %s", SystemLabel( (AstSystemType) i, status ) ); astWriteString( channel, buff, 1, 0, this->usedunits[ i ], comm ); } } } /* SpecOrigin. */ /* ----------- */ set = TestSpecOrigin( this, status ); dval = set ? GetSpecOrigin( this, status ) : astGetSpecOrigin( this ); if( dval != AST__BAD ) { astWriteDouble( channel, "SpOrg", set, 0, dval, "Spec offset" ); } } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASpecFrame and astCheckSpecFrame functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SpecFrame,Frame) astMAKE_CHECK(SpecFrame) AstSpecFrame *astSpecFrame_( const char *options, int *status, ...) { /* *+ * Name: * astSpecFrame * Purpose: * Create a SpecFrame. * Type: * Protected function. * Synopsis: * #include "specframe.h" * AstSpecFrame *astSpecFrame( const char *options, int *status, ... ) * Class Membership: * SpecFrame constructor. * Description: * This function creates a new SpecFrame and optionally initialises its * attributes. * Parameters: * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new SpecFrame. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new SpecFrame. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- * Implementation Notes: * - This function implements the basic SpecFrame constructor which * is available via the protected interface to the SpecFrame class. * A public interface is provided by the astSpecFrameId_ function. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMapping *um; /* Mapping from default to actual units */ AstSpecFrame *new; /* Pointer to new SpecFrame */ AstSystemType s; /* System */ const char *u; /* Units string */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SpecFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSpecFrame( NULL, sizeof( AstSpecFrame ), !class_init, &class_vtab, "SpecFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SpecFrame's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* Check the Units are appropriate for the System. */ u = astGetUnit( new, 0 ); s = astGetSystem( new ); um = astUnitMapper( DefUnit( s, "astSpecFrame", "SpecFrame", status ), u, NULL, NULL ); if( um ) { um = astAnnul( um ); } else { astError( AST__BADUN, "astSpecFrame: Inappropriate units (%s) " "specified for a %s axis.", status, u, SystemLabel( s, status ) ); } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new SpecFrame. */ return new; } AstSpecFrame *astInitSpecFrame_( void *mem, size_t size, int init, AstSpecFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSpecFrame * Purpose: * Initialise a SpecFrame. * Type: * Protected function. * Synopsis: * #include "specframe.h" * AstSpecFrame *astInitSpecFrame( void *mem, size_t size, int init, * AstFrameVtab *vtab, const char *name ) * Class Membership: * SpecFrame initialiser. * Description: * This function is provided for use by class implementations to * initialise a new SpecFrame object. It allocates memory (if * necessary) to accommodate the SpecFrame plus any additional data * associated with the derived class. It then initialises a * SpecFrame structure at the start of this memory. If the "init" * flag is set, it also initialises the contents of a virtual function * table for a SpecFrame at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SpecFrame is to be * created. This must be of sufficient size to accommodate the * SpecFrame data (sizeof(SpecFrame)) plus any data used by * the derived class. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SpecFrame (plus derived * class data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also stored * in the SpecFrame structure, so a valid value must be supplied * even if not required for allocating memory. * init * A logical flag indicating if the SpecFrame's virtual function * table is to be initialised. If this value is non-zero, the * virtual function table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be * associated with the new SpecFrame. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object belongs * (it is this pointer value that will subsequently be returned by * the astGetClass method). * Returned Value: * A pointer to the new SpecFrame. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstSpecFrame *new; /* Pointer to the new SpecFrame */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSpecFrameVtab( vtab, name ); /* Initialise a 1D Frame structure (the parent class) as the first component within the SpecFrame structure, allocating memory if necessary. */ new = (AstSpecFrame *) astInitFrame( mem, size, 0, (AstFrameVtab *) vtab, name, 1 ); if ( astOK ) { /* Initialise the SpecFrame data. */ /* ----------------------------- */ /* Initialise all attributes to their "undefined" values. */ new->alignstdofrest = AST__BADSOR; new->refdec = AST__BAD; new->refra = AST__BAD; new->restfreq = AST__BAD; new->sourcevel = AST__BAD; new->sourcevrf = AST__BADSOR; new->sourcesys = AST__BADSYSTEM; new->stdofrest = AST__BADSOR; new->nuunits = 0; new->usedunits = NULL; new->specorigin = AST__BAD; new->alignspecoffset = -INT_MAX; /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstSpecFrame *astLoadSpecFrame_( void *mem, size_t size, AstSpecFrameVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSpecFrame * Purpose: * Load a SpecFrame. * Type: * Protected function. * Synopsis: * #include "specframe.h" * AstSpecFrame *astLoadSpecFrame( void *mem, size_t size, * AstSpecFrameVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * SpecFrame loader. * Description: * This function is provided to load a new SpecFrame using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SpecFrame structure in this memory, using data read from the * input Channel. * Parameters: * mem * A pointer to the memory into which the SpecFrame is to be * loaded. This must be of sufficient size to accommodate the * SpecFrame data (sizeof(SpecFrame)) plus any data used by * derived classes. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SpecFrame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SpecFrame structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSpecFrame) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SpecFrame. If this is NULL, a pointer * to the (static) virtual function table for the SpecFrame class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SpecFrame" is used instead. * Returned Value: * A pointer to the new SpecFrame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSpecFrame *new; /* Pointer to the new SpecFrame */ char buff[ 20 ]; /* Buffer for item name */ char *sval; /* Pointer to string value */ double obslat; /* Value for ObsLat attribute */ double obslon; /* Get a pointer to the thread specific global data structure. */ /* Value for ObsLon attribute */ int i; /* Loop count */ int j; /* Loop count */ int nc; /* String length */ int sys; /* System value */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SpecFrame. In this case the SpecFrame belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSpecFrame ); vtab = &class_vtab; name = "SpecFrame"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSpecFrameVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SpecFrame. */ new = astLoadFrame( mem, size, (AstFrameVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SpecFrame" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* StdOfRest. */ /* ---------- */ /* Set the default and read the external representation as a string. */ new->stdofrest = AST__BADSOR; sval = astReadString( channel, "sor", NULL ); /* If a value was read, convert from a string to a StdOfRest code. */ if ( sval ) { if ( astOK ) { new->stdofrest = StdOfRestCode( sval, status ); /* Report an error if the value wasn't recognised. */ if ( new->stdofrest == AST__BADSOR ) { astError( AST__ATTIN, "astRead(%s): Invalid standard of rest description " "\"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* AlignStdOfRest. */ /* --------------- */ /* Set the default and read the external representation as a string. */ new->alignstdofrest = AST__BADSOR; sval = astReadString( channel, "alsor", NULL ); /* If a value was read, convert from a string to a StdOfRest code. */ if ( sval ) { if ( astOK ) { new->alignstdofrest = StdOfRestCode( sval, status ); /* Report an error if the value wasn't recognised. */ if ( new->alignstdofrest == AST__BADSOR ) { astError( AST__ATTIN, "astRead(%s): Invalid alignment standard of rest " "description \"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* GeoLat. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had a GeoLat attribute (now ObsLat is used instead). */ if( !astTestObsLat( new ) ) { obslat = astReadDouble( channel, "geolat", AST__BAD ); if ( obslat != AST__BAD ) astSetObsLat( new, obslat ); } /* GeoLon. */ /* ------- */ /* Retained for backward compatibility with older versions of AST in which SpecFrame had a GeoLon attribute (now ObsLon is used instead). */ if( !astTestObsLon( new ) ) { obslon = astReadDouble( channel, "geolon", AST__BAD ); if ( obslon != AST__BAD ) astSetObsLon( new, obslon ); } /* RefRA. */ /* ------ */ new->refra = astReadDouble( channel, "refra", AST__BAD ); if ( TestRefRA( new, status ) ) SetRefRA( new, new->refra, status ); /* RefDec. */ /* ------- */ new->refdec = astReadDouble( channel, "refdec", AST__BAD ); if ( TestRefDec( new, status ) ) SetRefDec( new, new->refdec, status ); /* RestFreq. */ /* --------- */ new->restfreq = astReadDouble( channel, "rstfrq", AST__BAD ); if ( TestRestFreq( new, status ) ) SetRestFreq( new, new->restfreq, status ); /* AlignSpecOffset */ /* --------------- */ new->alignspecoffset = astReadInt( channel, "alspof", -INT_MAX ); if ( TestAlignSpecOffset( new, status ) ) SetAlignSpecOffset( new, new->alignspecoffset, status ); /* SourceVel. */ /* ---------- */ new->sourcevel = astReadDouble( channel, "srcvel", AST__BAD ); if ( TestSourceVel( new, status ) ) SetSourceVel( new, new->sourcevel, status ); /* SourceVRF */ /* --------- */ /* Set the default and read the external representation as a string. */ new->sourcevrf = AST__BADSOR; sval = astReadString( channel, "srcvrf", NULL ); /* If a value was read, convert from a string to a StdOfRest code. */ if ( sval ) { if ( astOK ) { new->sourcevrf = StdOfRestCode( sval, status ); /* Report an error if the value wasn't recognised. */ if ( new->sourcevrf == AST__BADSOR ) { astError( AST__ATTIN, "astRead(%s): Invalid source velocity rest frame " "description \"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* SourceSys */ /* --------- */ /* Set the default and read the external representation as a string. */ new->sourcesys = AST__BADSYSTEM; sval = astReadString( channel, "srcsys", NULL ); /* If a value was read, convert from a string to a System code. */ if ( sval ) { if ( astOK ) { new->sourcesys = SystemCode( (AstFrame *) new, sval, status ); /* Report an error if the value wasn't recognised. */ if ( new->sourcesys == AST__BADSYSTEM ) { astError( AST__ATTIN, "astRead(%s): Invalid source velocity spectral system " "description \"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* UsedUnits */ /* --------- */ new->nuunits = 0; new->usedunits = NULL; for( sys = FIRST_SYSTEM; sys <= LAST_SYSTEM; sys++ ) { nc = sprintf( buff, "u%s", astSystemString( new, (AstSystemType) sys )); for( j = 0; j < nc; j++ ) buff[ j ] = tolower( buff[ j ] ); sval = astReadString( channel, buff, NULL ); if( sval ) { if( (int) sys >= new->nuunits ) { new->usedunits = astGrow( new->usedunits, sys + 1, sizeof(char *) ); if( astOK ) { for( i = new->nuunits; i < sys + 1; i++ ) new->usedunits[ i ] = NULL; new->nuunits = sys + 1; } } else { new->usedunits[ sys ] = astFree( new->usedunits[ sys ] ); } if( astOK ) { new->usedunits[ sys ] = astStore( new->usedunits[ sys ], sval, strlen( sval ) + 1 ); } sval = astFree( sval); } } /* SpecOrigin. */ /* --------- */ new->specorigin = astReadDouble( channel, "sporg", AST__BAD ); if ( TestSpecOrigin( new, status ) ) SetSpecOrigin( new, new->specorigin, status ); /* If an error occurred, clean up by deleting the new SpecFrame. */ if ( !astOK ) new = astDelete( new ); } /* Return the new SpecFrame pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astGetRefPos_( AstSpecFrame *this, AstSkyFrame *frm, double *lon, double *lat, int *status ){ if ( !astOK ) return; (**astMEMBER(this,SpecFrame,GetRefPos))(this,frm,lon,lat, status ); } void astSetRefPos_( AstSpecFrame *this, AstSkyFrame *frm, double lon, double lat, int *status ){ if ( !astOK ) return; (**astMEMBER(this,SpecFrame,SetRefPos))(this,frm,lon,lat, status ); } void astSetStdOfRest_( AstSpecFrame *this, AstStdOfRestType value, int *status ){ if ( !astOK ) return; (**astMEMBER(this,SpecFrame,SetStdOfRest))(this,value, status ); } void astClearStdOfRest_( AstSpecFrame *this, int *status ){ if ( !astOK ) return; (**astMEMBER(this,SpecFrame,ClearStdOfRest))(this, status ); } /* Special public interface functions. */ /* =================================== */ /* These provide the public interface to certain special functions whose public interface cannot be handled using macros (such as astINVOKE) alone. In general, they are named after the corresponding protected version of the function, but with "Id" appended to the name. */ /* Public Interface Function Prototypes. */ /* ------------------------------------- */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSpecFrame *astSpecFrameId_( const char *, ... ); /* Special interface function implementations. */ /* ------------------------------------------- */ AstSpecFrame *astSpecFrameId_( const char *options, ... ) { /* *++ * Name: c astSpecFrame f AST_SPECFRAME * Purpose: * Create a SpecFrame. * Type: * Public function. * Synopsis: c #include "specframe.h" c AstSpecFrame *astSpecFrame( const char *options, ... ) f RESULT = AST_SPECFRAME( OPTIONS, STATUS ) * Class Membership: * SpecFrame constructor. * Description: * This function creates a new SpecFrame and optionally initialises * its attributes. * * A SpecFrame is a specialised form of one-dimensional Frame which * represents various coordinate systems used to describe positions within * an electro-magnetic spectrum. The particular coordinate system to be * used is specified by setting the SpecFrame's System attribute (the * default is wavelength) qualified, as necessary, by other attributes * such as the rest frequency, the standard of rest, the epoch of * observation, etc (see the description of the System attribute for * details). * * By setting a value for thr SpecOrigin attribute, a SpecFrame can be made * to represent offsets from a given spectral position, rather than absolute * Parameters: c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SpecFrame. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SpecFrame. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSpecFrame() f AST_SPECFRAME = INTEGER * A pointer to the new SpecFrame. * Examples: c frame = astSpecFrame( "" ); f FRAME = AST_SPECFRAME( ' ', STATUS ) * Creates a SpecFrame to describe the default wavelength spectral * coordinate system. The RestFreq attribute (rest frequency) is * unspecified, so it will not be possible to align this SpecFrame * with another SpecFrame on the basis of a velocity-based system. The * standard of rest is also unspecified. This means that alignment * will be possible with other SpecFrames, but no correction will be * made for Doppler shift caused by change of rest frame during the * alignment. c frame = astSpecFrame( "System=VELO, RestFreq=1.0E15, StdOfRest=LSRK" ); f FRAME = AST_SPECFRAME( 'System=VELO, RestFreq=1.0E15, StdOfRest=LSRK', STATUS ) * Creates a SpecFrame describing a apparent radial velocity ("VELO") axis * with rest frequency 1.0E15 Hz (about 3000 Angstroms), measured * in the kinematic Local Standard of Rest ("LSRK"). Since the * source position has not been specified (using attributes RefRA and * RefDec), it will only be possible to align this SpecFrame with * other SpecFrames which are also measured in the LSRK standard of * rest. * Notes: * - When conversion between two SpecFrames is requested (as when c supplying SpecFrames to astConvert), f supplying SpecFrames AST_CONVERT), * account will be taken of the nature of the spectral coordinate systems * they represent, together with any qualifying rest frequency, standard * of rest, epoch values, etc. The AlignSystem and AlignStdOfRest * attributes will also be taken into account. The results will therefore * fully reflect the relationship between positions measured in the two * systems. In addition, any difference in the Unit attributes of the two * systems will also be taken into account. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astSpecFrame constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astSpecFrame_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - The variable argument list also prevents this function from * invoking astSpecFrame_ directly, so it must be a * re-implementation of it in all respects, except for the final * conversion of the result to an ID value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMapping *um; /* Mapping from default to actual units */ AstSpecFrame *new; /* Pointer to new SpecFrame */ AstSystemType s; /* System */ const char *u; /* Units string */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ astGET_GLOBALS(NULL); /* Get a pointer to the thread specific global data structure. */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SpecFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSpecFrame( NULL, sizeof( AstSpecFrame ), !class_init, &class_vtab, "SpecFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SpecFrame's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* Check the Units are appropriate for the System. */ u = astGetUnit( new, 0 ); s = astGetSystem( new ); um = astUnitMapper( DefUnit( s, "astSpecFrame", "SpecFrame", status ), u, NULL, NULL ); if( um ) { um = astAnnul( um ); } else { astError( AST__BADUN, "astSpecFrame: Inappropriate units (%s) " "specified for a %s axis.", status, u, SystemLabel( s, status ) ); } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new SpecFrame. */ return astMakeId( new ); } ./ast-7.3.3/compile0000755000175000017500000000717312245363456012536 0ustar olesoles#! /bin/sh # Wrapper for compilers which do not understand `-c -o'. scriptversion=2005-05-14.22 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand `-c -o'. Remove `-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file `INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; esac ofile= cfile= eat= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as `compile cc -o foo foo.c'. # So we strip `-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no `-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # `.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` # Create the lock directory. # Note: use `[/.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ./ast-7.3.3/nullregion.h0000644000175000017500000001534612262533650013502 0ustar olesoles#if !defined( NULLREGION_INCLUDED ) /* Include this file only once */ #define NULLREGION_INCLUDED /* *+ * Name: * nullregion.h * Type: * C include file. * Purpose: * Define the interface to the NullRegion class. * Invocation: * #include "nullregion.h" * Description: * This include file defines the interface to the NullRegion class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The NullRegion class implement a Region with no boundaries. * Inheritance: * The NullRegion class inherits from the Region class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 11-OCT-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "region.h" /* Coordinate regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* NullRegion structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstNullRegion { /* Attributes inherited from the parent class. */ AstRegion region; /* Parent class structure */ } AstNullRegion; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstNullRegionVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstRegionVtab region_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ } AstNullRegionVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstNullRegionGlobals { AstNullRegionVtab Class_Vtab; int Class_Init; } AstNullRegionGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitNullRegionGlobals_( AstNullRegionGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(NullRegion) /* Check class membership */ astPROTO_ISA(NullRegion) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstNullRegion *astNullRegion_( void *, AstRegion *, const char *, int *, ...); #else AstNullRegion *astNullRegionId_( void *, AstRegion *, const char *, ... )__attribute__((format(printf,3,4))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstNullRegion *astInitNullRegion_( void *, size_t, int, AstNullRegionVtab *, const char *, AstFrame *, AstRegion *, int * ); /* Vtab initialiser. */ void astInitNullRegionVtab_( AstNullRegionVtab *, const char *, int * ); /* Loader. */ AstNullRegion *astLoadNullRegion_( void *, size_t, AstNullRegionVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckNullRegion(this) astINVOKE_CHECK(NullRegion,this,0) #define astVerifyNullRegion(this) astINVOKE_CHECK(NullRegion,this,1) /* Test class membership. */ #define astIsANullRegion(this) astINVOKE_ISA(NullRegion,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astNullRegion astINVOKE(F,astNullRegion_) #else #define astNullRegion astINVOKE(F,astNullRegionId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitNullRegion(mem,size,init,vtab,name,frame,unc) \ astINVOKE(O,astInitNullRegion_(mem,size,init,vtab,name,frame,unc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitNullRegionVtab(vtab,name) astINVOKE(V,astInitNullRegionVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadNullRegion(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadNullRegion_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckNullRegion to validate NullRegion pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #endif #endif ./ast-7.3.3/LICENCE0000644000175000017500000004313612262533650012136 0ustar olesoles GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ./ast-7.3.3/unitmap.h0000644000175000017500000002046512262533650012777 0ustar olesoles#if !defined( UNITMAP_INCLUDED ) /* Include this file only once */ #define UNITMAP_INCLUDED /* *+ * Name: * unitmap.h * Type: * C include file. * Purpose: * Define the interface to the UnitMap class. * Invocation: * #include "unitmap.h" * Description: * This include file defines the interface to the UnitMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The UnitMap class implements Mappings that perform an identity * (unit) coordinate transformation, simply by copying each * coordinate value from input to output (and similarly for the * inverse transformation). UnitMaps are therefore of little use * for converting coordinates, but they serve a useful role as * "null" Mappings in cases where a Mapping is needed (e.g. to * pass to a function), but no coordinate transformation is wanted. * Inheritance: * The UnitMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * None. * * Protected: * astMapMerge * Simplify a sequence of Mappings containing a UnitMap. * astTransform * Transform a set of points. * New Methods Defined: * Public: * None. * * Protected: * None. * Other Class Functions: * Public: * astIsAUnitMap * Test class membership. * astUnitMap * Create a UnitMap. * * Protected: * astCheckUnitMap * Validate class membership. * astInitUnitMap * Initialise a UnitMap. * astInitUnitMapVtab * Initialise the virtual function table for the UnitMap class. * astLoadUnitMap * Load a UnitMap. * Macros: * None. * Type Definitions: * Public: * AstUnitMap * UnitMap object type. * * Protected: * AstUnitMapVtab * UnitMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 7-FEB-1996 (RFWS): * Original version. * 13-DEC-1996 (RFWS): * Over-ride the astMapMerge method. * 8-JAN-2003 (DSB): * Added protected astInitUnitMapVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* UnitMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstUnitMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ /* None. */ } AstUnitMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstUnitMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ /* None. */ } AstUnitMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstUnitMapGlobals { AstUnitMapVtab Class_Vtab; int Class_Init; } AstUnitMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitUnitMapGlobals_( AstUnitMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(UnitMap) /* Check class membership */ astPROTO_ISA(UnitMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstUnitMap *astUnitMap_( int, const char *, int *, ...); #else AstUnitMap *astUnitMapId_( int, const char *, ... )__attribute__((format(printf,2,3))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstUnitMap *astInitUnitMap_( void *, size_t, int, AstUnitMapVtab *, const char *, int, int * ); /* Vtab initialiser. */ void astInitUnitMapVtab_( AstUnitMapVtab *, const char *, int * ); /* Loader. */ AstUnitMap *astLoadUnitMap_( void *, size_t, AstUnitMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ /* None. */ /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckUnitMap(this) astINVOKE_CHECK(UnitMap,this,0) #define astVerifyUnitMap(this) astINVOKE_CHECK(UnitMap,this,1) /* Test class membership. */ #define astIsAUnitMap(this) astINVOKE_ISA(UnitMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astUnitMap astINVOKE(F,astUnitMap_) #else #define astUnitMap astINVOKE(F,astUnitMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitUnitMap(mem,size,init,vtab,name,ncoord) \ astINVOKE(O,astInitUnitMap_(mem,size,init,vtab,name,ncoord,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitUnitMapVtab(vtab,name) astINVOKE(V,astInitUnitMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadUnitMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadUnitMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckUnitMap to validate UnitMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ /* None. */ #endif ./ast-7.3.3/memory.c0000644000175000017500000047410112262533650012625 0ustar olesoles/* * Name: * memory.c * Purpose: * Implement memory allocation/deallocation functions. * Description: * This file implements the Memory module which is used for * allocating and freeing memory in the AST library. For a * description of the module and its interface, see the .h file of * the same name. * Note, it is assumed that malloc, free and realloc are thread-safe. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009-2010 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: D.S. Berry (Starlink) * History: * 2-JAN-1996 (RFWS): * Original version. * 26-JAN-1996 (RFWS): * Removed trailing underscores from static functions and * changed to use new error function interfaces. * 20-JUN-1996 (RFWS): * Added astString. * 15-JUL-1996 (RFWS): * Make IsDynamic execute under error conditions to avoid memory * leaks in such situations. * 11-SEP-1996 (RFWS): * Added astStringArray (original written by DSB). * 18-MAR-1998 (RFWS): * Added notes about these functions being available for writing * foreign language and graphics interfaces, etc. * 29-JAN-2002 (DSB): * Added astChrLen and astSscanf. * 15-FEB-2002 (DSB): * Removed use of non-ANSI vsscanf from astSscanf. * 15-NOV-2002 (DSB): * Moved ChrMatch from SkyFrame (etc) to here. Included stdio.h and * ctype.h. * 10-FEB-2003 (DSB): * Added facilities for detecting and tracing memory leaks. These * are only included if AST is compiled with the -DDEBUG flag. * 3-MAR-2004 (DSB): * Modified astSscanf to avoid use of uninitialised values * corresponding to "%n" fields in the format string. * 26-JAN-2004 (DSB): * Modified astRealloc to clarify the nature of the returned pointer * (which is not a "Memory *"). Also correct issuing and deissuing * of pointers in DEBUG code within astRealloc. * 16-FEB-2006 (DSB): * Convert Magic from a function to a macro for extra speed. * 21-FEB-2006 (DSB): * Convert IsDynamic from a function to a macro for extra speed. * 23-FEB-2006 (DSB): * Added the caching system for allocated but unused memory blocks, * controlled by AST tuning parameter MemoryCaching. * 2-MAR-2006 (DSB): * Added astFlushMemory, and renamed the memory debugging functions. * These are now conditionally compiled if the MEM_DEBUG macros is * defined (set by configuring AST with the --with-memdebug option). * Also modified them to take into account MemoryCaching. * 24-MAY-2006 (DSB): * Ensure that pointers to memory returned by this module are all * aligned on 8 byte boundaries. This fixes problems with ualigned * memory access that could cause bus errors on Solaris. * 26-MAY-2006 (DSB): * Cast (void *) pointers to (char *) before doing arithmetic on * them (changes supplied by Micah Johnson). * 4-DEC-2006 (DSB): * Fix bug in astMalloc that caused a non-null pointer to be * returned on error. * 4-JAN-2007 (DSB): * Move definition of astCLASS macro so that it comes before the * inclusion of the AST include files (which test for astCLASS). * 27-JUN-2007 (DSB): * Added astIsDynamic. * 24-OCT-2007 (DSB): * Zero the size of memory blocks stored in the Cache so that an * error will be reported if an attempt is made to free a memory * block that has already been freed. * 25-OCT-2007 (DSB): * Added astRemoveLeadingBlanks. * 28-FEB-2008 (DSB): * Added astChrSub. * 17-MAR-2008 (DSB): * Added "{nnn}" quantifier to astChrSub. * 27-MAR-2008 (DSB): * Added astChrSplitRE, and re-structured regexp functions. * 18-NOV-2008 (DSB): * In astFlushMemory, do not release permanent memory blocks as * they may still be needed. * 9-FEB-2009 (DSB): * Added astChr2Double. * 25-JUN-2009 (DSB): * Fix handling of escape characters in astSplitC. * 19-MAY-2010 (DSB): * - Added astStringCase. * - Changed access from protected to public for commonly used * functions. * 26-MAY-2010 (DSB): * Added astCalloc. * 18-AUG-2010 (DSB): * Added astMemoryStats * 19-AUG-2010 (DSB): * Added astMemoryWarning * 8-OCT-2010 (DSB): * Modify memory allocation to use "calloc" directly, rather than * using "malloc+memset". * 12-APR-2011 (DSB): * Fix regular expression problem where a ".*" template field failed to * match a null string if it occurred before a closing parenthesis at * the end of the template. * 26-MAY-2011 (DSB): * - Changed API for astCalloc to match RTL (i.e. remove "init"). * - Changed astChr2Double to check for strigs like "2.", which * some sscanfs fail to read as a floating point value. * 27-MAY-2011 (DSB): * Added astFreeDouble to free a dynamically allocated array of * pointers to other dynamically allocated arrays. * 21-JUN-2011 (DSB): * Added astCheckMemory - an alternative to astFlushMemory that does * not free any memory. * 21-NOV-2011 (DSB): * Correct matchend value returned by astChrSplitRE. * 6-JAN-2014 (DSB): * Optimise access to cache to avoid valgrind warnings. */ /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* Module Macros. */ /* ============== */ /* Define the astCLASS macro (even although this is not a class implementation) to obtain access to the protected error handling functions. */ #define astCLASS memory /* The maximum number of fields within a format string allowed by astSscanf. */ #define VMAXFLD 20 /* The maximum number of nested astBeginPM/astEndPM contexts. */ #define PM_STACK_MAXSIZE 20 /* Select the appropriate memory management functions. These will be the system's malloc, calloc, free and realloc unless AST was configured with the "--with-starmem" option, in which case they will be the starmem malloc, calloc, free and realloc. */ #ifdef HAVE_STAR_MEM_H # include # define MALLOC starMalloc # define CALLOC starCalloc # define FREE starFree # define REALLOC starRealloc #else # define MALLOC malloc # define CALLOC calloc # define FREE free # define REALLOC realloc #endif #ifdef MEM_DEBUG #define ISSUED "issued" #define FREED "freed" #endif /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "error.h" /* Error reporting facilities */ #include "globals.h" /* Thread-specific global data */ #include "memory.h" /* Interface to this module */ #include "pointset.h" /* For AST__BAD */ #ifdef MEM_DEBUG #include "object.h" /* For astMakePointer */ #endif /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #ifdef THREAD_SAFE #include #endif #ifdef MEM_PROFILE #include #endif /* Function Macros. */ /* =============== */ /* These are defined as macros rather than functions to avoid the overhead of a function call since they are called extremely frequently. */ /* * Name: * IS_DYNAMIC * Purpose: * Test whether a memory region has been dynamically allocated. * Type: * Private macro * Synopsis: * #include "memory.h" * IS_DYNAMIC( ptr, dynamic ) * Description: * This macro takes a pointer to a region of memory and tests if * the memory has previously been dynamically allocated using other * functions from this module. It does this by checking for the * presence of a "magic" number in the header which precedes the * allocated memory. If the magic number is not present (or the * pointer is invalid for any other reason), an error is reported * and the global error status is set. * * The result of the test is written to the variable specified by "res". * Parameters: * ptr * Pointer to the start (as known to the external user) of the * dynamically allocated memory. * dynamic * Name of an "int" variable to recieve the result of the test. * If the memory was allocated dynamically, a value of 1 is * stored in this variable. Otherwise, zero is stored and an error * results. * Notes: * - A NULL pointer value produces an error report from this * function, although other functions may wish to regard a NULL * pointer as valid. * - This function attempts to execute even if the global error * status is set, although no further error report will be made if * the memory is not dynamically allocated under these * circumstances. * - The test performed by this function is not 100% secure as the * "magic" value could occur by accident (although this is * unlikely). It is mainly intended to provide security against * programming errors, including accidental corruption of the * memory header and attempts to allocate the same region of memory * more than once. */ #define IS_DYNAMIC(ptr,dynamic) \ \ /* Initialise. */ \ dynamic = 0; \ \ /* Check that a NULL pointer has not been supplied and report an error \ if it has (but not if the global status is already set). */ \ if ( !ptr ) { \ if ( astOK ) { \ astError( AST__PTRIN, "Invalid NULL pointer (address %p).", status, ptr ); \ } \ \ /* If OK, derive a pointer to the memory header that precedes the \ allocated region of memory. */ \ } else { \ Memory *isdynmem; /* Pointer to memory header */ \ isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); \ \ /* Check if the "magic number" in the header is valid and report an \ error if it is not (but not if the global status is already \ set). */ \ if ( isdynmem->magic != MAGIC( isdynmem, isdynmem->size ) ) { \ if ( astOK ) { \ astError( AST__PTRIN, \ "Invalid pointer or corrupted memory at address %p.", status, \ ptr ); \ } \ \ /* Note if the magic number is OK. */ \ } else { \ dynamic = 1; \ } \ } /* * Name: * MAGIC * Purpose: * Generate a "magic number". * Type: * Private macro. * Synopsis: * #include "memory.h" * unsigned long MAGIC( void *ptr, size_t size ) * Description: * This macro generates a "magic number" which is a function of * a memory address and an object size. This number may be stored * in a region of dynamically allocated memory to allow it to be * recognised as dynamically allocated by other routines, and also * to provide security against memory leaks, etc. * Parameters: * ptr * The memory pointer. * size * The object size. * Returned Value: * The function returns the magic number. * Notes: * This function does not perform error checking. */ /* Form the bit-wise exclusive OR between the memory address and the object size, then add 1 and invert the bits. Return the result as an unsigned long integer. */ #define MAGIC(ptr,size) \ ( ~( ( ( (unsigned long) ptr ) ^ ( (unsigned long) size ) ) + \ ( (unsigned long) 1 ) ) ) /* A macro that returns the size of the a Memory structure padded to a multiple of 8 bytes. */ #define SIZEOF_MEMORY \ ( ( sizeof_memory != 0 ) ? sizeof_memory : SizeOfMemory( status ) ) /* Type Definitions. */ /* ================= */ #ifdef MEM_PROFILE /* Structure used to record the time spent between matching calls to astStartTimer and astStopTimer. */ typedef struct AstTimer { int id; /* Unique integer identifier for timer */ clock_t e0; /* Absolute elapsed time at timer start */ clock_t u0; /* Absolute user time at timer start */ clock_t s0; /* Absolute system time at timer start */ clock_t et; /* Cumulative elapsed time within timer */ clock_t ut; /* Cumulative user time within timer */ clock_t st; /* Cumulative system time within timer */ int nentry; /* Number of entries into the timer */ const char *name; /* An identifying label for the timer */ const char *file; /* Name of source file where timer was started */ int line; /* Source file line no. where timer was started */ struct AstTimer *parent; /* The parent enclosing timer */ int nchild; /* Number of child timers */ struct AstTimer **children;/* Timers that count time within this timer */ } AstTimer; #endif /* Module Variables. */ /* ================= */ /* Extra stuff for profiling (can only be used in single threaded environments). */ #ifdef MEM_PROFILE static AstTimer *Current_Timer = NULL; static int Enable_Timers = 0; static int Timer_Count = 0; #endif /* Extra stuff for debugging of memory management (tracking of leaks etc). */ #ifdef MEM_DEBUG /* The identifier for the memory block which is to be tracked. */ static int Watched_ID = -1; /* The next integer to use to identify an active memory block pointer. */ static int Next_ID = -1; /* Indicates if future memory allocations are permanent (i.e. will not usually be freed explicitly by AST). */ static int Perm_Mem = 0; /* A "first in, last out" stack of Perm_Mem values used by nested astBeginPM/astEndPM contexts. */ static int PM_Stack[ PM_STACK_MAXSIZE ]; /* The number of values currently in the PM_Stack array. */ static int PM_Stack_Size = 0; /* A pointer to a double linked list holding pointers to currently active memory blocks (i.e. memory blocks for which a pointer has been issued but not yet freed). This does not include the memory blocks in the Cache array (these are not considered to be active). */ static Memory *Active_List = NULL; /* Should a new ID be issued each time a cached memory block is returned by astMalloc? Otherwise, the same ID value is used throughout the life of a memory block. */ static int Keep_ID = 0; /* Suppress all memory use reports except for issuing and freeing? */ static int Quiet_Use = 0; /* Report the ID of every cached block when the cache is emptied? */ static int List_Cache = 0; /* Memory allocation at which to issue a warning. */ static size_t Warn_Usage = 0; /* Current memory allocated by AST. */ static size_t Current_Usage = 0; /* Peak memory allocated by AST. */ static size_t Peak_Usage = 0; #ifdef THREAD_SAFE static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_DEBUG_MUTEX pthread_mutex_lock( &mutex2 ); #define UNLOCK_DEBUG_MUTEX pthread_mutex_unlock( &mutex2 ); #else #define LOCK_DEBUG_MUTEX #define UNLOCK_DEBUG_MUTEX #endif #endif /* Define macros for accessing all items of thread-safe global data used by this module. */ #ifdef THREAD_SAFE #define sizeof_memory astGLOBAL(Memory,Sizeof_Memory) #define cache astGLOBAL(Memory,Cache) #define cache_init astGLOBAL(Memory,Cache_Init) #define use_cache astGLOBAL(Memory,Use_Cache) /* Define the initial values for the global data for this module. */ #define GLOBAL_inits \ globals->Sizeof_Memory = 0; \ globals->Cache_Init = 0; \ globals->Use_Cache = 0; \ /* Create the global initialisation function. */ astMAKE_INITGLOBALS(Memory) /* If thread safety is not needed, declare globals at static variables. */ /* -------------------------------------------------------------------- */ #else /* The size of a Memory header structure, padded to a multiple of 8 bytes. This value is initialised by the SizeOfMemory function, and should be accessed using the SIZEOF_MEMORY macro. */ static size_t sizeof_memory = 0; /* A cache of allocated but currently unused memory block. This cache is maintained in order to avoid the overhead of continual calls to malloc to allocate small blocks of memory. The vast majority of memory blocks allocated by AST are under 200 bytes in size. Each element in this array stores a pointer to the header for a free (i.e. allocated but currently unused) memory block. The size of the memory block (not including the Memory header) will equal the index at which the pointer is stored within "cache". Each free memory block contains (in its Memory header) a pointer to the header for another free memory block of the same size (or a NULL pointer if there are no other free memory blocks of the same size). */ static Memory *cache[ MXCSIZE + 1 ]; /* Has the "cache" array been initialised? */ static int cache_init = 0; /* Should the cache be used? */ static int use_cache = 0; #endif /* Prototypes for Private Functions. */ /* ================================= */ static size_t SizeOfMemory( int * ); static char *CheckTempStart( const char *, const char *, const char *, char *, int *, int *, int *, int *, int *, int *, int *, int * ); static char *ChrMatcher( const char *, const char *, const char *, const char *, const char *[], int, int, int, char ***, int *, const char **, int * ); static char *ChrSuber( const char *, const char *, const char *[], int, int, char ***, int *, const char **, int * ); #ifdef MEM_DEBUG static void Issue( Memory *, int * ); static void DeIssue( Memory *, int * ); #endif #ifdef MEM_PROFILE static AstTimer *ReportTimer( AstTimer *, int, AstTimer **, int *, int * ); static int CompareTimers( const void *, const void * ); static int CompareTimers2( const void *, const void * ); #endif /* Function implementations. */ /* ========================= */ char *astAppendString_( char *str1, int *nc, const char *str2, int *status ) { /* *++ * Name: * astAppendString * Purpose: * Append a string to another string which grows dynamically. * Type: * Public function. * Synopsis: * #include "memory.h" * char *astAppendString( char *str1, int *nc, const char *str2 ) * Description: * This function appends one string to another dynamically * allocated string, extending the dynamic string as necessary to * accommodate the new characters (plus the final null). * Parameters: * str1 * Pointer to the null-terminated dynamic string, whose memory * has been allocated using an AST memory allocation function. * If no space has yet been allocated for this string, a NULL * pointer may be given and fresh space will be allocated by this * function. * nc * Pointer to an integer containing the number of characters in * the dynamic string (excluding the final null). This is used * to save repeated searching of this string to determine its * length and it defines the point where the new string will be * appended. Its value is updated by this function to include * the extra characters appended. * * If "str1" is NULL, the initial value supplied for "*nc" will * be ignored and zero will be used. * str2 * Pointer to a constant null-terminated string, a copy of which * is to be appended to "str1". * Returned Value: * astAppendString() * A possibly new pointer to the dynamic string with the new string * appended (its location in memory may have to change if it has to * be extended, in which case the original memory is automatically * freed by this function). When the string is no longer required, * its memory should be freed using astFree. * Notes: * - If this function is invoked with the global error status set * or if it should fail for any reason, then the returned pointer * will be equal to "str1" and the dynamic string contents will be * unchanged. *-- */ /* Local Variables: */ char *result; /* Pointer value to return */ int len; /* Length of new string */ /* Initialise. */ result = str1; /* If the first string pointer is NULL, also initialise the character count to zero. */ if ( !str1 ) *nc = 0; /* Check the global error status. */ if ( !astOK || !str2 ) return result; /* Calculate the total string length once the two strings have been concatenated. */ len = *nc + (int) strlen( str2 ); /* Extend the first (dynamic) string to the required length, including a final null. Save the resulting pointer, which will be returned. */ result = astGrow( str1, len + 1, sizeof( char ) ); /* If OK, append the second string and update the total character count. */ if ( astOK ) { (void) strcpy( result + *nc, str2 ); *nc = len; } /* Return the result pointer. */ return result; } void *astCalloc_( size_t nmemb, size_t size, int *status ) { /* *++ * Name: * astCalloc * Purpose: * Allocate and initialise memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astCalloc( size_t nmemb, size_t size ) * Description: * This function allocates memory in a similar manner to the * standard C "calloc" function, but with improved security * (against memory leaks, etc.) and with error reporting. It also * fills the allocated memory with zeros. * * Like astMalloc, it allows zero-sized memory allocation * (without error), resulting in a NULL returned pointer value. * Parameters: * nmemb * The number of array elements for which memory is to be allocated. * size * The size of each array element, in bytes. * Returned Value: * astCalloc() * If successful, the function returns a pointer to the start of * the allocated memory region. If the size allocated is zero, this * will be a NULL pointer. * Notes: * - A pointer value of NULL is returned if this function is * invoked with the global error status set or if it fails for any * reason. *-- */ /* Local Variables: */ void *result; /* Returned pointer */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Attempt to allocate and initialise the required amount of memory. */ result = astMallocInit( nmemb*size ); /* If the above call failed due to failure of the system malloc function, issue an extra error giving the number of elements and element size. */ if( astStatus == AST__NOMEM ) { astError( AST__NOMEM, "(%lu elements, each of %lu bytes).", status, (unsigned long) nmemb, (unsigned long) size ); } /* Return the result. */ return result; } static char *CheckTempStart( const char *template, const char *temp, const char *pattern, char *allowed, int *ntemp, int *allow, int *min_nc, int *max_nc, int *start_sub, int *end_sub, int *greedy, int *status ){ /* * Name: * CheckTempStart * Purpose: * Examine the leading field in an astChrSub template. * Type: * Private function. * Synopsis: * char *CheckTempStart( const char *template, const char *temp, * const char *pattern, * char *allowed, int *ntemp, int *allow, * int *min_nc, int *max_nc, int *start_sub, * int *end_sub, int *greedy, int *status ) * Description: * This function returns inforation about the leading field in a * template string supplied to astChrSub. * Parameters: * template * The full template string (used for error messages). * temp * Pointer to the next character to read from the template string. * pattern * Pointer to the user supplied pattern string (only used in error * messages). * allowed * Pointer to a buffer in which to store a string of characters * that the leading temeplate field will match. A NULL pointer may * be supplied in which case new memory will be allocated. The * supplied memory is expanded as necessary, and a pointer to it is * returned as the function value. * ntemp * Address of an int in which to return the number of characters * consumed from the start of "temp". * allow * Address of an int in which to return a flag which is non-zero if * the returned string contains characters that are allowed in the * test field, or zero if the returned string contains characters that * are disallowed in the test field. * min_nc * Address of an int in which to return the minimum number of * test characters that must belong to the returned set of * allowed characters. * max_nc * Address of an int in which to return the maximum number of * test characters that must belong to the returned set of * allowed characters. * start_sub * Address of an int in which to return a flag which is non-zero if * the leading template field indicates the start of a field to be * substituted. In this case the supplied "allowed" pointer is * returned without change as the function value, "Min_nc" is * returned as zero, and max_nc is returned as zero. * end_sub * Address of an int in which to return a flag which is non-zero if * the leading template field indicates the end of a field to be * substituted. In this case the supplied "allowed" pointer is * returned without change as the function value, "Min_nc" is * returned as zero, and limit is returned as zero. * greedy * Address of an int in which to return a flag which is non-zero if * the template starts with a greedy quantifier. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a (possibly newly allocated) memory area holding a * string of characters that the leading temeplate field will match. * This string should be released using astFree when no longer needed. * If a NULL pointyer is returned, then all characters are allowed * (or disallowed if "*allow" is zero). * Notes: * - The returned value is also stored in the module variable * sizeof_memory. */ /* Local Variables: */ char *result; const char *start; const char *end; /* Initialise. */ result = allowed; *ntemp = 0; *allow = 1; *min_nc = 0; *max_nc = 0; *start_sub = 0; *end_sub = 0; *greedy = 1; /* Check global status */ if( !astOK ) return result; /* If the next character is an opening parenthesis, this marks the start of a substitution field. */ if( *temp == '(' ) { *start_sub = 1; *ntemp = 1; /* If the next character is an closing parenthesis, this marks the end of a substitution field. */ } else if( *temp == ')' ) { *end_sub = 1; *ntemp = 1; /* If the next character is an opening bracket, this marks the start of a field of allowed or disallowed characters. */ } else { if( *temp == '[' ) { /* If the first character in the brackets is "^" this is a field of disallowed characters, otherwise they are allowed. */ if( temp[ 1 ] == '^' ) { *allow = 0; start = temp + 2; } else { start = temp + 1; } /* Get a pointer to the closing bracket. */ end = strchr( temp, ']' ); /* Copy the intervening string into the returned string. */ if( end ) { result = astStore( allowed, start, end - start + 1 ); if( result ) result[ end - start ] = 0; /* Report an error if no closing bracket was found. */ } else { astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "missing ']'.", status, pattern ); } /* Indicate how many template characters have been used. */ *ntemp = end - temp + 1; /* A single dot matches any character. */ } else if( *temp == '.' ) { result = astFree( result ); *ntemp = 1; /* Now deal with escape sequences. */ } else if( *temp == '\\' ) { /* Digits... */ if( temp[ 1 ] == 'd' || temp[ 1 ] == 'D' ) { result = astStore( allowed, "0123456789", 11 ); result[ 10 ] = 0; if( temp[ 1 ] == 'D' ) *allow = 0; /* White space... */ } else if( temp[ 1 ] == 's' || temp[ 1 ] == 'S' ) { result = astStore( allowed, " \n\r", 5 ); result[ 4 ] = 0; if( temp[ 1 ] == 'S' ) *allow = 0; /* Word characters... */ } else if( temp[ 1 ] == 'w' || temp[ 1 ] == 'W' ) { result = astStore( allowed, "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", 64 ); result[ 63 ] = 0; if( temp[ 1 ] == 'W' ) *allow = 0; /* Any other character is treated literally. */ } else { result = astStore( allowed, temp + 1, 2 ); result[ 1 ] = 0; } /* Set number of template characters consumed. */ *ntemp = 2; /* Everything else must be matched literally. */ } else { if( *temp == '*' || *temp == '?' || *temp == '+' ){ astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "field starts with '%c'.", status, pattern, temp[ *ntemp ] ); } else { result = astStore( allowed, temp, 2 ); result[ 1 ] = 0; *ntemp = 1; } } /* Now see if there is any quantifier. */ if( temp[ *ntemp ] == '*' ) { *min_nc = 0; *max_nc = INT_MAX; (*ntemp)++; if( temp[ *ntemp ] == '?' ){ *greedy = 0; (*ntemp)++; } } else if( temp[ *ntemp ] == '+' ) { *min_nc = 1; *max_nc = INT_MAX; (*ntemp)++; if( temp[ *ntemp ] == '?' ){ *greedy = 0; (*ntemp)++; } } else if( temp[ *ntemp ] == '?' ) { *min_nc = 0; *max_nc = 1; (*ntemp)++; } else { /* See if the remaining string starts with "{nnn}". If so, extract the "nnn" and use it as the minimum and maximum field length. */ if( temp[ *ntemp ] == '{' ) { start = temp + *ntemp + 1; while( isdigit( (int) *start ) ) { *min_nc = 10*( *min_nc ) + (int )( ( *start ) - '0' ); start++; } if( *start == '}' ) { *max_nc = *min_nc; *ntemp = start - temp + 1; } else { start = NULL; } } else { start = NULL; } /* If the remaining string does not start with "{nnn}", use a minimum and maximum field length of 1. */ if( !start ) { *min_nc = 1; *max_nc = 1; } } } /* Return the string of allowed characters. */ return result; } double astChr2Double_( const char *str, int *status ) { /* *++ * Name: * astChr2Double * Purpose: * read a double value from a string. * Type: * Public function. * Synopsis: * #include "memory.h" * double astChr2Double( const char *str ) * Description: * This function reads a double from the supplied null-terminated string, * ignoring leading and trailing white space. AST__BAD is ereturned * without error if the string is not a numerical value. * Parameters: * str * Pointer to the string. * Returned Value: * astChr2Double() * The double value, or AST__BAD. * Notes: * - A value of AST__BAD is returned if this function is invoked with * the global error status set or if it should fail for any reason. *-- */ /* Local Variables: */ double result; /* The returned value */ int ival; /* Integer value read from string */ int len; /* Length of supplied string */ int nc; /* Number of characters read from the string */ /* Check the global error status and supplied pointer. */ if ( !astOK || !str ) return AST__BAD; /* Save the length of the supplied string. */ len = strlen( str ); /* Use scanf to read the floating point value. This fails if either 1) the string does not begin with a numerical value (in which case astSscanf returns zero), or 2) there are non-white characters following the numerical value (in which case "nc" - the number of characters read from the string - is less than the length of the string). */ if ( nc = 0, ( 1 != astSscanf( str, " %lg %n", &result, &nc ) ) || ( nc < len ) ) { result = AST__BAD; } /* If the above failed, try again allowing the string to be an integer followed by a dot (e.g. "1."). Some implementations of sscanf do not consider this to be a floating point value. */ if( 1 || result == AST__BAD ) { if ( nc = 0, ( 1 == astSscanf( str, " %d. %n", &ival, &nc ) ) && ( nc >= len ) ) { result = ival; } } /* Return the result. */ return result; } void astChrCase_( const char *in, char *out, int upper, int blen, int *status ) { /* *++ * Name: * astChrCase * Purpose: * Convert a string to upper or lower case. * Type: * Public function. * Synopsis: * #include "memory.h" * void astChrCase( const char *in, char *out, int upper, int blen, int *status ) * Description: * This function converts a supplied string to upper or lower case, * storing the result in a supplied buffer. The astStringCase function * is similar, but stores the result in a dynamically allocated buffer. * Parameters: * in * Pointer to the null terminated string to be converted. If this * is NULL, the supplied contents of the "out" string are used as * the input string. * out * Pointer to the buffer to receive the converted string. The * length of this buffer is given by "blen". If NULL is supplied * for "in", then the supplied contents of "out" are converted and * written back into "out" over-writing the supplied contents. * upper * If non-zero, the string is converted to upper case. Otherwise it * is converted to lower case. * blen * The length of the output buffer. Ignored if "in" is NULL. No * more than "blen - 1" characters will be copied from "in" to * "out", and a terminating null character will then be added. *-- */ /* Local Variables: */ const char *pin; char *pout; int i; /* Check the global error status. */ if ( !astOK ) return; /* The simple case of over-writing the supplied string. */ if( ! in ) { pout = out - 1; while( *(++pout) ) *pout = toupper( (int) *pout ); /* If a separate output buffer has been supplied... */ } else { /* Initialise pointers to the input and output buffers. */ pin = in; pout = out; /* Copy the string character by character, converting the case in the process. Start counting from 1, not 0, in order to ensure that we are left with room for a terminating null. */ for( i = 1; i < blen && *pin; i++ ) { *(pout++) = toupper( (int) *(pin++) ); } /* Terminate the returned string. */ *pout = 0; } } int astChrMatch_( const char *str1, const char *str2, int *status ) { /* *++ * Name: * astChrMatch * Purpose: * Case insensitive string comparison. * Type: * Public function. * Synopsis: * #include "memory.h" * int astChrMatch( const char *str1, const char *str2 ) * Description: * This function compares two null terminated strings for equality, * discounting differences in case and any trailing white space in either * string. * Parameters: * str1 * Pointer to the first string. * str2 * Pointer to the second string. * Returned Value: * astChrMatch() * Non-zero if the two strings match, otherwise zero. * Notes: * - A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. *-- */ /* Local Variables: */ int match; /* Strings match? */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ match = 1; /* Loop to compare characters in the two strings until a mis-match occurs or we reach the end of the longer string. */ while ( match && ( *str1 || *str2 ) ) { /* Two characters match if (a) we are at the end of one string and the other string contains white space or (b) both strings contain the same character when converted to lower case. */ match = ( !*str1 && isspace( *str2 ) ) || ( !*str2 && isspace( *str1 ) ) || ( tolower( *str1 ) == tolower( *str2 ) ); /* Step through each string a character at a time until its end is reached. */ if ( *str1 ) str1++; if ( *str2 ) str2++; } /* Return the result. */ return match; } int astChrMatchN_( const char *str1, const char *str2, size_t n, int *status ) { /* *++ * Name: * astChrMatchN * Purpose: * Case insensitive string comparison of at most N characters * Type: * Public function. * Synopsis: * #include "memory.h" * int astChrMatchN( const char *str1, const char *str2, size_t n ) * Description: * This function compares two null terminated strings for equality, * discounting differences in case and any trailing white space in either * string. No more than "n" characters are compared. * Parameters: * str1 * Pointer to the first string. * str2 * Pointer to the second string. * n * Maximum number of characters to compare. * Returned Value: * astChrMatchN() * Non-zero if the two strings match, otherwise zero. * Notes: * - A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. *-- */ /* Local Variables: */ int match; /* Strings match? */ int nc; /* Number of characters compared so far */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ match = 1; /* So far we have compared zero characters */ nc = 0; /* Loop to compare characters in the two strings until a mis-match occurs or we reach the end of the longer string, or we reach the specified maximum number of characters. */ while ( match && ( *str1 || *str2 ) && nc++ < n ) { /* Two characters match if (a) we are at the end of one string and the other string contains white space or (b) both strings contain the same character when converted to lower case. */ match = ( !*str1 && isspace( *str2 ) ) || ( !*str2 && isspace( *str1 ) ) || ( tolower( *str1 ) == tolower( *str2 ) ); /* Step through each string a character at a time until its end is reached. */ if ( *str1 ) str1++; if ( *str2 ) str2++; } /* Return the result. */ return match; } char **astChrSplit_( const char *str, int *n, int *status ) { /* *++ * Name: * astChrSplit * Purpose: * Extract words from a supplied string. * Type: * Public function. * Synopsis: * #include "memory.h" * char **astChrSplit_( const char *str, int *n ) * Description: * This function extracts all space-separated words form the supplied * string and returns them in an array of dynamically allocated strings. * Parameters: * str * Pointer to the string to be split. * n * Address of an int in which to return the number of words returned. * Returned Value: * astChrSplit() * A pointer to a dynamically allocated array containing "*n" elements. * Each element is a pointer to a dynamically allocated character * string containing a word extracted from the supplied string. Each * of these words will have no leading or trailing white space. * Notes: * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason, or if * the supplied string contains no words. *-- */ /* Local Variables: */ char **result; char *w; const char *p; const char *ws; int first; int state; int wl; /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise. */ result = NULL; ws = NULL; *n = 0; /* State 0 is "looking for the next non-white character which marks the start of the next word". State 1 is "looking for the next white character which marks the end of the current word". */ state = 0; /* Loop through all characters in the supplied string, including the terminating null. */ p = str - 1; first = 1; while( *(p++) || first ) { first = 0; /* If this is the terminating null or a space, and we are currently looking for the end of a word, allocate memory for the new word, copy the text in, terminate it, extend the returned array by one element, and store the new word in it. */ if( !*p || isspace( *p ) ) { if( state == 1 ) { wl = p - ws; w = astMalloc( wl + 1 ); if( w ) { strncpy( w, ws, wl ); w[ wl ] = 0; result = astGrow( result, *n + 1, sizeof( char * ) ); if( result ) result[ (*n)++ ] = w; } state = 0; } /* If this is non-blank character, and we are currently looking for the start of a word, note the address of the start of the word, and indicate that we are now looking for the end of a word. */ } else { if( state == 0 ) { state = 1; ws = p; } } } /* Return the result. */ return result; } char **astChrSplitC_( const char *str, char c, int *n, int *status ) { /* *++ * Name: * astChrSplitC * Purpose: * Split a string using a specified character delimiter. * Type: * Public function. * Synopsis: * #include "memory.h" * char **astChrSplitC( const char *str, char c, int *n ) * Description: * This function extracts all sub-strings separated by a given * character from the supplied string and returns them in an array * of dynamically allocated strings. The delimiter character itself * is not included in the returned strings. * * Delimiter characters that are preceded by "\" are not used as * delimiters but are included in the returned word instead (without * the "\"). * Parameters: * str * Pointer to the string to be split. * c * The delimiter character. * n * Address of an int in which to return the number of words returned. * Returned Value: * astChrSplitC() * A pointer to a dynamically allocated array containing "*n" elements. * Each element is a pointer to a dynamically allocated character * string containing a word extracted from the supplied string. * Notes: * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason, or if * the supplied string contains no words. *-- */ /* Local Variables: */ char **result; char *word; const char *p; int escaped; int wordlen; /* Initialise returned values. */ *n = 0; result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* More initialisations. */ word = NULL; wordlen = 0; escaped = 0; /* Loop through all characters in the supplied string, including the terminating null. */ p = str; while( *p ) { /* Is this a delimiter character? */ if( *p == c ) { /* If it is escaped, it does not mark the end of a word. Put it into the current output buffer instead, overwriting the escape character that preceded it. */ if( escaped ) { word[ wordlen - 1 ] = c; /* The next character is not escaped. */ escaped = 0; /* If the delimiter is not escaped, terminate the current word and store a pointer to it in the returned array. */ } else { result = astGrow( result, *n + 1, sizeof( char * ) ); word = astGrow( word, wordlen + 1, 1 ); if( result && word ) { word[ wordlen ] = 0; result[ (*n)++ ] = word; wordlen = 0; word = NULL; } } /* If this is not a delimitier character, store it in the returned word. */ } else { word = astGrow( word, wordlen + 1, 1 ); if( word ) word[ wordlen++ ] = *p; /* If the current character was escaped, indicate that the next character is not escaped. */ if( escaped ) { escaped = 0; /* If this character is a unescaped backslash, set a flag indicating that the next character is escaped. */ } else if( *p == '\\' ){ escaped = 1; } } /* Move on to the next character. */ p++; } /* Store the text following the final delimitier. */ result = astGrow( result, *n + 1, sizeof( char * ) ); word = astGrow( word, wordlen + 1, 1 ); if( result && word ) { word[ wordlen ] = 0; result[ (*n)++ ] = word; } /* Return the result. */ return result; } char **astChrSplitRE_( const char *str, const char *regexp, int *n, const char **matchend, int *status ) { /* *++ * Name: * astChrSplitRE * Purpose: * Extract sub-strings matching a specified regular expression. * Type: * Public function. * Synopsis: * #include "memory.h" * char **astChrSplitRE( const char *str, const char *regexp, int *n, * const char **matchend ) * Description: * This function compares the supplied string with the supplied * regular expression. If they match, each section of the test string * that corresponds to a parenthesised sub-string in the regular * expression is copied and stored in the returned array. * Parameters: * str * Pointer to the string to be split. * regexp * The regular expression. See "Template Syntax:" in the astChrSub * prologue. Note, this function differs from astChrSub in that any * equals signs (=) in the regular expression are treated literally. * n * Address of an int in which to return the number of sub-strings * returned. * matchend * A pointer to a location at which to return a pointer to the * character that follows the last character within the supplied test * string that matched any parenthesises sub-section of "regexp". A * NULL pointer is returned if no matches were found. A NULL pointer * may be supplied if the location of the last matching character is * not needed. * Returned Value: * astChrSplitRE() * A pointer to a dynamically allocated array containing "*n" elements. * Each element is a pointer to a dynamically allocated character * string containing a sub-string extracted from the supplied string. * The array itself, and the strings within it, should all be freed * using astFree when no longer needed. * Notes: * - If a parenthesised sub-string in the regular expression is matched * by more than one sub-string within the test string, then only the * first is returned. To return multiple matches, the regular * expression should include multiple copies of the parenthesised * sub-string (for instance, separated by ".+?" if the intervening * string is immaterial). * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason, or if * the supplied string contains no words. *-- */ /* Local Variables: */ char **result; char *temp; int i; /* Initialise returned values. */ *n = 0; result = NULL; /* Check global status */ if( !astOK ) return result; /* Call ChrSuber to do the work, saving the matching parts of the test string. */ temp = ChrSuber( str, regexp, NULL, 0, 1, &result, n, matchend, status ); if( temp ) { temp = astFree( temp ); /* Free all results if no match was found. */ } else if( result ) { for( i = 0; i < *n; i++ ) result[ i ] = astFree( result[ i ] ); result = astFree( result ); *n = 0; } /* Return the result */ return result; } char *ChrSuber( const char *test, const char *pattern, const char *subs[], int nsub, int ignore_equals, char ***parts, int *npart, const char **matchend, int *status ){ /* * Name: * ChrSuber * Purpose: * Performs substitutions on a supplied string. * Type: * Private function. * Synopsis: * #include "memory.h" * char *ChrSuber( const char *test, const char *pattern, * const char *subs[], int nsub, int ignore_equals, * char ***parts, int *npart, const char **matchend, * int *status ) * Description: * This function performs the work for astChrSub and astChrSplitRE. * Parameters: * test * The string to be tested. * pattern * The template string. See "Template Syntax:" in the astChrSub prologue. * subs * An array of strings that are to replace the sections of the test * string that match each parenthesised sub-string in "pattern". The * first element of "subs" replaces the part of the test string that * matches the first parenthesised sub-string in the template, etc. * * If "nsub" is zero, then the "subs" pointer is ignored. In this * case, and if parameter "ignore_equals" is zero, substitution strings * may be specified by appended them to the end of the "pattern" string, * separated by "=" characters * nsub * The number of substitution strings supplied in array "subs". * ignore_equals * If non-zero, any equals signs in the supplied pattern are * treated literally, rather than being used to split the template * from any substitution strigs. * parts * Address of a location at which to return a pointer to an array * of character string pointers. The strings are the sub-sections * of "test" that matched the parenthesised sub-sections of * "template". The array will have "*npart" elements. Ignored if NULL. * npart * Address of a location at which to return the length of the * "parts" array. Ignored if "parts" is NULL. * matchend * A pointer to a location at which to return a pointer to the * character that follows the last character within the supplied test * string that matched any parenthesises sub-section of "regexp". A * NULL pointer is returned if no matches were found. A NULL pointer * may be supplied if the location of the last matching character is * not needed. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated string holding the result * of the substitutions, or NULL if the test string does not match * the template string. This string should be freed using astFree * when no longer needed. If no substituions are specified then a * copy of the test string is returned if it matches the template. * Notes: * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason, or if * the supplied test string does not match the template. */ /* Local Variables: */ char **sections; char **temps; char *cptr; char *result; char *temp; char *template; int i; int nsec; int ntemp; size_t tlen; /* Initialise */ result = NULL; if( parts ) *npart = 0; /* Check global status */ if( !astOK ) return result; /* If required, split the total "pattern" string into sections, using (unescaped) "=" characters as the delimiter. The first section is the actual template, and each subsequent section (if any) holds a substitution string. */ if( ! ignore_equals ) { sections = astChrSplitC( pattern, '=', &nsec ); /* If equals signs are being treated literally, just take a copy of the supplied pattern. */ } else { cptr = astStore( NULL, pattern, strlen( pattern ) + 1 ); sections = &cptr; nsec = 1; } if( sections ) { /* If the caller did not provide any substitution strings, use the ones appended to the end of the pattern string (if any). */ if( nsub == 0 ) { subs = (void *) ( sections + 1 ); nsub = nsec - 1; } /* Split the template section into sub-sections, using (unescaped) "|" characters as the delimiter. Each sub-section is an alternate pattern matching template. */ temps = astChrSplitC( sections[ 0 ], '|', &ntemp ); } else { temps = 0; ntemp = 0; } /* Loop round each template until all templates have been checked or a match occurs.. */ for( i = 0; i < ntemp && !result; i++ ) { temp = temps[ i ]; tlen = strlen( temp ); /* If the template starts with "^" or "(^", remove the "^" character. Otherwise insert ".*?" at the start. Allocate three extra characters in case we later need to add ".*?" to the end of the string. */ if( temp[ 0 ] == '^' ) { template = astMalloc( tlen + 3 ); if( template ) { strcpy( template, temp + 1 ); tlen--; } } else if( temp[ 0 ] == '(' && temp[ 1 ] == '^') { template = astMalloc( tlen + 3 ); if( template ) { template[ 0 ] = '('; strcpy( template + 1, temp + 2 ); tlen--; } } else { template = astMalloc( tlen + 7 ); if( template ) { template[ 0 ] = '.'; template[ 1 ] = '*'; template[ 2 ] = '?'; strcpy( template + 3, temp ); tlen += 3; } } /* If the pattern ends with "$" or "$)", remove the "$" character. Otherwise insert ".*?" at the end. */ if( template[ tlen - 1 ] == '$' ) { tlen--; } else if( template[ tlen - 2 ] == '$' && template[ tlen - 1 ] == ')' ) { template[ tlen - 2 ] = ')'; tlen--; } else { template[ tlen ] = '.'; template[ tlen + 1 ] = '*'; template[ tlen + 2 ] = '?'; tlen += 3; } /* Ensure the string is terminated */ template[ tlen ] = 0; /* See if the test string matches the current template. */ result = ChrMatcher( test, test + strlen( test ), template, pattern, subs, nsub, 0, 1, parts, npart, matchend, status ); /* Free resources. */ template = astFree( template ); } if( temps ) { for( i = 0; i < ntemp; i++ ) temps[ i ] = astFree( temps[ i ] ); temps = astFree( temps ); } if( sections ) { for( i = 0; i < nsec; i++ ) sections[ i ] = astFree( sections[ i ] ); if( ! ignore_equals ) sections = astFree( sections ); } /* Return a NULL pointer if an error has occurred. */ if( !astOK ) result = astFree( result ); /* Return the result */ return result; } char *astChrSub_( const char *test, const char *pattern, const char *subs[], int nsub, int *status ){ /* *++ * Name: c astChrSub f AST_CHRSUB * Purpose: * Performs substitutions on a supplied string. * Type: * Public function. * Synopsis: c #include "memory.h" c char *astChrSub( const char *test, const char *pattern, c const char *subs[], int nsub ) f MATCH = AST_CHRSUB( TEST, PATTERN, RESULT, STATUS ) * Description: * This function checks a supplied test string to see if it matches a * supplied template. If it does, specified sub-sections of the test * string may optionally be replaced by supplied substitution strings. * The resulting string is returned. * Parameters: c test f TEST = CHARACTER * ( * ) (Given) * The string to be tested. * pattern f PATTERN = CHARACTER * ( * ) (Given) * The template string. See "Template Syntax:" below. * subs * An array of strings that are to replace the sections of the test * string that match each parenthesised sub-string in "pattern". The * first element of "subs" replaces the part of the test string that * matches the first parenthesised sub-string in the template, etc. * * If "nsub" is zero, then the "subs" pointer is ignored. In this * case, substitution strings may be specified by appended them to * the end of the "pattern" string, separated by "=" characters. * Note, if you need to include a literal "=" character in the * pattern, precede it by an escape "\" character. * nsub * The number of substitution strings supplied in array "subs". f RESULT = CHARACTER * ( * ) (Returned) f Returned holding the result of the substitutions. If the test f string does not match the template, then a blank string is f returned. * Returned Value: c astChrSub() c A pointer to a dynamically allocated string holding the result c of the substitutions, or NULL if the test string does not match c the template string. This string should be freed using astFree c when no longer needed. If no substituions are specified then a c copy of the test string is returned if it matches the template. f AST_CHRSUB = LOGICAL f .TRUE. if the test string matched the supplied template, and f .FALSE. otherwise. * Template Syntax: * The template syntax is a minimal form of regular expression, The * quantifiers allowed are "*", "?", "+", "{n}", "*?" and "+?" (the * last two are non-greedy - they match the minimum length possible * that still gives an overall match to the template). The only * constraints allowed are "^" and "$". The following atoms are allowed: * * - [chars]: Matches any of the specified characters. * * - [^chars]: Matches anything but the specified characters. * * - .: Matches any single character. * * - x: Matches the character x so long as x has no other significance. * * - \x: Always matches the character x (except for [dDsSwW]). * * - \d: Matches a single digit. * * - \D: Matches anything but a single digit. * * - \w: Matches any alphanumeric character, and "_". * * - \W: Matches anything but alphanumeric characters, and "_". * * - \s: Matches white space. * * - \S: Matches anything but white space. * * Note, minus signs ("-") within brackets have no special significance, * so ranges of characters must be specified explicitly. * * Multiple template strings can be concatenated, using the "|" * character to separate them. The test string is compared against * each one in turn until a match is found. * c Parentheses are used within each template to identify sub-strings c that are to be replaced by the strings supplied in "sub". c c If "nsub" is supplied as zero, then substitution strings may be c specified by appended them to the end of the "pattern" string, c separated by "=" characters. If "nsub" is not zero, then any c substitution strings appended to the end of "pattern" are ignored. f f Parentheses are used within each template to identify sub-strings f that are to be replaced by new strings. The new strings are f specified by appended them to the end of the "pattern" string, f separated by "=" characters. * c Each element of "subs" f Each new string * may contain a reference to a token of the * form "$1", "$2", etc. The "$1" token will be replaced by the part * of the test string that matched the first parenthesised sub-string * in "pattern". The "$2" token will be replaced by the part of the * test string that matched the second parenthesised sub-string in * "pattern", etc. * c Notes: c - A NULL pointer is returned if this function is invoked with the c global error status set or if it should fail for any reason, or if c the supplied test string does not match the template. *-- */ /* Call ChrSuber to do the work, without saving the matching parts of the test string. */ return ChrSuber( test, pattern, subs, nsub, 0, NULL, NULL, NULL, status ); } void *astFree_( void *ptr, int *status ) { /* *++ * Name: * astFree * Purpose: * Free previously allocated memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astFree( void *ptr ) * Description: * This function frees memory that has previouly been dynamically * allocated using one of the AST memory function. * Parameters: * ptr * Pointer to previously allocated memory. An error will result * if the memory has not previously been allocated by another * function in this module. However, a NULL pointer value is * accepted (without error) as indicating that no memory has yet * been allocated, so that no action is required. * Returned Value: * astFree() * Always returns a NULL pointer. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ Memory *mem; /* Pointer to memory header */ int isdynamic; /* Is the memory dynamically allocated? */ size_t size; /* The usable size of the memory block */ /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* If the incoming pointer is NULL, do nothing. Otherwise, check if it points at dynamically allocated memory (IsDynamic sets the global error status if it does not). */ if( ptr ) { IS_DYNAMIC( ptr, isdynamic ); } else { isdynamic = 0; } if ( isdynamic ) { /* If OK, obtain a pointer to the memory header. */ mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); #ifdef MEM_DEBUG DeIssue( mem, status ); #endif /* If the memory block is small enough, and the cache is being used, put it into the cache rather than freeing it, so that it can be reused. */ size = mem->size; if( use_cache && size <= MXCSIZE ) { mem->next = cache[ size ]; cache[ size ] = mem; /* Set the size to zero to indicate that the memory block has been freed. The size of the block is implied by the Cache element it is stored in. */ mem->size = (size_t) 0; /* Simply free other memory blocks, clearing the "magic number" and size values it contains. This helps prevent accidental re-use of the memory. */ } else { mem->magic = (unsigned long) 0; mem->size = (size_t) 0; /* Free the allocated memory. */ FREE( mem ); } } /* Always return a NULL pointer. */ return NULL; } void *astFreeDouble_( void *ptr, int *status ) { /* *++ * Name: * astFreeDouble * Purpose: * Free previously double allocated memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astFreeDouble( void *ptr ) * Description: * This function frees memory that has previouly been dynamically * allocated using one of the AST memory function. It assumes that * the supplied pointer is a pointer to an array of pointers. Each * of these pointers is first freed, and then the supplied pointer * is freed. * Parameters: * ptr * Pointer to previously allocated memory. An error will result * if the memory has not previously been allocated by another * function in this module. However, a NULL pointer value is * accepted (without error) as indicating that no memory has yet * been allocated, so that no action is required. * Returned Value: * astFreeDouble() * Always returns a NULL pointer. *-- */ /* Local Variables: */ int iptr; /* Index of sub-pointer */ int nptr; /* Number of sub-pointers */ size_t size; /* The usable size of the memory block */ void **ptrs; /* Pointer to array of pointers */ /* Check a pointer was supplied. */ if( ! ptr ) return NULL; /* Get the size of the memory area. */ size = astSizeOf( ptr ); /* Get the number of points this amount of memory could hold. */ nptr = size/sizeof( void * ); /* Report an error if the size is not an integer multiple of an address size. */ if( nptr*sizeof( void * ) != size ) { astError( AST__MEMIN, "Invalid attempt to free double allocated " "memory: the supplied memory size (%lu bytes) is not " "an integer multiple of %lu.", status, size, sizeof( void * ) ); } else { /* Free each sub-pointer. */ ptrs = (void **) ptr; for( iptr = 0; iptr < nptr; iptr++ ) { ptrs[ iptr ] = astFree( ptrs[ iptr ] ); } /* Free the supplied pointer. */ ptr = astFree( ptr ); } /* Always return a NULL pointer. */ return NULL; } void *astGrow_( void *ptr, int n, size_t size, int *status ) { /* *++ * Name: * astGrow * Purpose: * Allocate memory for an adjustable array. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astGrow( void *ptr, int n, size_t size ) * Description: * This function allocates memory in which to store an array of * data whose eventual size is unknown. It should be invoked * whenever a new array size is determined and will appropriately * increase the amount of memory allocated when necessary. In * general, it will over-allocate in anticipation of future growth * so that the amount of memory does not need adjusting on every * invocation. * Parameters: * ptr * Pointer to previously allocated memory (or NULL if none has * yet been allocated). * n * Number of array elements to be stored (may be zero). * size * The size of each array element. * Returned Value: * astGrow() * If the memory was allocated successfully, a pointer to the start * of the possibly new memory region is returned (this may be the * same as the original pointer). * Notes: * - When new memory is allocated, the existing contents are preserved. * - This function does not free memory once it is allocated, so * the size allocated grows to accommodate the maximum size of the * array (or "high water mark"). Other memory handling routines may * be used to free the memory (or alter its size) if necessary. * - If this function is invoked with the global error status set, * or if it fails for any reason, the original pointer value is * returned and the memory contents are unchanged. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int isdynamic; /* Is the memory dynamically allocated? */ Memory *mem; /* Pointer to memory header */ size_t newsize; /* New size to allocate */ void *new; /* Result pointer */ /* Check the global error status. */ if ( !astOK ) return ptr; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = ptr; /* Calculate the total size of memory needed. */ size *= (size_t) n; /* If no memory has yet been allocated, allocate exactly the amount required. */ if ( !ptr ) { new = astMalloc( size ); /* Otherwise, check that the incoming pointer identifies previously allocated memory. */ } else { IS_DYNAMIC( ptr, isdynamic ); if ( isdynamic ) { /* Obtain a pointer to the memory header and check if the new size exceeds that already allocated. */ mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); if ( mem->size < size ) { /* If so, calculate a possible new size by doubling the old size. Increase this further if necessary. */ newsize = mem->size * ( (size_t) 2 ); if ( size > newsize ) newsize = size; /* Re-allocate the memory. */ new = astRealloc( ptr, newsize ); } } } /* Return the result. */ return new; } int astIsDynamic_( const void *ptr, int *status ) { /* *++ * Name: * astIsDynamic * Purpose: * Returns a flag indicating if memory was allocated dynamically. * Type: * Public function. * Synopsis: * #include "memory.h" * int astIsDynamic_( const void *ptr ) * Description: * This function takes a pointer to a region of memory and tests if * the memory has previously been dynamically allocated using other * functions from this module. It does this by checking for the * presence of a "magic" number in the header which precedes the * allocated memory. If the magic number is not present (or the * pointer is invalid for any other reason), zero is returned. * Otherwise 1 is returned. * Parameters: * ptr * Pointer to test. * Returned Value: * astIsDynamic() * Non-zero if the memory was allocated dynamically. Zero is returned * if the supplied pointer is NULL. * Notes: * - A value of zero is returned if this function is invoked with * the global error status set, or if it fails for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ Memory *isdynmem; /* Pointer to memory header */ \ /* Check the global error status and the supplied pointer. */ if ( !astOK || ! ptr ) return 0; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Derive a pointer to the memory header that precedes the supplied region of memory. */ isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); /* Check if the "magic number" in the header is valid, returning non-zero if it is. */ return ( isdynmem->magic == MAGIC( isdynmem, isdynmem->size ) ); } void *astMalloc_( size_t size, int init, int *status ) { /* *++ * Name: * astMalloc * Purpose: * Allocate memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astMalloc( size_t size ) * Description: * This function allocates memory in a similar manner to the * standard C "malloc" function, but with improved security * (against memory leaks, etc.) and with error reporting. It also * allows zero-sized memory allocation (without error), resulting * in a NULL returned pointer value. * Parameters: * size * The size of the memory region required (may be zero). * Returned Value: * astMalloc() * If successful, the function returns a pointer to the start of * the allocated memory region. If the size allocated is zero, this * will be a NULL pointer. * Notes: * - A pointer value of NULL is returned if this function is * invoked with the global error status set or if it fails for any * reason. *-- * astMallocInit: * - This function can be invoked using either the public astMalloc * macro documented above, or the private astMallocInit macro. * astMallocInit has the same interface as astMalloc, but calls calloc * rather than malloc so that the allocated memory is filled with zeros. * Ideally, we should use an extra layer in the calling heirarchy to * remove the hidden "init" argument in the astMalloc_ interface, but * astMalloc is time-critical in many situations and so it is included * as a "hidden" argument. */ /* Local Constants: */ #define ERRBUF_LEN 80 /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ char *errstat; /* Pointer to system error message */ Memory *mem; /* Pointer to space allocated by malloc */ void *result; /* Returned pointer */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check that the size requested is not negative and report an error if it is. */ if ( size < (size_t) 0 ) { astError( AST__MEMIN, "Invalid attempt to allocate %lu bytes of memory.", status, (unsigned long) size ); /* Otherwise, if the size is greater than zero, either get a previously allocated memory block from the cache, or attempt to use malloc to allocate the memory, including space for the header structure. */ } else if ( size != (size_t ) 0 ) { /* If the cache is being used and a cached memory block of the required size is available, remove it from the cache array and use it. */ mem = ( use_cache && size <= MXCSIZE ) ? cache[ size ] : NULL; if( mem ) { cache[ size ] = mem->next; mem->next = NULL; mem->size = (size_t) size; /* Initialise the memory (but not the header) if required. */ if( init ) (void) memset( (char *) mem + SIZEOF_MEMORY, 0, size ); /* Otherwise, allocate a new memory block using "malloc" or "calloc". */ } else { if( init ) { mem = CALLOC( 1, SIZEOF_MEMORY + size ); } else { mem = MALLOC( SIZEOF_MEMORY + size ); } /* Report an error if malloc failed. */ if ( !mem ) { #if HAVE_STRERROR_R strerror_r( errno, errbuf, ERRBUF_LEN ); errstat = errbuf; #else errstat = strerror( errno ); #endif astError( AST__NOMEM, "malloc: %s", status, errstat ); astError( AST__NOMEM, "Failed to allocate %lu bytes of memory.", status, (unsigned long) size ); /* If successful, set the "magic number" in the header and also store the size. */ } else { mem->magic = MAGIC( mem, size ); mem->size = size; mem->next = NULL; #ifdef MEM_DEBUG mem->id = -1; mem->prev = NULL; #endif } } /* Do nothing more if no memory is being returned. */ if( mem ) { #ifdef MEM_DEBUG Issue( mem, status ); #endif /* Increment the memory pointer to the start of the region of allocated memory to be used by the caller.*/ result = mem; result = (char *) result + SIZEOF_MEMORY; } } /* Return the result. */ return result; } #undef ERRBUF_LEN static char *ChrMatcher( const char *test, const char *end, const char *template, const char *pattern, const char *subs[], int nsub, int ignore, int expdoll, char ***mres, int *mlen, const char **matchend, int *status ){ /* * Name: * ChrMatcher * Purpose: * Performs substitutions on a supplied string. * Type: * Private function. * Synopsis: * #include "memory.h" * char *ChrMatcher( const char *test, const char *end, const char *template, * const char *pattern, const char *subs[], int nsub, * int ignore, int expdoll, char ***mres, int *mlen, * const char **matchend, int *status ) * Description: * This function is performs most of the work for astChrSub. * Parameters: * test * The string to be tested. * end * Pointer to the terminating null character at the end of "test". * template * The template string. See astChrSub for details. * pattern * The user supplied "pattern" string (only used for error messages). * subs * An array of strings holding the values that are to be substituted * into each parenthesised substring in "test". * nsub * The length of the subs arrays. * ignore * If non-zero, then no substitutions are performed, and any * inbalance in parentheses is ignored. * expdoll * If non-zero, then any "$1", "$2", etc, tokens in the * substitution fields will be repalced by the corresponding fields * in the test string. * mres * Address of a location at which to return a pointer to an array * of character string pointers. The strings are the sub-sections * of "test" that matched the parenthesised sub-sections of * "template". The array will have "*m" elements. Ignored if NULL. * mlen * Address of a location at which to return the length of the * returned "mres" array. Ignored if "mres" is NULL. * matchend * A pointer to a location at which to return a pointer to the * character that follows the last character within the supplied test * string that matched any parenthesises sub-section of "regexp". A * NULL pointer is returned if no matches were found. A NULL pointer * may be supplied if the location of the last matching character is * not needed. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated string holding the result of the * substitutions, or NULL if the test string does not match the template * string. This string should be freed using astFree when no longer * needed. * Notes: * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason, or if * the supplied test string does not match the template. */ /* Local Variables: */ char **matches; char **newsubs; char **parts; char *allowed; char *r; char *result; char *sres; char *stest; char stemp[10]; const char *aaa; const char *aa; const char *a; const char *b; int allow; int dollar; int end_sub; int greedy; int i; int in_sub; int ipart; int match; int matchlen; int max_na; int min_na; int na; int nb; int nmatch; int npart; int partlen; int reslen; int start_sub; size_t stl; /* Initialisation. */ if( mres ) *mlen = 0; aaa = NULL; if( matchend ) *matchend = NULL; /* Check the global error status. */ if( !astOK ) return NULL; /* more initialisation. */ result = NULL; allowed = NULL; /* Get memory for a set of pointers to copies of the test sub-strings that fall between the sub-strings being replaced. */ parts = astMalloc( sizeof( char *)*(size_t) ( nsub + 1 ) ); /* Get memory for a set of pointers to copies of the test sub-strings that match the parenthesised sub-strings in the template. */ matches = astMalloc( sizeof( char *)*(size_t) nsub ); /* Initialise pointers to the next test and template characters to read. */ a = test; b = template; /* Initialise the pointer to the start of the previous test character */ aa = test; /* Assume the test string matches the template. */ match = 1; /* The template pointer is not currently in a substitution field. */ in_sub = 0; /* Initialise the number of substitution fields found so far. */ npart = 0; nmatch = 0; /* Loop until we have reached the end of either the test or template string. We break out of the loop early if we find that the test string does not match the template string. */ while( match && *a && *b ) { /* Examine the string at the start of the template string. This returns a string of allowed (or disallowed) characters that the next test character can match, the number of template characters consumed, the minimum number of test characters that must match the allowed character set, and a flag indicating if the number of matching test characters can exceed the minimum number or must be exactly equal to the minimum number. */ allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, &min_na, &max_na, &start_sub, &end_sub, &greedy, status ); if( !astOK ) break; /* Increment the the pointer to the next template character. */ b += nb; /* If the leading field in the template indicates the start of a substitution field, record the test string up to the current point. */ if( start_sub ){ /* Do nothing if we are ignoring substitutions. */ if( ! ignore ){ /* Store a pointer to the first test character that matches the substitution template. */ aaa = a; /* Report an error and abort if we are already inside a substitution field */ if( in_sub ) { astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "missing ')'.", status, pattern ); break; } /* Indicate that we are now in a substitution field. */ in_sub = 1; /* If possible, store a copy of the test string that started at the end of the previous substitution field and ends at the current point. First ensure the "parts" array is large enough since the string may contain more than "nsub" parenthesised sub-strings. */ parts = astGrow( parts, npart + 1, sizeof( char * ) ); if( parts ) { partlen = ( a - aa ); parts[ npart ] = astStore( NULL, aa, partlen + 1 ); if( parts[ npart ] ) { parts[ npart ][ partlen ] = 0; npart++; } } } /* If the leading field in the template indicates the end of a substitution field, initialise the start of the next part of the test string. */ } else if( end_sub ){ /* Do nothing if we are ignoring substitutions. */ if( ! ignore ){ /* Report an error and abort if we are not currently in a substitution field. */ if( ! in_sub ) { astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "missing '('.", status, pattern ); break; } /* We are no longer in a substitution field. */ in_sub = 0; /* If possible, store a copy of the test string that matched the substitution template. */ matches = astGrow( matches, nmatch + 1, sizeof( char * ) ); if( matches ) { matchlen = ( a - aaa ); matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 ); if( matches[ nmatch ] ) { matches[ nmatch ][ matchlen ] = 0; nmatch++; if( matchend ) *matchend = a; } } /* Record the start of the next test string part. */ aa = a; } /* Otherwise, find how many characters at the front of the test string match the leading field in the template. Find the number of leading characters in the test string that are contained in the set of characters allowed by the leading field in the template. */ } else { if( !allowed ) { na = strlen( a ); } else if( allow ) { na = strspn( a, allowed ); } else { na = strcspn( a, allowed ); } /* Check that the minmum number of matching characters is available. */ if( na < min_na ){ match = 0; break; } /* Dont match more characters than are needed. */ if( na > max_na ) na = max_na; /* We cannot match more characters than are available. */ if( na < max_na ) max_na = na; /* If we have exhausted the template, match the maximum number of characters. */ if( ! *b ) { na = max_na; /* If we still have a match, we may choose to use fewer than the max allowed number of test characters in order to allow the next template field to be matched. Don't need to do this if we have reached the end of the template. */ } else if( max_na > min_na ) { match = 0; /* If a greedy quantifier was used, try using a decreasing number of test characters, starting at the maximum allowed and decreasing down to the minimum, until a number is found which allows the rest of the string to be matched. */ if( greedy ) { for( na = max_na; na >= min_na; na-- ) { r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0, NULL, NULL, NULL, status ); if( r ) { match = 1; r = astFree( r ); break; } } /* If a non-greedy quantifier was used, try using an increasing number of test characters, starting at the minimum allowed and increasing up to the maximum, until a number is found which allows the rest of the string to be matched. */ } else { for( na = min_na; na <= max_na; na++ ) { r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0, NULL, NULL, NULL, status ); if( r ) { match = 1; r = astFree( r ); break; } } } } /* Increment the the pointer to the next test character. */ a += na; if( a > end ) a = end; } } /* If the test string is finished but the template string is not, see if the next part of the template string will match a null test string. But ignore the ends of substitution fields. */ if( !*a && *b && match ) { while( *b && *b != ')' ) { allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, &min_na, &max_na, &start_sub, &end_sub, &greedy, status ); b += nb; allowed = astFree( allowed ); if( min_na > 0 ) { match = 0; break; } } } /* If the next character in the template is a closing parenthesis, then we are finishing a substitution field. */ if( match && *b == ')' ) { /*Check we are not ignoring substitutions. */ if( ! ignore ){ /* Report an error and abort if we are not currently in a substitution field. */ if( ! in_sub ) { astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "missing '('.", status, pattern ); } /* We are no longer in a substitution field. */ in_sub = 0; /* If possible, store a copy of the test string that matched the substitution field. */ matches = astGrow( matches, nmatch + 1, sizeof( char * ) ); if( matches ) { matchlen = ( a - aaa ); matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 ); if( matches[ nmatch ] ) { matches[ nmatch ][ matchlen ] = 0; nmatch++; if( matchend ) *matchend = a; } } aa = a; } b++; } /* If the test string is finished but the template string is not, see if the rest of the template string will match a null test string. */ if( !*a && *b && match ) { while( *b ) { allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, &min_na, &max_na, &start_sub, &end_sub, &greedy, status ); b += nb; allowed = astFree( allowed ); if( min_na > 0 ) { match = 0; break; } } } /* No match if either string was not used completely. */ if( *a || *b ) match = 0; /* Report an error if we are still inside a substitution field */ if( match && in_sub && !ignore ) { astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " "missing ')'.", status, pattern ); match = 0; } /* If we have a match, construct the returned string. */ if( match && parts ) { /* Store the test string following the final substitution field. */ parts = astGrow( parts, npart + 1, sizeof( char * ) ); if( parts ) { partlen = ( a - aa ); parts[ npart ] = astStore( NULL, aa, partlen + 1 ); if( parts[ npart ] ) { parts[ npart ][ partlen ] = 0; npart++; } } /* If required, expand $1, $2, etc within the replacement strings. */ if( expdoll) { newsubs = astMalloc( sizeof( char * )*nsub ); if( newsubs ) { for( i = 0; i < nsub; i++ ) { stl = strlen( subs[ i ] ); stest = astStore( NULL, subs[ i ], stl + 1 ); for( dollar = 1; dollar <= nsub; dollar++ ) { sprintf( stemp, ".*($%d).*", dollar ); sres = ChrMatcher( stest, stest + stl, stemp, stemp, (void *) ( matches + dollar - 1 ), 1, 0, 0, NULL, NULL, NULL, status ); if( sres ) { (void) astFree( stest ); stest = sres; } } newsubs[ i ] = stest; } } } else { newsubs = (char **) subs; } /* Concatenate the sub-strings to form the final string. */ reslen = 0; for( ipart = 0; ipart < npart - 1; ipart++ ) { result = astAppendString( result, &reslen, parts[ ipart ] ); if( ipart < nsub ) { result = astAppendString( result, &reslen, newsubs[ ipart ] ); } else { result = astAppendString( result, &reslen, matches[ ipart ] ); } } result = astAppendString( result, &reslen, parts[ ipart ] ); /* Free resources. */ if( newsubs && newsubs != (char **) subs ) { for( i = 0; i < nsub; i++ ) { newsubs[ i ] = astFree( newsubs[ i ] ); } newsubs = astFree( newsubs ); } } allowed = astFree( allowed ); for( ipart = 0; ipart < npart; ipart++ ) { parts[ ipart ] = astFree( parts[ ipart ] ); } parts = astFree( parts ); /* If required, return the array holding the test sub-strings that matched the parenthesised template sub-strings, together with the length of the array. Otherwise, free the memory holding these strings. */ if( mres ) { *mres = matches; *mlen = nmatch; } else if( matches ) { for( i = 0; i < nmatch; i++ ) { matches[ i ] = astFree( matches[ i ] ); } matches = astFree( matches ); } /* Return the result. */ return result; } int astMemCaching_( int newval, int *status ){ /* *++ * Name: * astMemCaching * Purpose: * Controls whether allocated but unused memory is cached in this module. * Type: * Public function. * Synopsis: * #include "memory.h" * int astMemCaching( int newval ) * Description: * This function sets a flag indicating if allocated but unused memory * should be cached or not. It also returns the original value of the * flag. * * If caching is switched on or off as a result of this call, then the * current contents of the cache are discarded. * * Note, each thread has a separate cache. Calling this function * affects only the currently executing thread. * Parameters: * newval * The new value for the MemoryCaching tuning parameter (see * astTune in objectc.c). If AST__TUNULL is supplied, the current * value is left unchanged. * Returned Value: * astMemCaching() * The original value of the MemoryCaching tuning parameter. *-- */ /* Local Variables: */ astDECLARE_GLOBALS int i; int result; Memory *mem; #ifdef MEM_DEBUG int id_list_size; int *id_list; #endif /* Check the global error status. */ if ( !astOK ) return 0; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Store the original value of the tuning parameter. */ result = use_cache; /* If a new value is to be set. */ if( newval != AST__TUNULL ) { /* If the cache has been initialised, empty it. */ if( cache_init ) { /* If we are listing the ID of every memory block in the cache, count the number of blocks in the cache and then allocate an array to store the ID values in. This is done so that we can sort them before displaying them. */ #ifdef MEM_DEBUG if( List_Cache ) { Memory *next; id_list_size = 0; for( i = 0; i <= MXCSIZE; i++ ) { next = cache[ i ]; while( next ) { id_list_size++; next = next->next; } } id_list = MALLOC( sizeof(int)*id_list_size ); if( !id_list ) { astError( AST__INTER, "astMemCaching: Cannot allocate %lu " "bytes of memory", status, (unsigned long)(sizeof(int)*id_list_size) ); } id_list_size = 0; } else { id_list = NULL; } #endif for( i = 0; i <= MXCSIZE; i++ ) { while( cache[ i ] ) { mem = cache[ i ]; cache[ i ] = mem->next; mem->size = (size_t) i; #ifdef MEM_DEBUG if( id_list ) { id_list[ id_list_size++ ] = mem->id; } #endif FREE( mem ); } } /* If we are displaying the IDs of memory blocks still in the cache, sort them using a bubblesort algorithm, then display them. */ #ifdef MEM_DEBUG if( id_list ) { if( id_list_size == 0 ) { printf( "Emptying the AST memory cache - (the cache is " "already empty)\n" ); } else { int sorted, j, t; sorted = 0; for( j = id_list_size - 2; !sorted && j >= 0; j-- ) { sorted = 1; for( i = 0; i <= j; i++ ) { if( id_list[ i ] > id_list[ i + 1 ] ) { sorted = 0; t = id_list[ i ]; id_list[ i ] = id_list[ i + 1 ]; id_list[ i + 1 ] = t; } } } printf( "Emptying the AST memory cache - freeing the " "following memory blocks: "); for( i = 0; i < id_list_size; i++ ) printf( "%d ", id_list[ i ] ); printf( "\n" ); } } #endif /* Otherwise, initialise the cache array to hold a NULL pointer at every element. */ } else { for( i = 0; i <= MXCSIZE; i++ ) cache[ i ] = NULL; cache_init = 1; } /* Store the new value. */ use_cache = newval; } /* Return the original value. */ return result; } void *astRealloc_( void *ptr, size_t size, int *status ) { /* *++ * Name: * astRealloc * Purpose: * Change the size of a dynamically allocated region of memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astRealloc( void *ptr, size_t size ) * Description: * This function changes the size of a dynamically allocated region * of memory, preserving its contents up to the minimum of the old * and new sizes. This may involve copying the contents to a new * location, so a new pointer is returned (and the old memory freed * if necessary). * * This function is similar to the standard C "realloc" function * except that it provides better security against programming * errors and also supports the allocation of zero-size memory * regions (indicated by a NULL pointer). * Parameters: * ptr * Pointer to previously allocated memory (or NULL if the * previous size of the allocated memory was zero). * size * New size required for the memory region. This may be zero, in * which case a NULL pointer is returned (no error results). It * should not be negative. * Returned Value: * astRealloc() * If the memory was reallocated successfully, a pointer to the * start of the new memory region is returned (this may be the same * as the original pointer). If size was given as zero, a NULL * pointer is returned. * Notes: * - If this function is invoked with the error status set, or if * it fails for any reason, the original pointer value is returned * and the memory contents are unchanged. Note that this behaviour * differs from that of the standard C "realloc" function which * returns NULL if it fails. *-- */ /* Local Constants: */ #define ERRBUF_LEN 80 /* Local Variables: */ astDECLARE_GLOBALS char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ char *errstat; /* Pointer to system error message */ int isdynamic; /* Was memory allocated dynamically? */ void *result; /* Returned pointer */ Memory *mem; /* Pointer to memory header */ /* Check the global error status. */ if ( !astOK ) return ptr; /* Initialise. */ result = ptr; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* If a NULL pointer was supplied, use astMalloc to allocate some new memory. */ if ( !ptr ) { result = astMalloc( size ); /* Otherwise, check that the pointer supplied points at memory allocated by a function in this module (IsDynamic sets the global error status if it does not). */ } else { IS_DYNAMIC( ptr, isdynamic ); if ( isdynamic ) { /* Check that a negative size has not been given and report an error if necessary. */ if ( size < (size_t) 0 ) { astError( AST__MEMIN, "Invalid attempt to reallocate a block of memory to %ld bytes.", status, (long) size ); /* If OK, obtain a pointer to the memory header. */ } else { mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); /* If the new size is zero, free the old memory and set a NULL return pointer value. */ if ( size == (size_t) 0 ) { astFree( ptr ); result = NULL; /* Otherwise, reallocate the memory. */ } else { /* If the cache is being used, for small memory blocks, do the equivalent of mem = REALLOC( mem, SIZEOF_MEMORY + size ); using astMalloc, astFree and memcpy explicitly in order to ensure that the memory blocks are cached. */ if( use_cache && ( mem->size <= MXCSIZE || size <= MXCSIZE ) ) { result = astMalloc( size ); if( result ) { if( mem->size < size ) { memcpy( result, ptr, mem->size ); } else { memcpy( result, ptr, size ); } astFree( ptr ); } else { result = ptr; } /* For other memory blocks simply use realloc. */ } else { #ifdef MEM_DEBUG DeIssue( mem, status ); #endif mem = REALLOC( mem, SIZEOF_MEMORY + size ); /* If this failed, report an error and return the original pointer value. */ if ( !mem ) { #if HAVE_STRERROR_R strerror_r( errno, errbuf, ERRBUF_LEN ); errstat = errbuf; #else errstat = strerror( errno ); #endif astError( AST__NOMEM, "realloc: %s", status, errstat ); astError( AST__NOMEM, "Failed to reallocate a block of " "memory to %ld bytes.", status, (long) size ); /* If successful, set the new "magic" value and size in the memory header and obtain a pointer to the start of the region of memory to be used by the caller. */ } else { mem->magic = MAGIC( mem, size ); mem->size = size; mem->next = NULL; #ifdef MEM_DEBUG mem->id = -1; mem->prev = NULL; Issue( mem, status ); #endif result = mem; result = (char *) result + SIZEOF_MEMORY; } } } } } } /* Return the result. */ return result; } #undef ERRBUF_LEN void astRemoveLeadingBlanks_( char *string, int *status ) { /* *++ * Name: * astRemoveLeadingBlanks * Purpose: * Remove any leading white space from a string. * Type: * Public function. * Synopsis: * #include "memory.h" * void astRemoveLeadingBlanks( char *string ) * Description: * This function moves characters in the supplied string to the left * in order to remove any leading white space. * Parameters: * string * Pointer to the string. *-- */ /* Local Variables: */ char *c, *d; /* Check a string has been supplied. */ if( string ){ /* Get a pointer to the first non-white character in the string. */ c = string; while( *c && isspace( *c ) ) c++; /* Do nothing more if there are no leading spaces. */ if( c > string ) { /* Copy all characters (excluding the trailing null) to the left to over-write the leading spaces. */ d = string; while( *c ) *(d++) = *(c++); /* Terminate the returned string. */ *d = 0; } } } size_t astSizeOf_( const void *ptr, int *status ) { /* *++ * Name: * astSizeOf * Purpose: * Determine the size of a dynamically allocated region of memory. * Type: * Public function. * Synopsis: * #include "memory.h" * size_t astSizeOf( const void *ptr ) * Description: * This function returns the size of a region of dynamically * allocated memory. * Parameters: * ptr * Pointer to dynamically allocated memory (or NULL if the size * of the allocated memory was zero). * Returned Value: * astSizeOf() * The allocated size. This will be zero if a NULL pointer was * supplied (no error will result). * Notes: * - A value of zero is returned if this function is invoked with * the global error status set, or if it fails for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int isdynamic; /* Was the memory allocated dynamically? */ size_t size; /* Memory size */ /* Check the global error status. */ if ( !astOK ) return (size_t) 0; /* Initialise. */ size = (size_t) 0; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check if a non-NULL valid pointer has been given. If so, extract the memory size from the header which precedes it. */ if ( ptr ){ IS_DYNAMIC( ptr, isdynamic ); if( isdynamic ) size = ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size; } /* Return the result. */ return size; } static size_t SizeOfMemory( int *status ){ /* * Name: * SizeOfMemory * Purpose: * Returns the size of a Memory structure, padded to an 8 byte * boundary. * Type: * Private function. * Synopsis: * size_t SizeOfMemory( int *status ) * Description: * This function returns the size of a Memory structure used to * store header information about any block of memory allocated by this * module. The returned value may be larger than the actual size of * the Memory structure in order to ensure that the pointer returned by * astMalloc etc points to an 8 byte boundary. Failure to do this can * result in some operating systems having problems. E.g Solaris * requires this alignment if the returned pointer is going to be used to * store doubles. * Parameters: * status * Pointer to the inherited status variable. * Returned Value: * The size to use for a Memory structure. * Notes: * - The returned value is also stored in the module variable * sizeof_memory. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get the basic size of a Memory structure. */ sizeof_memory = sizeof( Memory ); /* Now increase the returned value to ensure it is a multiple of 8. Mask off all but the last 3 bits, xor with 0x7 to get the remainder, add 1 to make it a multiple of 8 bytes. */ sizeof_memory += ((sizeof_memory & 0x7) ? ((sizeof_memory & 0x7) ^ 0x7) + 1 : 0); /* Return the value */ return sizeof_memory; } size_t astTSizeOf_( const void *ptr, int *status ) { /* *+ * Name: * astTSizeOf * Purpose: * Determine the total size of a dynamically allocated region of memory. * Type: * Protected function. * Synopsis: * #include "memory.h" * size_t astTSizeOf( const void *ptr ) * Description: * This function returns the size of a region of dynamically * allocated memory, including the extra memory used to store * the header information for the memory block (size and magic number). * Parameters: * ptr * Pointer to dynamically allocated memory (or NULL if the size * of the allocated memory was zero). * Returned Value: * The allocated size. This will be zero if a NULL pointer was * supplied (no error will result). * Notes: * - A value of zero is returned if this function is invoked with * the global error status set, or if it fails for any reason. * - This function is documented as protected because it should not * be invoked by external code. However, it is available via the * external C interface so that it may be used when writing (e.g.) * foreign language or graphics interfaces. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int isdynamic; /* Was the memory allocated dynamically? */ size_t size; /* Memory size */ /* Check the global error status. */ if ( !astOK ) return (size_t) 0; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ size = (size_t) 0; /* Check if a non-NULL valid pointer has been given. If so, extract the memory size from the header which precedes it. */ if ( ptr ){ IS_DYNAMIC( ptr, isdynamic ); if( isdynamic ) size = SIZEOF_MEMORY + ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size; } /* Return the result. */ return size; } void *astStore_( void *ptr, const void *data, size_t size, int *status ) { /* *++ * Name: * astStore * Purpose: * Store data in dynamically allocated memory. * Type: * Public function. * Synopsis: * #include "memory.h" * void *astStore( void *ptr, const void *data, size_t size ) * Description: * This function stores data in dynamically allocated memory, * allocating the memory (or adjusting the size of previously * allocated memory) to match the amount of data to be stored. * Parameters: * ptr * Pointer to previously allocated memory (or NULL if none has * yet been allocated). * data * Pointer to the start of the data to be stored. This may be * given as NULL if there are no data, in which case it will be * ignored and this function behaves like astRealloc, preserving * the existing memory contents. * size * The total size of the data to be stored and/or the size of * memory to be allocated. This may be zero, in which case the * data parameter is ignored, any previously-allocated memory is * freed and a NULL pointer is returned. * Returned Value: * astStore() * If the data were stored successfully, a pointer to the start of * the possibly new memory region is returned (this may be the same * as the original pointer). If size was given as zero, a NULL * pointer is returned. * Notes: * - This is a convenience function for use when storing data of * arbitrary size in memory which is to be allocated * dynamically. It is appropriate when the size of the data will * not change frequently because the size of the memory region will * be adjusted to fit the data on every invocation. * - If this function is invoked with the error status set, or if * it fails for any reason, the original pointer value is returned * and the memory contents are unchanged. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int valid; /* Is the memory pointer usable? */ void *new; /* Pointer to returned memory */ /* Check the global error status. */ if ( !astOK ) return ptr; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = ptr; /* If the new size is zero, use astRealloc to free any previously allocated memory. Also re-allocate the memory if the data pointer is NULL (in which case we want to preserve its contents). */ if ( ( size == (size_t) 0 ) || !data ) { new = astRealloc( ptr, size ); /* In other cases, we do not want to preserve any memory contents. Check if the incoming memory pointer is valid (IsDynamic sets the global error status if it is not). */ } else { if ( !ptr ){ valid = 1; } else { IS_DYNAMIC( ptr, valid ); } if( valid ) { /* Allocate the new memory. If successful, free the old memory (if necessary) and copy the data into it. */ new = astMalloc( size ); if ( astOK ) { if ( ptr ) ptr = astFree( ptr ); (void) memcpy( new, data, size ); /* If memory allocation failed, do not free the old memory but return a pointer to it. */ } else { new = ptr; } } } /* Return the result. */ return new; } char *astString_( const char *chars, int nchars, int *status ) { /* *++ * Name: * astString * Purpose: * Create a C string from an array of characters. * Type: * Public function. * Synopsis: * #include "memory.h" * char *astString( const char *chars, int nchars ) * Description: * This function allocates memory to hold a C string and fills the * string with the sequence of characters supplied. It then * terminates the string with a null character and returns a * pointer to its start. The memory used for the string may later * be de-allocated using astFree. * * This function is intended for constructing null terminated C * strings from arrays of characters which are not null terminated, * such as when importing a character argument from a Fortran 77 * program. * Parameters: * chars * Pointer to the array of characters to be used to fill the string. * nchars * The number of characters in the array (zero or more). * Returned Value: * astString() * If successful, the function returns a pointer to the start of * the allocated string. If the number of characters is zero, a * zero-length string is still allocated and a pointer to it is * returned. * Notes: * - A pointer value of NULL is returned if this function is * invoked with the global error status set or if it fails for any * reason. *-- */ /* Local Variables: */ char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the number of characters in the string is valid and report an error if it is not. */ if ( nchars < 0 ) { astError( AST__NCHIN, "astString: Invalid attempt to allocate a string " "with %d characters.", status, nchars); /* Allocate memory to hold the string. */ } else { result = (char *) astMalloc( (size_t) ( nchars + 1 ) ); /* If successful, copy the characters into the string. */ if ( astOK && result ) { (void) memcpy( result, chars, (size_t) nchars ); /* Terminate the string. */ result[ nchars ] = '\0'; } } /* Return the result. */ return result; } char **astStringArray_( const char *chars, int nel, int len, int *status ) { /* *++ * Name: * astStringArray * Purpose: * Create an array of C strings from an array of characters. * Type: * Public function. * Synopsis: * #include "memory.h" * char **astStringArray( const char *chars, int nel, int len ) * Description: * This function turns an array of fixed-length character data into * a dynamicllay allocated array of null-terminated C strings with * an index array that may be used to access them. * * The array of character data supplied is assumed to hold "nel" * adjacent fixed-length strings (without terminating nulls), each * of length "len" characters. This function allocates memory and * creates a null-terminated copy of each of these strings. It also * creates an array of "nel" pointers which point at the start of * each of these new strings. A pointer to this index array is * returned. * * The memory used is allocated in a single block and should later * be de-allocated using astFree. s * Parameters: * chars * Pointer to the array of input characters. The number of characters * in this array should be at least equal to (nel * len). * nel * The number of fixed-length strings in the input character * array. This may be zero but should not be negative. * len * The number of characters in each fixed-length input * string. This may be zero but should not be negative. * Returned Value: * astStringArray() * A pointer to the start of the index array, which contains "nel" * pointers pointing at the start of each null-terminated output * string. * * The returned pointer should be passed to astFree to de-allocate * the memory used when it is no longer required. This will free * both the index array and the memory used by the strings it * points at. * Notes: * - A NULL pointer will also be returned if the value of "nel" is * zero, in which case no memory is allocated. * - A pointer value of NULL will also be returned if this function * is invoked with the global error status set or if it fails for * any reason. *-- */ /* Local Variables: */ char **result; /* Result pointer to return */ char *out_str; /* Pointer to start of next output string */ const char *in_str; /* Pointer to start of next input string */ int i; /* Loop counter for array elements */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the array size is valid and report an error if it is not. */ if ( nel < 0 ) { astError( AST__NELIN, "astStringArray: Invalid attempt to allocate an array of " "%d strings.", status, nel ); /* If the string length will be used, check that it is valid and report an error if it is not. */ } else if ( ( nel > 0 ) && ( len < 0 ) ) { astError( AST__NCHIN, "astStringArray: Invalid attempt to allocate an " "array of strings with %d characters in each.", status, len ); /* Allocate memory to hold the array of string pointers plus the string data (with terminating nulls). */ } else { result = astMalloc( sizeof( char * ) * (size_t) nel + (size_t) ( nel * ( len + 1 ) ) ); /* If successful, initialise pointers to the start of the current input and output strings. */ if( astOK ){ in_str = chars; out_str = (char *) ( result + nel ); /* Loop to copy each string. */ for ( i = 0; i < nel; i++ ) { (void) memcpy( out_str, in_str, (size_t) len ); /* Terminate the output string. */ out_str[ len ] = '\0'; /* Store a pointer to the start of the output string in the array of character pointers. */ result[ i ] = out_str; /* Increment the pointers to the start of the next string. */ out_str += len + 1; in_str += len; } } } /* Return the result. */ return result; } char *astStringCase_( const char *string, int upper, int *status ) { /* *++ * Name: * astStringCase * Purpose: * Convert a string to upper or lower case. * Type: * Public function. * Synopsis: * #include "memory.h" * char *astStringCase( const char string, int upper ) * Description: * This function converts a supplied string to upper or lower case, * storing the result in dynamically allocated memory. The astChrCase * function is similar, but stores the result in a supplied buffer. * Parameters: * string * Pointer to the null terminated string to be converted. * upper * If non-zero, the string is converted to upper case. Otherwise it * is converted to lower case. * Returned Value: * astStringCase() * If successful, the function returns a pointer to the start of * the allocated string. The returned memory should be freed using * astFree when no longer needed. * Notes: * - A pointer value of NULL is returned if this function is * invoked with the global error status set or if it fails for any * reason. *-- */ /* Local Variables: */ char *pout; /* Pointer to next output character */ char *result; /* Pointer value to return */ const char *pin; /* Pointer to next input character */ int i; /* Character index */ int len; /* String length */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get the length of the supplied string, excluding the trailing null. */ len = strlen( string ); /* Allocate memory to hold the converted string, plus terminating null. */ result = (char *) astMalloc( (size_t) ( len + 1 ) ); /* If successful, copy the characters into the string, converting each one to the requested case. */ if ( result ) { pin = string; pout = result; if( upper ) { for( i = 0; i < len; i++ ) { *(pout++) = toupper( (int) *(pin++) ); } } else { for( i = 0; i < len; i++ ) { *(pout++) = tolower( (int) *(pin++) ); } } /* Terminate the string. */ *pout = '\0'; } /* Return the result. */ return result; } size_t astChrLen_( const char *string, int *status ) { /* *++ * Name: * astChrLen * Purpose: * Determine the used length of a string. * Type: * Public function. * Synopsis: * #include "memory.h" * size_t astChrLen( const char *string ) * Description: * This function returns the used length of a string. This excludes any * trailing white space or non-printable characters (such as the * trailing null character). * Parameters: * string * Pointer to the string. * Returned Value: * astChrLen() * The number of characters in the supplied string, not including the * trailing newline, and any trailing white-spaces or non-printable * characters. *-- */ /* Local Variables: */ const char *c; /* Pointer to the next character to check */ size_t ret; /* The returned string length */ /* Initialise the returned string length. */ ret = 0; /* Check a string has been supplied. */ if( string ){ /* Check each character in turn, starting with the last one. */ ret = strlen( string ); c = string + ret - 1; while( ret ){ if( isprint( (int) *c ) && !isspace( (int) *c ) ) break; c--; ret--; } } /* Return the answer. */ return ret; } int astSscanf_( const char *str, const char *fmt, ...) { /* *+ * Name: * astSscanf * Purpose: * A wrapper for the ANSI sscanf function. * Type: * Protected function. * Synopsis: * #include "memory.h" * int astSscanf( const char *str, const char *fmt, ...) * Description: * This function is a direct plug-in replacement for sscanf. It ensures ANSI * behaviour is available on all platforms, including those (such as * MacOS) on which have the native sscanf function exhibits non-ANSI * behaviour. * Parameters: * str * Pointer to the string to be scanned. * fmt * Pointer to the format string which defines the fields to be * looked for within "str". * ... * Pointers to locations at which to return the value of each * succesfuly converted field, in the order specified in "fmt". * Returned Value: * The number of fields which were succesfully read from "str". *- */ /* Local Variables: */ char *c; /* Pointer to the next character to check */ char *newfor; /* Pointer to modified format string */ const char *d; /* Pointer to the next character to check */ int *status; /* Pointer to inherited status value */ int iptr; /* Index into ptr array */ int lfor; /* No. of characters in format string */ int lstr; /* No. of characters in scanned string */ int nc; /* No. of characters read from str */ int nfld; /* No. of counted field specifiers found so far */ int nptr; /* Np. of pointers stored */ int ret; /* The returned number of conversions */ va_list args; /* Variable argument list pointer */ void *fptr; /* The next supplied pointer */ void *ptr[ VMAXFLD ]; /* Array of supplied pointers */ /* Initialise the variable argument list pointer. */ va_start( args, fmt ); /* Get a pointer to the integer holding the inherited status value. */ status = astGetStatusPtr; /* Initialise the returned string length. */ ret = 0; /* Check a string and format have been supplied. */ if( str && fmt ){ /* Go through the format string, counting the number of field specifiers which will return a value, and storing the corresponding points in the ptr array. */ nptr = 0; c = (char *) fmt; while( *c ) { /* Field specifiers are marked by a % sign. */ if( *c == '%' ) { /* Look at the character following the % sign. Quit if the end of the string has been reached. */ c++; if( *c ) { /* If the % sign is followed by a "*" or another "%", then there will be no corresponding pointer in the variable argument list "args". Ignore such field specifiers. */ if( *c != '*' && *c != '%' ) { /* If possible store the corresponding pointer from the variable argument list supplied to this function. Report an error if there are too many. */ if ( nptr < VMAXFLD ) { ptr[ nptr++ ] = va_arg( args, void *); /* If the current field specifier is "%n" the corresponding pointer should be a pointer to an integer. We initialise the integer to zero. We need to do this because sscanf does not include "%n" values in the returned count of succesful conversions, and so there is no sure way of knowing whether a value has been stored for a "%n" field, and so whether it is safe to use it as an index into the supplied. */ if( *c == 'n' ) *( (int *) ptr[ nptr - 1 ] ) = 0; } else { astError( AST__INTER, "astSscanf: Format string " "'%s' contains more than %d fields " "(AST internal programming error).", status, fmt, VMAXFLD ); break; } } /* Move on the first character following the field specifier. */ c++; } /* If this is not the start of a field specifier, pass on. */ } else { c++; } } /* Fill any unused pointers with NULL. */ for( iptr = nptr; iptr < VMAXFLD; iptr++ ) ptr[iptr] = NULL; /* Get the length of the string to be scanned. */ lstr = strlen( str ); /* Get the length of the format string excluding any trailing white space. */ lfor = astChrLen( fmt ); /* Bill Joye reports that MacOS sscanf fails to return the correct number of characters read (using a %n conversion) if there is a space before the %n. So check for this. Does the format string contain " %n"? */ c = strstr( fmt, " %n" ); if( c && astOK ) { /* Take a copy of the supplied format string (excluding any trailing spaces). */ newfor = (char *) astStore( NULL, (void *) fmt, (size_t) lfor + 1 ); if( newfor ) { /* Ensure the string is terminated (in case the supplied format string has any trailing spaces). */ newfor[ lfor ] = 0; /* Remove all spaces from before any %n. */ c = strstr( (const char *) newfor, " %n" ); while( c ) { while( *(c++) ) *( c - 1 ) = *c; c = strstr( newfor, " %n" ); } /* Use the native sscanf with the modified format string. Note, we cannot use vsscanf because it is not ANSI C. Instead, we list the pointers explicitly. */ ret = sscanf( str, newfor, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] ); /* Now look through the original format string for conversions specifiers. If any %n conversions are found which are preceded by a space, then correct the returned character counts to include any spaces following the corresponding point in the scanned string. */ nfld = 0; iptr = 0; c = (char *) fmt; while( *c ) { /* Field specifiers are marked by a % sign. */ if( *c == '%' ) { /* Look at the character following the % sign. Quit if the end of the string has been reached. */ c++; if( *c ) { /* If the % sign is followed by a "*" or another "%", then there will be no corresponding pointer in the variable argument list "args". Ignore such field specifiers. */ if( *c != '*' && *c != '%' ) { /* Get the supplied pointer corresponding to this field specifier. */ fptr = ptr[ iptr++ ]; /* Increment the number of matched fields required. "%n" specifiers are not included in the value returned by sscanf so skip over them. */ if( *c != 'n' ) { nfld++; /* If the % sign is followed by a "n", and was preceded by a space, we may need to correct the returned character count. */ } else if( c > fmt + 1 && *(c-2) == ' ' ) { /* Do not correct the returned value if sscanf did not get as far as this field specifier before an error occurred. */ if( ret >= nfld ) { /* Get the original character count produced by sscanf. */ nc = *( (int *) fptr ); /* For each space in "str" which follows, increment the returned count by one (so long as the original count is not zero or more than the length of the string - this is not foolproof, but I can't think of a better check - all uses of %n in AST initialize the supplied count to zero before calling sscanf so a value fo zero is a safe (ish) bet that the supplied string doesn't match the supplied format). */ if( nc > 0 && nc < lstr ) { d = str + nc; while( *(d++) == ' ' ) nc++; *( (int *) fptr ) = nc; } } } } /* Move on the first character following the field specifier. */ c++; } /* If this is not the start of a field specifier, pass on. */ } else { c++; } } /* Release the temporary copy of the format string. */ newfor = (char *) astFree( (void *) newfor ); } /* If the format string should not trigger any known problems, use sscanf directly. */ } else if( astOK ) { ret = sscanf( str, fmt, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] ); } } /* Tidy up the argument pointer. */ va_end( args ); /* Return the answer. */ return ret; } /* The next functions are used only when memory debugging is switched on via the MEM_DEBUG macro. They can be used for locating memory leaks, etc. */ #ifdef MEM_DEBUG void astActiveMemory_( const char *label ) { /* *+ * Name: * astActiveMemory * Purpose: * Display a list of any currently active AST memory pointers. * Type: * Protected function. * Synopsis: * #include "memory.h" * astActiveMemory( const char *label ) * Description: * This function displays a list of the identifiers for all currently * active AST memory chunks. The list is written to standard output * using "printf", preceded by the supplied text. * Parameters: * label * A textual label to display before the memody id values (may be * NULL). * Notes: * - This function attempts to execute even if an error has occurred. * - Memory blocks which are not usually freed are not reported. Such * blocks are typically used by AST to hold internal state information. *- */ Memory *next; if( label ) printf("%s: ", label ); next = Active_List; if( next ) { while( next ) { if( !next->perm ) { printf( "%d(%s:%d) ", next->id, next->file, next->line ); } next = next->next; } } else { printf("There are currently no active AST memory blocks."); } printf("\n"); } void astWatchMemory_( int id ) { /* *+ * Name: * astWatchMemory * Purpose: * Indicate uses of the memory block with the specified identifier * should be reported. * Type: * Protected function. * Synopsis: * #include "memory.h" * astWatchMemory( int id ) * Description: * This function forces astMemoryAlarm to be invoked when key * operations are performed on a specified memory block. These key * operations include; allocation, freeing, copying and cloning of * Objects, etc. * * astMemoryAlarm reports a message when called identifying the memory * block and the action performed on it. When using a debugger, these * events can be trapped and investigated by setting a debugger * breakpoint in astMemoryAlarm_. * Parameters: * id * The identifier of the memory block which is to be watched. * Notes: * - This function attempts to execute even if an error has occurred. *- */ Watched_ID = id; } int astMemoryId_( const void *ptr, int *status ){ /* *+ * Name: * astMemoryId * Purpose: * Return the integer identifier for a memory block. * Type: * Protected function. * Synopsis: * #include "memory.h" * int astMemoryId( const void *ptr ) * Description: * This function returns the integer identifier associated with a * memory block allocated by function sin this module. * Parameters: * ptr * The pointer (a genuine C pointer, not an encoded object * identifier). * Returned Value: * The integer identifier. A value of -1 is returned if "ptr" is NULL. *- */ astDECLARE_GLOBALS astGET_GLOBALS(NULL); return ptr ? ((Memory *)(ptr-SIZEOF_MEMORY))->id : -1; } void *astMemoryPtr_( int id ){ /* *+ * Name: * astMemoryPtr * Purpose: * Return a pointer to the memory block with a given identifier. * Type: * Protected function. * Synopsis: * #include "memory.h" * void *astMemoryPtr( int id ) * Description: * This function returns a pointer to the memory block with a given * identifier. NULL is returned if the given identifier is not active. * Parameters: * id * The identifier for an active memory block. * Returned Value: * The pointer to the memory block. NULL is returned if no active memory * with the given ID can be found. Note, this is always a genuine C * pointer (even for public Object pointers). *- */ Memory *next; void *ret; ret = NULL; next = Active_List; while( next ) { if( next->id == id ) { ret = next + 1; break; } } return ret; } void astMemoryAlarm_( const char *verb ){ /* *+ * Name: * astMemoryAlarm * Purpose: * Called when a watched memory ID is used. * Type: * Protected function. * Synopsis: * #include "memory.h" * void astMemoryAlarm( const char *verb ) * Description: * This function is called when a watched memory ID is used. See * astWatchMemory. * Parameters: * verb * Text to include in message. *- */ printf( "astMemoryAlarm: Memory id %d has been %s.\n", Watched_ID, verb ); } void astMemoryStats_( int reset, size_t *peak, size_t *current, int *status ) { /* *+ * Name: * astMemoryStats * Purpose: * Return the current and peak AST memory usage. * Type: * Protected function. * Synopsis: * #include "memory.h" * astMemoryStats( int reset, size_t *peak, size_t *current ) * Description: * This function returns the current amount of memory allocated * using AST memory management functions, and the peak amount of * simultaneously allocated memory since the last time the peak value * was reset. * Parameters: * reset * If non-zero, the peak value is reset to the current usage * upon return. * peak * Address at which to return the peak memory usage since the last * reset, in bytes. * current * Address at which to return the current memory usage, in bytes. *- */ LOCK_DEBUG_MUTEX; if( peak ) *peak = Peak_Usage; if( current ) *current = Current_Usage; if( reset ) Peak_Usage = Current_Usage; UNLOCK_DEBUG_MUTEX; } void astMemoryWarning_( size_t threshold, int *status ) { /* *+ * Name: * astMemoryWarning * Purpose: * Issues a warning memory goes over a specified threshold. * Type: * Protected function. * Synopsis: * #include "memory.h" * astMemoryWarning( size_t threshold ) * Description: * This function prints a warning message to standard output if the * AST memory usage exceeds the specified threshold. * Parameters: * threshold * The memory allocation, in bytes, at which a warning should be issued, * Supply zero to suppress warnings. * Notes: * - This function is used to reset the threshold to zero when the first * warning is issued in order to prevent a flood of warnings appearing. * Therefore, setting a debugger breakpoint in this function * ("astMemoryWarning_" - do not forget the trailing underscore) * allows you to locate the point at which memory allocation first * exceeds the threshold. *- */ LOCK_DEBUG_MUTEX; Warn_Usage = threshold; UNLOCK_DEBUG_MUTEX; } void astMemoryUse_( const void *ptr, const char *verb, int *status ){ /* *+ * Name: * astMemoryUse * Purpose: * Called to report the use of a memory block pointer. * Type: * Protected function. * Synopsis: * #include "memory.h" * void astMemoryUse( void *ptr, const char *verb ) * Description: * If the supplied memory block is being watched, astMemoryAlarm is * called to report the use of the pointer. The reported text includes * the supplied "verb". A memory block can be watched by calling * astWatchMemory. * Parameters: * ptr * A pointer to the memory block being used. The pointer must have * been returned by one of the AST memory management functions (e.g. * astMalloc, astRealloc, etc). * verb * A verb indicating what is being done to the pointer. *- */ astDECLARE_GLOBALS astGET_GLOBALS(NULL); if( ptr && astMemoryId( ptr ) == Watched_ID ) { if( !Quiet_Use || !strcmp( verb, ISSUED ) || !strcmp( verb, FREED ) ) { astMemoryAlarm( verb ); } } } int astMemoryTune_( const char *name, int value, int *status ){ /* *+ * Name: * astMemoryTune * Purpose: * Set a tuning parameter for the memory debugging functions. * Type: * Protected function. * Synopsis: * #include "memory.h" * int astMemoryTune( const char *name, int value ) * Description: * There are a few tuning parameters which control the behaviour of * the memory debugging functions. This function allows these tuning * parameters to be queried or set. * Parameters: * name * The name of the tuning parameter to query or set. Valid names are: * * "Keep_ID": A boolean flag indicating if a new ID should be issued * for a cached memory block each time it is returned by astMalloc? * Otherwise, the same ID value is used throughtout the life of a * memory block. Default is zero (false). * * "List_Cache": A boolean flag which if non-zero (true) causes the * ID of every memory block in the cache to be reported when the * cache is emptied by astFlushMemory. * * "Quiet_Use": A boolean flag controlling the number of reports issued * when a memory block is being watched (see astWatchMemory). If * non-zero (true), then the only events which are reported are the * issuing of a memory block pointer by astMalloc or astRealloc,and * the freeing (or caching) of a memory block by astFree. If Quiet_Use * is zero (the default), then additional reports are made for * memory blocks used to hold AST Objects whenever the Object is * copied, cloned, or checked. * value * The new value for the tuning parameter. If AST__TUNULL is * supplied, the original value is left unchanged. * Returned Value: * The original value of the tuning parameter. *- */ int result = AST__TUNULL; if( name ) { if( astChrMatch( name, "Keep_ID" ) ) { result = Keep_ID; if( value != AST__TUNULL ) Keep_ID = value; } else if( astChrMatch( name, "Quiet_Use" ) ) { result = Quiet_Use; if( value != AST__TUNULL ) Quiet_Use = value; } else if( astChrMatch( name, "List_Cache" ) ) { result = List_Cache; if( value != AST__TUNULL ) List_Cache = value; } else if( astOK ) { astError( AST__TUNAM, "astMemoryTune: Unknown AST memory tuning " "parameter specified \"%s\".", status, name ); } } return result; } void astBeginPM_( int *status ) { /* *+ * Name: * astBeginPM * Purpose: * Start a block of permanent memory allocations. * Type: * Protected function. * Synopsis: * #include "memory.h" * astBeginPM * Description: * This function indicates that all memory allocations made by calls * to other functions in this module (e.g. astMalloc), up to the * astEndPM call which matches the astBeginPM call, will not usually * be freed explicitly. Matching astBeginPM/astEndPM calls should be * used to enclose all code which allocates memory which is never * freed explitly by AST. Such memory allocations may be freed if * required, using the astFlushMemory function (but note this should * only be done once all use of AST by an application has finished). * * Matching pairs of astBeginPM/astEndPM calls can be nested up to a * maximum depth of 20. *- */ LOCK_DEBUG_MUTEX; /* The global Perm_Mem flag indicates whether or not subsequent memory management functions in this module should store pointers to allocated blocks in the PM_List array. Push the current value of this flag onto a stack, and set the value to 1. */ if( PM_Stack_Size >= PM_STACK_MAXSIZE ){ if( astOK ) { astError( AST__INTER, "astBeginPM: Maximum stack size has been " "exceeded (internal AST programming error)." , status); } } else { PM_Stack[ PM_Stack_Size++ ] = Perm_Mem; Perm_Mem = 1; } UNLOCK_DEBUG_MUTEX; } void astEndPM_( int *status ) { /* *+ * Name: * astEndPM * Purpose: * End a block of permanent memory allocations. * Type: * Protected function. * Synopsis: * #include "memory.h" * astEndPM * Description: * This function indicates the end of the block of permanent memory * allocations started by the matching call to astBeginPM. See * astBeginPM for further details. *- */ LOCK_DEBUG_MUTEX; /* The global Perm_Mem flag indicates whether or not subsequent memory management functions in this module should store pointers to allocated blocks in the PM_List array. Pop the value from the top of this stack. */ if( PM_Stack_Size == 0 ){ if( astOK ) { astError( AST__INTER, "astEndPM: astEndPM called without " "matching astBeginPM (internal AST programming error)." , status); } } else { Perm_Mem = PM_Stack[ --PM_Stack_Size ]; } UNLOCK_DEBUG_MUTEX; } void astFlushMemory_( int leak, int *status ) { /* *+ * Name: * astFlushMemory * Purpose: * Free all permanent and cached memory blocks. * Type: * Protected function. * Synopsis: * #include "memory.h" * astFlushMemory( int leak ); * Description: * This function should only be called once all use of AST by an * application has finished. It frees any allocated but currently * unused memory stored in an internal cache of unused memory * pointers. (Note, it does not free any memory used permanently to * store internal AST state information). * * It is not normally necessary to call this function since the memory * will be freed anyway by the operating system when the application * terminates. However, it can be called if required in order to * stop memory management tools such as valgrind from reporting that * the memory has not been freed at the end of an application. * * In addition, if "leak" is non-zero this function will also report * an error if any active AST memory pointers remain which have not * been freed (other than pointers for the cached and permanent * memory described above). Leakage of active memory blocks can be * investigated using astActiveMemory and astWatchMemory. * Parameters: * leak * Should an error be reported if any non-permanent memory blocks * are found to be active? *- */ /* Local Variables: */ Memory *next; int nact; int istat; /* Empty the cache. */ astMemCaching( astMemCaching( AST__TUNULL ) ); /* Free and count all non-permanent memory blocks. */ nact = 0; next = Active_List; while( Active_List ) { next = Active_List->next; if( !Active_List->perm ) { nact++; FREE( Active_List ); } Active_List = next; } /* Report an error if any active pointers remained. if an error has already occurred, use the existing status value. */ if( nact && leak ){ if( astOK ) { istat = AST__INTER; } else { istat = astStatus; } astError( istat, "astFlushMemory: %d AST memory blocks have not " "been released (programming error).", status, nact ); } else { printf("astFlushMemory: All AST memory blocks were released correctly.\n" ); } } void astCheckMemory_( int *status ) { /* *+ * Name: * astCheckMemory * Purpose: * Check that all AST memory blocks have been released. * Type: * Protected function. * Synopsis: * #include "memory.h" * astCheckMemory * Description: * This macro reports an error if any active AST memory pointers * remain which have not been freed (other than pointers for cached * and "permanently allocated" memory). Leakage of active memory blocks * can be investigated using astActiveMemory and astWatchMemory. *- */ /* Local Variables: */ Memory *next; int nact; int istat; /* Empty the cache. */ astMemCaching( astMemCaching( AST__TUNULL ) ); /* Count all non-permanent memory blocks. */ nact = 0; next = Active_List; while( Active_List ) { next = Active_List->next; if( !Active_List->perm ) nact++; Active_List = next; } /* Report an error if any active pointers remained. If an error has already occurred, use the existing status value. */ if( nact ){ if( astOK ) { istat = AST__INTER; } else { istat = astStatus; } astError( istat, "astCheckMemory: %d AST memory blocks have not " "been released (programming error).", status, nact ); } else { printf("astCheckMemory: All AST memory blocks were released correctly.\n" ); } } static void Issue( Memory *mem, int *status ) { /* * Name: * Issue * Purpose: * Indicate that a pointer to a memory block has been issued. * Type: * Private function. * Synopsis: * #include "memory.h" * void Issue( Memory *mem, int *status ); * Description: * Initialises the extra debug items in the Memory header, and adds the * Memory structure to the list of active memory blocks. * Parameters: * mem * Pointer to the Memory structure. * status * Pointer to the inherited status value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Return if no pointer was supplied. */ if( !mem ) return; LOCK_DEBUG_MUTEX; astGET_GLOBALS(NULL); /* Store a unique identifier for this pointer. Unless global Keep_ID is non-zero, a new identifier is used each time the pointer becomes active (i.e. each time it is remove from the cache or malloced). */ if( !Keep_ID || mem->id < 0 ) mem->id = ++Next_ID; /* Record the file name and line number where it was issued. */ if( AST__GLOBALS && AST__GLOBALS->Error.Current_File ) { strncpy( mem->file, AST__GLOBALS->Error.Current_File, sizeof(mem->file) ); mem->file[ sizeof(mem->file) - 1 ] = 0; mem->line = AST__GLOBALS->Error.Current_Line; } else { mem->file[ 0 ] = 0; mem->line = 0; } /* Indicate if this is a permanent memory block (i.e. it will usually not be freed by AST). */ mem->perm = Perm_Mem; /* Add it to the double linked list of active pointers. */ mem->next = Active_List; mem->prev = NULL; if( Active_List ) Active_List->prev = mem; Active_List = mem; /* Report that the pointer is being issued. */ astMemoryUse( (void *) mem + SIZEOF_MEMORY, ISSUED ); /* Update the current and peak memory usage. */ Current_Usage += mem->size + SIZEOF_MEMORY; if( Current_Usage > Peak_Usage ) Peak_Usage = Current_Usage; /* If the current allocation is above the threshold set using astMemoryWarning, issue a warning message, and then reset the threshold to zero to prevent further warnings being issued, and to allow a debugger breakpoint to be set. */ if( Current_Usage > Warn_Usage && Warn_Usage > 0 ) { printf( "Warning - AST memory allocation has exceeded %ld bytes\n", Warn_Usage ); astMemoryWarning( 0 ); } UNLOCK_DEBUG_MUTEX; } static void DeIssue( Memory *mem, int *status ) { /* * Name: * DeIssue * Purpose: * Indicate that a pointer to a memory block has been freed. * Type: * Private function. * Synopsis: * #include "memory.h" * void DeIssue( Memeory *mem, int *status ); * Description: * Initialises the extra debug items in the Memory header, and adds the * Memory structure to the list of active memory blocks. * Parameters: * mem * Pointer to the Memory structure. * status * Pointer to the inherited status value. */ /* Local Variables: */ astDECLARE_GLOBALS Memory *next; Memory *prev; /* Return if no pointer was supplied. */ if( !mem ) return; LOCK_DEBUG_MUTEX; astGET_GLOBALS(NULL); /* Report that the pointer is being freed. */ astMemoryUse( (void *) mem + SIZEOF_MEMORY, FREED ); /* Remove the block from the double linked list of active pointers. */ next = mem->next; prev = mem->prev; if( prev ) prev->next = next; if( next ) next->prev = prev; if( mem == Active_List ) Active_List = next; mem->next = NULL; mem->prev = NULL; /* Update the current memory usage. */ Current_Usage -= mem->size + SIZEOF_MEMORY; UNLOCK_DEBUG_MUTEX; } #endif /* The next functions are used only when profiling AST application. */ #ifdef MEM_PROFILE void astStartTimer_( const char *file, int line, const char *name, int *status ) { /* *+ * Name: * astStartTimer * Purpose: * Measure the time spent until the corresponding call to astStopTimer. * Type: * Protected function. * Synopsis: * #include "memory.h" * void astStartTimer( const char *name ); * Description: * This function looks for a timer with the specified name within the * current parent timer. If no timer with the given name is found, a * new timer is created and initialised to zero. The current absolute * time (elapsed, user and system) is recorded in the timer. The new * timer then becomes the current timer. * Parameters: * name * A label for the timer. This should be unique within the * enclosing parent timer. * Notes: * - This function should only be used in a single-threaded environment. * - This function returns without action if timers are currently * disabled (see astEnableTimers). *- */ /* Local Variables: */ int n, found, i; AstTimer *t; struct tms buf; /* Check inherited status. Also return if timers are currently disabled. */ if( !Enable_Timers || *status != 0 ) return; /* See if a timer with the given name exists in the list of child timers within the current timer. */ found = 0; if( Current_Timer ) { for( i = 0; i < Current_Timer->nchild; i++ ) { t = Current_Timer->children[ i ]; if( !strcmp( t->name, name ) ) { found = 1; break; } } } /* If not, create and initialise one now, and add it into the list of children within the current timer. */ if( !found ) { t = astMalloc( sizeof( AstTimer ) ); t->id = Timer_Count++; t->et = 0; t->ut = 0; t->st = 0; t->nentry = 0; t->name = name; t->file = file; t->line = line; t->parent = Current_Timer; t->nchild = 0; t->children = NULL; if( Current_Timer ) { n = (Current_Timer->nchild)++; Current_Timer->children = astGrow( Current_Timer->children, sizeof( AstTimer *), Current_Timer->nchild ); Current_Timer->children[ n ] = t; } } /* Record the current absolute times (elapsed, user and system) within the new timer. */ t->e0 = times(&buf); t->u0 = buf.tms_utime; t->s0 = buf.tms_stime; /* Increment the number of entries into the timer. */ (t->nentry)++; /* Use the new timer as the current timer until the corresponding call to astStopTimer. */ Current_Timer = t; } void astEnableTimers_( int enable, int *status ) { /* *+ * Name: * astEnableTimers * Purpose: * Set a global flag indicating if the use of AST timers is enabled. * Type: * Protected function. * Synopsis: * #include "memory.h" * void astStartTimer( int enable ); * Description: * This function sets a global flag that enables otr disables the user * of AST Timers. If timers are disabled, the astStartTimer and * astStopTimer functions will return without action. * Parameters: * enable * If non-zero, timers will be used. * Notes: * - This function should only be used in a single-threaded environment. *- */ Enable_Timers = enable; } void astStopTimer_( int *status ) { /* *+ * Name: * astStopTimer * Purpose: * Record the time spent since the corresponding call to astStartTimer. * Type: * Protected function. * Synopsis: * #include "memory.h" * void astStopTimer; * Description: * This function obtains the time increments since the corresponding * call to astStartTimer, and adds these increments onto the total * times stored in the current timer. It then changes the current * timer to be the parent timer associated the current timer on entry. * * If the current timer on entry has no parent (i.e. is a top level * timer), the times spent in the top-level timer, and all its * descendent timers, are displayed. * Notes: * - This function should only be used in a single-threaded environment. * - This function returns without action if timers are currently * disabled (see astEnableTimers). *- */ /* Local Variables: */ AstTimer *flat; AstTimer *t; int i; int nflat; struct tms buf; /* Check inherited status. Also return if timers are currently disabled. */ if( !Enable_Timers || !Current_Timer || *status != 0 ) return; /* Get the current absolute times, and thus find the elapsed times since the corresponding call to astStartTimer. Use these elapsed times to increment the total times spent in the timer. */ Current_Timer->et += ( times(&buf) - Current_Timer->e0 ); Current_Timer->st += ( buf.tms_stime - Current_Timer->s0 ); Current_Timer->ut += ( buf.tms_utime - Current_Timer->u0 ); /* If this is a top level timer, display the times spent in the current timer, and in all its descendent timers. This also frees the memory used by the timers. */ if( !Current_Timer->parent ) { flat = NULL; nflat = 0; Current_Timer = ReportTimer( Current_Timer, 0, &flat, &nflat, status ); /* Sort and display the flat list of timers, then free the memory used by the flat list. */ qsort( flat, nflat, sizeof( AstTimer), CompareTimers2 ); printf("\n\n"); t = flat; for( i = 0; i < nflat; i++,t++ ) { printf( "%s (%s:%d): ", t->name, t->file, t->line ); printf( "elapsed=%ld ", (long int) t->et ); /* printf( "system=%ld ", (long int) t->st ); printf( "user=%ld ", (long int) t->ut ); */ printf( "calls=%d ", t->nentry ); printf("\n"); } flat = astFree( flat ); /* If this is not a top level timer, restore the parent timer as the curent timer. */ } else { Current_Timer = Current_Timer->parent; } } static AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat, int *nflat, int *status ) { /* * Name: * ReportTimer * Purpose: * Free and report the times spent in a given timer, and all descendents. * Type: * Private function. * Synopsis: * #include "memory.h" * AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat, * int *nflat, int *status ) * Description: * This routines reports to standard output the times spent in the * supplied timer. It then calls itself recursively to report the times * spent in each of the child timers of the supplied timer. * * It also frees the memory used to hold the supplied timer. * Parameters: * t * Pointer to the AstTimer structure. * ind * The number of spaces of indentation to display before the timer * details. * flat * Address of a pointer to the start of an array of AstTimers. The * number of elements in this array is given by "*nflat". Each * Timer in this array holds the accumulated total for all entries * into a given timer, from all parent contexts. * nflat * Address of an int holding the current length of the "*flat" array. * status * Pointer to the inherited status value. */ /* Local Variables: */ int found; int i; AstTimer *ft; AstTimer *parent; /* Check inherited status */ if( *status != 0 ) return NULL; /* Display a single line of text containing the times stored in the supplied timer, preceded by the requested number of spaces. */ for( i = 0; i < ind; i++ ) printf(" "); printf( "%s (%s:%d): ", t->name, t->file, t->line ); printf( "id=%d ", t->id ); printf( "elapsed=%ld ", (long int) t->et ); /* printf( "system=%ld ", (long int) t->st ); printf( "user=%ld ", (long int) t->ut ); */ printf( "calls=%d ", t->nentry ); /* If there are any children, end the line with an opening bvrace. */ if( t->nchild ) printf("{"); printf("\n"); /* If there is more than one child, sort them into descending order of elapsed time usage. */ if( t->nchild > 1 ) qsort( t->children, t->nchild, sizeof( AstTimer * ), CompareTimers ); /* Increment the indentation and call this function recursively to display and free each child timer. */ ind += 3; for( i = 0; i < t->nchild; i++ ) { (t->children)[ i ] = ReportTimer( (t->children)[ i ], ind, flat, nflat, status ); } /* Delimit the children by displaying a closing brace. */ if( t->nchild ) { for( i = 0; i < ind - 3; i++ ) printf(" "); printf("}\n"); } /* See if this timer is contained within itself at a higher level. */ parent = t->parent; while( parent && ( parent->line != t->line || strcmp( parent->file, t->file ) ) ) { parent = parent->parent; } /* If not, search for a timer in the "flat" array of timers that has the same source file and line number. */ if( !parent ) { found = 0; ft = *flat; for( i = 0; i < *nflat; i++, ft++ ) { if( ft->line == t->line && !strcmp( ft->file, t->file ) ) { found = 1; break; } } /* If not found, add a new timer to the end of the "flat" array and initialise it. */ if( !found ) { i = (*nflat)++; *flat = astGrow( *flat, *nflat, sizeof( AstTimer ) ); ft = (*flat) + i; ft->id = 0; ft->et = t->et; ft->ut = t->ut; ft->st = t->st; ft->nentry = t->nentry; ft->name = t->name; ft->file = t->file; ft->line = t->line; ft->parent = NULL; ft->nchild = 0; ft->children = NULL; /* If found, increment the properites to include the supplied timer. */ } else { ft->et += t->et; ft->ut += t->ut; ft->st += t->st; ft->nentry += t->nentry; } } /* Free the memory used by the supplied timer. */ t->children = astFree( t->children ); return astFree( t ); } static int CompareTimers( const void *a, const void *b ){ return ((*((AstTimer **) b ))->et) - ((*((AstTimer **) a ))->et); } static int CompareTimers2( const void *a, const void *b ){ return (((AstTimer *) b )->et) - (((AstTimer *) a )->et); } #endif ./ast-7.3.3/grf3d_pgplot.c0000644000175000017500000030245712262533650013713 0ustar olesoles/* * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * 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 #include #include #include #include /* 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 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 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: * PG3DForward * 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_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; } ./ast-7.3.3/slamap.c0000644000175000017500000055003512262533650012573 0ustar olesoles/* *class++ * Name: * SlaMap * Purpose: * Sequence of celestial coordinate conversions. * Constructor Function: c astSlaMap (also see astSlaAdd) f AST_SLAMAP (also see AST_SLAADD) * Description: * An SlaMap is a specialised form of Mapping which can be used to * represent a sequence of conversions between standard celestial * (longitude, latitude) coordinate systems. * * When an SlaMap is first created, it simply performs a unit c (null) Mapping on a pair of coordinates. Using the astSlaAdd f (null) Mapping on a pair of coordinates. Using the AST_SLAADD c function, a series of coordinate conversion steps may then be f routine, a series of coordinate conversion steps may then be * added, selected from those provided by the SLALIB Positional * Astronomy Library (Starlink User Note SUN/67). This allows * multi-step conversions between a variety of celestial coordinate * systems to be assembled out of the building blocks provided by * SLALIB. * * For details of the individual coordinate conversions available, c see the description of the astSlaAdd function. f see the description of the AST_SLAADD routine. * Inheritance: * The SlaMap class inherits from the Mapping class. * Attributes: * The SlaMap class does not define any new attributes beyond those * which are applicable to all Mappings. * Functions: c In addition to those functions applicable to all Mappings, the c following function may also be applied to all SlaMaps: f In addition to those routines applicable to all Mappings, the f following routine may also be applied to all SlaMaps: * c - astSlaAdd: Add a celestial coordinate conversion to an SlaMap f - AST_SLAADD: Add a celestial coordinate conversion to an SlaMap * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2013 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 25-APR-1996 (RFWS): * Original version. * 28-MAY-1996 (RFWS): * Fixed bug in argument order to palMappa for AST__SLA_AMP case. * 26-SEP-1996 (RFWS): * Added external interface and I/O facilities. * 23-MAY-1997 (RFWS): * Over-ride the astMapMerge method. * 28-MAY-1997 (RFWS): * Use strings to specify conversions for the public interface * and convert to macros (from an enumerated type) for the * internal representation. Tidy the public prologues. * 8-JAN-2003 (DSB): * - Changed private InitVtab method to protected astInitSlaMapVtab * method. * - Included STP conversion functions. * 11-JUN-2003 (DSB): * - Added HFK5Z and FK5HZ conversion functions. * 28-SEP-2003 (DSB): * - Added HEEQ and EQHE conversion functions. * 2-DEC-2004 (DSB): * - Added J2000H and HJ2000 conversion functions. * 15-AUG-2005 (DSB): * - Added H2E and E2H conversion functions. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 22-FEB-2006 (DSB): * Cache results returned by palMappa in order to increase speed. * 10-MAY-2006 (DSB): * Override astEqual. * 31-AUG-2007 (DSB): * - Modify H2E and E2H conversion functions so that they convert to * and from apparent (HA,Dec) rather than topocentric (HA,Dec) (i.e. * include a correction for diurnal aberration). This requires an * extra conversion argument holding the magnitude of the diurnal * aberration vector. * - Correct bug in the simplification of adjacent AMP and MAP * conversions. * 15-NOV-2013 (DSB): * Fix bug in merging of adjacent AMP and MAP conversions (MapMerge * did not take account of the fact that the arguments for these * two conversions are stored in swapped order). *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SlaMap /* Codes to identify SLALIB sky coordinate conversions. */ #define AST__SLA_NULL 0 /* Null value */ #define AST__SLA_ADDET 1 /* Add E-terms of aberration */ #define AST__SLA_SUBET 2 /* Subtract E-terms of aberration */ #define AST__SLA_PREBN 3 /* Bessel-Newcomb (FK4) precession */ #define AST__SLA_PREC 4 /* Apply IAU 1975 (FK5) precession model */ #define AST__SLA_FK45Z 5 /* FK4 to FK5, no proper motion or parallax */ #define AST__SLA_FK54Z 6 /* FK5 to FK4, no proper motion or parallax */ #define AST__SLA_AMP 7 /* Geocentric apparent to mean place */ #define AST__SLA_MAP 8 /* Mean place to geocentric apparent */ #define AST__SLA_ECLEQ 9 /* Ecliptic to J2000.0 equatorial */ #define AST__SLA_EQECL 10 /* Equatorial J2000.0 to ecliptic */ #define AST__SLA_GALEQ 11 /* Galactic to J2000.0 equatorial */ #define AST__SLA_EQGAL 12 /* J2000.0 equatorial to galactic */ #define AST__SLA_GALSUP 13 /* Galactic to supergalactic */ #define AST__SLA_SUPGAL 14 /* Supergalactic to galactic */ #define AST__HPCEQ 15 /* Helioprojective-Cartesian to J2000.0 equatorial */ #define AST__EQHPC 16 /* J2000.0 equatorial to Helioprojective-Cartesian */ #define AST__HPREQ 17 /* Helioprojective-Radial to J2000.0 equatorial */ #define AST__EQHPR 18 /* J2000.0 equatorial to Helioprojective-Radial */ #define AST__SLA_HFK5Z 19 /* ICRS to FK5 J2000.0, no pm or parallax */ #define AST__SLA_FK5HZ 20 /* FK5 J2000.0 to ICRS, no pm or parallax */ #define AST__HEEQ 21 /* Helio-ecliptic to equatorial */ #define AST__EQHE 22 /* Equatorial to helio-ecliptic */ #define AST__J2000H 23 /* Dynamical J2000 to ICRS */ #define AST__HJ2000 24 /* ICRS to dynamical J2000 */ #define AST__SLA_DH2E 25 /* Horizon to equatorial coordinates */ #define AST__SLA_DE2H 26 /* Equatorial coordinates to horizon */ #define AST__R2H 27 /* RA to hour angle */ #define AST__H2R 28 /* Hour to RA angle */ /* Maximum number of arguments required by an SLALIB conversion. */ #define MAX_SLA_ARGS 4 /* The alphabet (used for generating keywords for arguments). */ #define ALPHABET "abcdefghijklmnopqrstuvwxyz" /* Angle conversion (PI is from the SLALIB slamac.h file) */ #define PI 3.1415926535897932384626433832795028841971693993751 #define PIBY2 (PI/2.0) #define D2R (PI/180.0) #define R2D (180.0/PI) #define AS2R (PI/648000.0) /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "pal.h" /* SLALIB interface */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate Mappings (parent class) */ #include "wcsmap.h" /* Required for AST__DPI */ #include "unitmap.h" /* Unit (null) Mappings */ #include "slamap.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->Eq_Cache = AST__BAD; \ globals->Ep_Cache = AST__BAD; \ /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SlaMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SlaMap,Class_Init) #define class_vtab astGLOBAL(SlaMap,Class_Vtab) #define eq_cache astGLOBAL(SlaMap,Eq_Cache) #define ep_cache astGLOBAL(SlaMap,Ep_Cache) #define amprms_cache astGLOBAL(SlaMap,Amprms_Cache) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* A cache used to store the most recent results from palMappa in order to avoid continuously recalculating the same values. */ static double eq_cache = AST__BAD; static double ep_cache = AST__BAD; static double amprms_cache[ 21 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSlaMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSlaMap *astSlaMapId_( int, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *CvtString( int, const char **, int *, const char *[ MAX_SLA_ARGS ], int * ); static int CvtCode( const char *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void AddSlaCvt( AstSlaMap *, int, const double *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void De2h( double, double, double, double, double *, double *, int * ); static void Dh2e( double, double, double, double, double *, double *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void Earth( double, double[3], int * ); static void SlaAdd( AstSlaMap *, const char *, const double[], int * ); static void SolarPole( double, double[3], int * ); static void Hpcc( double, double[3], double[3][3], double[3], int * ); static void Hprc( double, double[3], double[3][3], double[3], int * ); static void Hgc( double, double[3][3], double[3], int * ); static void Haec( double, double[3][3], double[3], int * ); static void Haqc( double, double[3][3], double[3], int * ); static void Gsec( double, double[3][3], double[3], int * ); static void STPConv( double, int, int, int, double[3], double *[3], int, double[3], double *[3], int * ); static void J2000H( int, int, double *, double *, int * ); static int GetObjSize( AstObject *, int * ); /* Member functions. */ /* ================= */ static void De2h( double ha, double dec, double phi, double diurab, double *az, double *el, int *status ){ /* Not quite like slaDe2h since it converts from apparent (ha,dec) to topocentric (az,el). This includes a correction for diurnal aberration. The magnitude of the diurnal aberration vector should be supplied in parameter "diurab". The extra code is taken from the Fortran routine SLA_AOPQK. */ /* Local Variables: */ double a; double cd; double ch; double cp; double f; double r; double sd; double sh; double sp; double x; double xhd; double xhdt; double y; double yhd; double yhdt; double z; double zhd; double zhdt; /* Check inherited status */ if( !astOK ) return; /* Pre-compute common values */ sh = sin( ha ); ch = cos( ha ); sd = sin( dec ); cd = cos( dec ); sp = sin( phi ); cp = cos( phi ); /* Components of cartesian (-ha,dec) vector. */ xhd = ch*cd; yhd = -sh*cd; zhd = sd; /* Modify the above vector to apply diurnal aberration. */ f = ( 1.0 - diurab*yhd ); xhdt = f*xhd; yhdt = f*( yhd + diurab ); zhdt = f*zhd; /* Convert to cartesian (az,el). */ x = -xhdt*sp + zhdt*cp; y = yhdt; z = xhdt*cp + zhdt*sp; /* Convert to spherical (az,el). */ r = sqrt( x*x + y*y ); if( r == 0.0 ) { a = 0.0; } else { a = atan2( y, x ); } while( a < 0.0 ) a += 2*AST__DPI; *az = a; *el = atan2( z, r ); } static void Dh2e( double az, double el, double phi, double diurab, double *ha, double *dec, int *status ){ /* Not quite like slaDh2e since it converts from topocentric (az,el) to apparent (ha,dec). This includes a correction for diurnal aberration. The magnitude of the diurnal aberration vector should be supplied in parameter "diurab". The extra code is taken from the Fortran routine SLA_OAPQK. */ /* Local Variables: */ double ca; double ce; double cp; double f; double r; double sa; double se; double sp; double x; double xmhda; double y; double ymhda; double z; double zmhda; /* Check inherited status */ if( !astOK ) return; /* Pre-compute common values. */ sa = sin( az ); ca = cos( az ); se = sin( el ); ce = cos( el ); sp = sin( phi ); cp = cos( phi ); /* Cartesian (az,el) to Cartesian (ha,dec) - note, +ha, not -ha. */ xmhda = -ca*ce*sp + se*cp; ymhda = -sa*ce; zmhda = ca*ce*cp + se*sp; /* Correct this vector for diurnal aberration. Since the above expressions produce +ha rather than -ha, we do not negate "diurab" before using it. Compare this to SLA_AOPQK. */ f = ( 1 - diurab*ymhda ); x = f*xmhda; y = f*( ymhda + diurab ); z = f*zmhda; /* Cartesian (ha,dec) to spherical (ha,dec). */ r = sqrt( x*x + y*y ); if( r == 0.0 ) { *ha = 0.0; } else { *ha = atan2( y, x ); } *dec = atan2( z, r ); } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two SlaMaps are equivalent. * Type: * Private function. * Synopsis: * #include "slamap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * SlaMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two SlaMaps are equivalent. * Parameters: * this * Pointer to the first Object (a SlaMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the SlaMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSlaMap *that; AstSlaMap *this; const char *argdesc[ MAX_SLA_ARGS ]; const char *comment; int i, j; int nargs; int nin; int nout; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two SlaMap structures. */ this = (AstSlaMap *) this_object; that = (AstSlaMap *) that_object; /* Check the second object is a SlaMap. We know the first is a SlaMap since we have arrived at this implementation of the virtual function. */ if( astIsASlaMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNin( that ) == nin && astGetNout( that ) == nout ) { /* If the Invert flags for the two SlaMaps differ, it may still be possible for them to be equivalent. First compare the SlaMaps if their Invert flags are the same. In this case all the attributes of the two SlaMaps must be identical. */ if( astGetInvert( this ) == astGetInvert( that ) ) { if( this->ncvt == that->ncvt ) { result = 1; for( i = 0; i < this->ncvt && result; i++ ) { if( this->cvttype[ i ] != that->cvttype[ i ] ) { result = 0; } else { CvtString( this->cvttype[ i ], &comment, &nargs, argdesc, status ); for( j = 0; j < nargs; j++ ) { if( !astEQUAL( this->cvtargs[ i ][ j ], that->cvtargs[ i ][ j ] ) ){ result = 0; break; } } } } } /* If the Invert flags for the two SlaMaps differ, the attributes of the two SlaMaps must be inversely related to each other. */ } else { /* In the specific case of a SlaMap, Invert flags must be equal. */ result = 0; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "slamap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * SlaMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied SlaMap, * in bytes. * Parameters: * this * Pointer to the SlaMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSlaMap *this; /* Pointer to SlaMap structure */ int result; /* Result value to return */ int cvt; /* Loop counter for coordinate conversions */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the SlaMap structure. */ this = (AstSlaMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); for ( cvt = 0; cvt < this->ncvt; cvt++ ) { result += astTSizeOf( this->cvtargs[ cvt ] ); result += astTSizeOf( this->cvtextra[ cvt ] ); } result += astTSizeOf( this->cvtargs ); result += astTSizeOf( this->cvtextra ); result += astTSizeOf( this->cvttype ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static void AddSlaCvt( AstSlaMap *this, int cvttype, const double *args, int *status ) { /* * Name: * AddSlaCvt * Purpose: * Add a coordinate conversion step to an SlaMap. * Type: * Private function. * Synopsis: * #include "slamap.h" * void AddSlaCvt( AstSlaMap *this, int cvttype, const double *args ) * Class Membership: * SlaMap member function. * Description: * This function allows one of the sky coordinate conversions * supported by SLALIB to be appended to an SlaMap. When an SlaMap * is first created (using astSlaMap), it simply performs a unit * mapping. By using AddSlaCvt repeatedly, a series of sky * coordinate conversions may then be specified which the SlaMap * will subsequently perform in sequence. This allows a complex * coordinate conversion to be assembled out of the basic building * blocks provided by SLALIB. The SlaMap will also perform the * inverse coordinate conversion (applying the individual * conversion steps in reverse) if required. * Parameters: * this * Pointer to the SlaMap. * cvttype * A code to identify which sky coordinate conversion is to be * appended. See the "SLALIB Coordinate Conversions" section * for details of those available. * args * Pointer to an array of double containing the argument values * required to fully specify the required coordinate * conversion. The number of arguments depends on the conversion * (see the "SLALIB Coordinate Conversions" section for * details). This value is ignored and may be NULL if no * arguments are required. * Returned Value: * void. * SLALIB Coordinate Conversions: * The following values may be supplied for the "cvttype" parameter * in order to specify the sky coordinate conversion to be * performed. In each case the value is named after the SLALIB * routine that performs the conversion, and the relevant SLALIB * documentation should be consulted for full details. * * The argument(s) required to fully specify each conversion are * indicated in parentheses after each value. Values for these * should be given in the array pointed at by "args". The argument * names given match the corresponding SLALIB function arguments * (in the Fortran 77 documentation - SUN/67) and their values * should be given using the same units, time scale, calendar, * etc. as in SLALIB. * * AST__SLA_ADDET( EQ ) * Add E-terms of aberration. * AST__SLA_SUBET( EQ ) * Subtract E-terms of aberration. * AST__SLA_PREBN( BEP0, BEP1 ) * Apply Bessel-Newcomb pre-IAU 1976 (FK4) precession model. * AST__SLA_PREC( EP0, EP1 ) * Apply IAU 1975 (FK5) precession model. * AST__SLA_FK45Z( BEPOCH ) * Convert FK4 to FK5 (no proper motion or parallax). * AST__SLA_FK54Z( BEPOCH ) * Convert FK5 to FK4 (no proper motion or parallax). * AST__SLA_AMP( DATE, EQ ) * Convert geocentric apparent to mean place. * AST__SLA_MAP( EQ, DATE ) * Convert mean place to geocentric apparent. * AST__SLA_ECLEQ( DATE ) * Convert ecliptic coordinates to J2000.0 equatorial. * AST__SLA_EQECL( DATE ) * Convert equatorial J2000.0 to ecliptic coordinates. * AST__SLA_GALEQ( ) * Convert galactic coordinates to J2000.0 equatorial. * AST__SLA_EQGAL( ) * Convert J2000.0 equatorial to galactic coordinates. * AST__SLA_HFK5Z( JEPOCH ) * Convert ICRS coordinates to J2000.0 equatorial (no proper * motion or parallax). * AST__SLA_FK5HZ( JEPOCH ) * Convert J2000.0 equatorial to ICRS coordinates (no proper * motion or parallax). * AST__SLA_GALSUP( ) * Convert galactic to supergalactic coordinates. * AST__SLA_SUPGAL( ) * Convert supergalactic coordinates to galactic. * AST__HPCEQ( DATE, OBSX, OBSY, OBSZ ) * Convert Helioprojective-Cartesian coordinates to J2000.0 * equatorial. This is not a native SLALIB conversion, but is * implemented by functions within this module. The DATE argument * is the MJD defining the HPC coordinate system. The OBSX, OBSY * and OBSZ arguments are the AST__HAEC coordinates of the observer. * AST__EQHPC( DATE, OBSX, OBSY, OBSZ ) * Convert J2000.0 equatorial coordinates to Helioprojective-Cartesian. * AST__HPREQ( DATE, OBSX, OBSY, OBSZ ) * Convert Helioprojective-Radial coordinates to J2000.0 equatorial. * AST__EQHPR( DATE, OBSX, OBSY, OBSZ ) * Convert J2000.0 equatorial coordinates to Helioprojective-Radial. * AST__HEEQ( DATE ) * Convert helio-ecliptic to ecliptic coordinates. * AST__EQHE( DATE ) * Convert ecliptic to helio-ecliptic coordinates. * AST__J2000H( ) * Convert dynamical J2000 to ICRS. * AST__HJ2000( ) * Convert ICRS to dynamical J2000. * AST__SLA_DH2E( LAT, DIURAB ) * Convert horizon to equatorial coordinates * AST__SLA_DE2H( LAT, DIURAB ) * Convert equatorial to horizon coordinates * AST__R2H( LAST ) * Convert RA to Hour Angle. * AST__H2R( LAST ) * Convert Hour Angle to RA. * Notes: * - The specified conversion is appended only if the SlaMap's * Invert attribute is zero. If it is non-zero, this function * effectively prefixes the inverse of the conversion specified * instead. * - Sky coordinate values are in radians (as for SLALIB) and all * conversions are performed using double arithmetic. */ /* Local Variables: */ const char *argdesc[ MAX_SLA_ARGS ]; /* Pointers to argument descriptions */ const char *comment; /* Pointer to comment string */ const char *cvt_string; /* Pointer to conversion type string */ int nargs; /* Number of arguments */ int ncvt; /* Number of coordinate conversions */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the coordinate conversion type and obtain the number of required arguments. */ cvt_string = CvtString( cvttype, &comment, &nargs, argdesc, status ); /* If the sky coordinate conversion type was not valid, then report an error. */ if ( astOK && !cvt_string ) { astError( AST__SLAIN, "AddSlaCvt(%s): Invalid SLALIB sky coordinate " "conversion type (%d).", status, astGetClass( this ), (int) cvttype ); } /* Note the number of coordinate conversions already stored in the SlaMap. */ if ( astOK ) { ncvt = this->ncvt; /* Extend the array of conversion types and the array of pointers to their argument lists to accommodate the new one. */ this->cvttype = (int *) astGrow( this->cvttype, ncvt + 1, sizeof( int ) ); this->cvtargs = (double **) astGrow( this->cvtargs, ncvt + 1, sizeof( double * ) ); this->cvtextra = (double **) astGrow( this->cvtextra, ncvt + 1, sizeof( double * ) ); /* If OK, allocate memory and store a copy of the argument list, putting a pointer to the copy into the SlaMap. */ if ( astOK ) { this->cvtargs[ ncvt ] = astStore( NULL, args, sizeof( double ) * (size_t) nargs ); this->cvtextra[ ncvt ] = NULL; } /* Store the conversion type and increment the conversion count. */ if ( astOK ) { this->cvttype[ ncvt ] = cvttype; this->ncvt++; } } } static int CvtCode( const char *cvt_string, int *status ) { /* * Name: * CvtCode * Purpose: * Convert a conversion type from a string representation to a code value. * Type: * Private function. * Synopsis: * #include "slamap.h" * int CvtCode( const char *cvt_string, int *status ) * Class Membership: * SlaMap member function. * Description: * This function accepts a string used to repersent one of the * SLALIB sky coordinate conversions and converts it into a code * value for internal use. * Parameters: * cvt_string * Pointer to a constant null-terminated string representing a * sky coordinate conversion. This is case sensitive and should * contain no unnecessary white space. * status * Pointer to the inherited status variable. * Returned Value: * The equivalent conversion code. If the string was not * recognised, the code AST__SLA_NULL is returned, without error. * Notes: * - A value of AST__SLA_NULL will be returned if this function is * invoked with the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ int result; /* Result value to return */ /* Initialise. */ result = AST__SLA_NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Test the string against each recognised value in turn and assign the result. */ if ( astChrMatch( cvt_string, "ADDET" ) ) { result = AST__SLA_ADDET; } else if ( astChrMatch( cvt_string, "SUBET" ) ) { result = AST__SLA_SUBET; } else if ( astChrMatch( cvt_string, "PREBN" ) ) { result = AST__SLA_PREBN; } else if ( astChrMatch( cvt_string, "PREC" ) ) { result = AST__SLA_PREC; } else if ( astChrMatch( cvt_string, "FK45Z" ) ) { result = AST__SLA_FK45Z; } else if ( astChrMatch( cvt_string, "FK54Z" ) ) { result = AST__SLA_FK54Z; } else if ( astChrMatch( cvt_string, "AMP" ) ) { result = AST__SLA_AMP; } else if ( astChrMatch( cvt_string, "MAP" ) ) { result = AST__SLA_MAP; } else if ( astChrMatch( cvt_string, "ECLEQ" ) ) { result = AST__SLA_ECLEQ; } else if ( astChrMatch( cvt_string, "EQECL" ) ) { result = AST__SLA_EQECL; } else if ( astChrMatch( cvt_string, "GALEQ" ) ) { result = AST__SLA_GALEQ; } else if ( astChrMatch( cvt_string, "EQGAL" ) ) { result = AST__SLA_EQGAL; } else if ( astChrMatch( cvt_string, "FK5HZ" ) ) { result = AST__SLA_FK5HZ; } else if ( astChrMatch( cvt_string, "HFK5Z" ) ) { result = AST__SLA_HFK5Z; } else if ( astChrMatch( cvt_string, "GALSUP" ) ) { result = AST__SLA_GALSUP; } else if ( astChrMatch( cvt_string, "SUPGAL" ) ) { result = AST__SLA_SUPGAL; } else if ( astChrMatch( cvt_string, "HPCEQ" ) ) { result = AST__HPCEQ; } else if ( astChrMatch( cvt_string, "EQHPC" ) ) { result = AST__EQHPC; } else if ( astChrMatch( cvt_string, "HPREQ" ) ) { result = AST__HPREQ; } else if ( astChrMatch( cvt_string, "EQHPR" ) ) { result = AST__EQHPR; } else if ( astChrMatch( cvt_string, "HEEQ" ) ) { result = AST__HEEQ; } else if ( astChrMatch( cvt_string, "EQHE" ) ) { result = AST__EQHE; } else if ( astChrMatch( cvt_string, "J2000H" ) ) { result = AST__J2000H; } else if ( astChrMatch( cvt_string, "HJ2000" ) ) { result = AST__HJ2000; } else if ( astChrMatch( cvt_string, "H2E" ) ) { result = AST__SLA_DH2E; } else if ( astChrMatch( cvt_string, "E2H" ) ) { result = AST__SLA_DE2H; } else if ( astChrMatch( cvt_string, "R2H" ) ) { result = AST__R2H; } else if ( astChrMatch( cvt_string, "H2R" ) ) { result = AST__H2R; } /* Return the result. */ return result; } static const char *CvtString( int cvt_code, const char **comment, int *nargs, const char *arg[ MAX_SLA_ARGS ], int *status ) { /* * Name: * CvtString * Purpose: * Convert a conversion type from a code value to a string representation. * Type: * Private function. * Synopsis: * #include "slamap.h" * const char *CvtString( int cvt_code, const char **comment, * int *nargs, const char *arg[ MAX_SLA_ARGS ], int *status ) * Class Membership: * SlaMap member function. * Description: * This function accepts a code value used to represent one of the * SLALIB sky coordinate conversions and converts it into an * equivalent string representation. It also returns a descriptive * comment and information about the arguments required in order to * perform the conversion. * Parameters: * cvt_code * The conversion code. * comment * Address of a location to return a pointer to a constant * null-terminated string containing a description of the * conversion. * nargs * Address of an int in which to return the number of arguments * required in order to perform the conversion (may be zero). * arg * An array in which to return a pointer to a constant * null-terminated string for each argument (above) containing a * description of what each argument represents. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string representation of * the conversion code value supplied. If the code supplied is not * valid, a NULL pointer will be returned, without error. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Result pointer to return */ /* Initialise the returned values. */ *comment = NULL; *nargs = 0; result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Test for each valid code value in turn and assign the appropriate return values. */ switch ( cvt_code ) { case AST__SLA_ADDET: result = "ADDET"; *comment = "Add E-terms of aberration"; *nargs = 1; arg[ 0 ] = "Besselian epoch of mean equinox (FK4)"; break; case AST__SLA_SUBET: result = "SUBET"; *comment = "Subtract E-terms of aberration"; *nargs = 1; arg[ 0 ] = "Besselian epoch of mean equinox (FK4)"; break; case AST__SLA_PREBN: result = "PREBN"; *comment = "Apply Bessel-Newcomb (FK4) precession"; *nargs = 2; arg[ 0 ] = "From Besselian epoch"; arg[ 1 ] = "To Besselian epoch"; break; case AST__SLA_PREC: result = "PREC"; *comment = "Apply IAU 1975 (FK5) precession"; *nargs = 2; arg[ 0 ] = "From Julian epoch"; arg[ 1 ] = "To Julian epoch"; break; case AST__SLA_FK45Z: result = "FK45Z"; *comment = "FK4 to FK5 J2000.0 (no PM or parallax)"; arg[ 0 ] = "Besselian epoch of FK4 coordinates"; *nargs = 1; break; case AST__SLA_FK54Z: result = "FK54Z"; *comment = "FK5 J2000.0 to FK4 (no PM or parallax)"; *nargs = 1; arg[ 0 ] = "Besselian epoch of FK4 system"; break; case AST__SLA_AMP: result = "AMP"; *comment = "Geocentric apparent to mean place (FK5)"; *nargs = 2; arg[ 0 ] = "TDB of apparent place (as MJD)"; arg[ 1 ] = "Julian epoch of mean equinox (FK5)"; break; case AST__SLA_MAP: result = "MAP"; *comment = "Mean place (FK5) to geocentric apparent"; *nargs = 2; arg[ 0 ] = "Julian epoch of mean equinox (FK5)"; arg[ 1 ] = "TDB of apparent place (as MJD)"; break; case AST__SLA_ECLEQ: result = "ECLEQ"; *comment = "Ecliptic (IAU 1980) to J2000.0 equatorial (FK5)"; *nargs = 1; arg[ 0 ] = "TDB of mean ecliptic (as MJD)"; break; case AST__SLA_EQECL: result = "EQECL"; *comment = "Equatorial J2000.0 (FK5) to ecliptic (IAU 1980)"; *nargs = 1; arg[ 0 ] = "TDB of mean ecliptic (as MJD)"; break; case AST__SLA_GALEQ: result = "GALEQ"; *comment = "Galactic (IAU 1958) to J2000.0 equatorial (FK5)"; *nargs = 0; break; case AST__SLA_EQGAL: result = "EQGAL"; *comment = "J2000.0 equatorial (FK5) to galactic (IAU 1958)"; *nargs = 0; break; case AST__SLA_FK5HZ: result = "FK5HZ"; *comment = "J2000.0 FK5 to ICRS (no PM or parallax)"; arg[ 0 ] = "Julian epoch of FK5 coordinates"; *nargs = 1; break; case AST__SLA_HFK5Z: result = "HFK5Z"; *comment = "ICRS to J2000.0 FK5 (no PM or parallax)"; arg[ 0 ] = "Julian epoch of FK5 coordinates"; *nargs = 1; break; case AST__SLA_GALSUP: result = "GALSUP"; *comment = "Galactic (IAU 1958) to supergalactic"; *nargs = 0; break; case AST__SLA_SUPGAL: result = "SUPGAL"; *comment = "Supergalactic to galactic (IAU 1958)"; *nargs = 0; break; case AST__HPCEQ: result = "HPCEQ"; *comment = "Helioprojective-Cartesian to J2000.0 equatorial (FK5)"; *nargs = 4; arg[ 0 ] = "Modified Julian Date of observation"; arg[ 1 ] = "Heliocentric-Aries-Ecliptic X value at observer"; arg[ 2 ] = "Heliocentric-Aries-Ecliptic Y value at observer"; arg[ 3 ] = "Heliocentric-Aries-Ecliptic Z value at observer"; break; case AST__EQHPC: result = "EQHPC"; *comment = "J2000.0 equatorial (FK5) to Helioprojective-Cartesian"; *nargs = 4; arg[ 0 ] = "Modified Julian Date of observation"; arg[ 1 ] = "Heliocentric-Aries-Ecliptic X value at observer"; arg[ 2 ] = "Heliocentric-Aries-Ecliptic Y value at observer"; arg[ 3 ] = "Heliocentric-Aries-Ecliptic Z value at observer"; break; case AST__HPREQ: result = "HPREQ"; *comment = "Helioprojective-Radial to J2000.0 equatorial (FK5)"; *nargs = 4; arg[ 0 ] = "Modified Julian Date of observation"; arg[ 1 ] = "Heliocentric-Aries-Ecliptic X value at observer"; arg[ 2 ] = "Heliocentric-Aries-Ecliptic Y value at observer"; arg[ 3 ] = "Heliocentric-Aries-Ecliptic Z value at observer"; break; case AST__EQHPR: result = "EQHPR"; *comment = "J2000.0 equatorial (FK5) to Helioprojective-Radial"; *nargs = 4; arg[ 0 ] = "Modified Julian Date of observation"; arg[ 1 ] = "Heliocentric-Aries-Ecliptic X value at observer"; arg[ 2 ] = "Heliocentric-Aries-Ecliptic Y value at observer"; arg[ 3 ] = "Heliocentric-Aries-Ecliptic Z value at observer"; break; case AST__HEEQ: result = "HEEQ"; *comment = "Helio-ecliptic to equatorial"; *nargs = 1; arg[ 0 ] = "Modified Julian Date of observation"; break; case AST__EQHE: result = "EQHE"; *comment = "Equatorial to helio-ecliptic"; *nargs = 1; arg[ 0 ] = "Modified Julian Date of observation"; break; case AST__J2000H: result = "J2000H"; *comment = "J2000 equatorial (dynamical) to ICRS"; *nargs = 0; break; case AST__HJ2000: result = "HJ2000"; *comment = "ICRS to J2000 equatorial (dynamical)"; *nargs = 0; break; case AST__SLA_DH2E: result = "H2E"; *comment = "Horizon to equatorial"; *nargs = 2; arg[ 0 ] = "Geodetic latitude of observer"; arg[ 1 ] = "Magnitude of diurnal aberration vector"; break; case AST__SLA_DE2H: result = "E2H"; *comment = "Equatorial to horizon"; *nargs = 2; arg[ 0 ] = "Geodetic latitude of observer"; arg[ 1 ] = "Magnitude of diurnal aberration vector"; break; case AST__R2H: result = "R2H"; *comment = "RA to Hour Angle"; *nargs = 1; arg[ 0 ] = "Local apparent sidereal time (radians)"; break; case AST__H2R: result = "H2R"; *comment = "Hour Angle to RA"; *nargs = 1; arg[ 0 ] = "Local apparent sidereal time (radians)"; break; } /* Return the result. */ return result; } static void Earth( double mjd, double earth[3], int *status ) { /* *+ * Name: * Earth * Purpose: * Returns the AST__HAEC position of the earth at the specified time. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Earth( double mjd, double earth[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns the AST__HAEC position of the earth at the * specified time. See astSTPConv for a description of the AST__HAEC * coordinate systems. * Parameters: * mjd * Modified Julian date. * earth * The AST__HAEC position of the earth at the given date. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ double dpb[3]; /* Earth position (barycentric) */ double dph[3]; /* Earth position (heliocentric) */ double dvb[3]; /* Earth velocity (barycentric) */ double dvh[3]; /* Earth velocity (heliocentric, AST__HAQC) */ double ecmat[3][3];/* Equatorial to ecliptic matrix */ int i; /* Loop count */ /* Initialize. */ for( i = 0; i < 3; i++ ) earth[ i ] = 0.0; /* Check the global error status. */ if ( !astOK ) return; /* Get the position of the earth at the given date in the AST__HAQC coord system (dph). */ palEvp( mjd, 2000.0, dvb, dpb, dvh, dph ); /* Now rotate the earths position vector into AST__HAEC coords. */ palEcmat( palEpj2d( 2000.0 ), ecmat ); palDmxv( ecmat, dph, earth ); /* Convert from AU to metres. */ earth[0] *= AST__AU; earth[1] *= AST__AU; earth[2] *= AST__AU; } static void Hgc( double mjd, double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Hgc * Purpose: * Returns matrix and offset for converting AST__HGC positions to AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Hgc( double mjd, double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__HGC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__HGC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * mat * Matrix which rotates from AST__HGC to AST__HAEC. * offset * The origin of the AST__HGC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ double earth[3]; /* Earth position (heliocentric, AST__HAEC) */ double len; /* Vector length */ double xhg[3]; /* Unix X vector of AST__HGC system in AST__HAEC */ double yhg[3]; /* Unix Y vector of AST__HGC system in AST__HAEC */ double ytemp[3]; /* Un-normalized Y vector */ double zhg[3]; /* Unix Z vector of AST__HGC system in AST__HAEC */ int i; /* Loop count */ int j; /* Loop count */ /* Initialize. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[ i ] = 0.0; } /* Check the global error status. */ if ( !astOK ) return; /* Get a unit vector parallel to the solar north pole at the given date. This vector is expressed in AST__HAEC coords. This is the Z axis of the AST__HGC system. */ SolarPole( mjd, zhg, status ); /* Get the position of the earth at the given date in the AST__HAEC coord system. */ Earth( mjd, earth, status ); /* The HG Y axis is perpendicular to both the polar axis and the sun-earth line. Obtain a Y vector by taking the cross product of the two vectors, and then normalize it into a unit vector. */ palDvxv( zhg, earth, ytemp ); palDvn( ytemp, yhg, &len ); /* The HG X axis is perpendicular to both Z and Y, */ palDvxv( yhg, zhg, xhg ); /* The HG X, Y and Z unit vectors form the columns of the required matrix. The origins of the two systems are co-incident, so return the zero offset vector initialised earlier. */ for( i = 0; i < 3; i++ ) { mat[ i ][ 0 ] = xhg[ i ]; mat[ i ][ 1 ] = yhg[ i ]; mat[ i ][ 2 ] = zhg[ i ]; } } static void Gsec( double mjd, double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Gsec * Purpose: * Returns matrix and offset for converting AST__GSEC positions to AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Gsec( double mjd, double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__GSEC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__GSEC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * mat * Matrix which rotates from AST__GSEC to AST__HAEC. * offset * The origin of the AST__GSEC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ double earth[3]; /* Earth position (heliocentric, AST__HAEC) */ double pole[3]; /* Solar pole (AST__HAEC) */ double len; /* Vector length */ double xgs[3]; /* Unix X vector of AST__GSEC system in AST__HAEC */ double ygs[3]; /* Unix Y vector of AST__GSEC system in AST__HAEC */ double ytemp[3]; /* Un-normalized Y vector */ double zgs[3]; /* Unix Z vector of AST__GSEC system in AST__HAEC */ int i; /* Loop count */ int j; /* Loop count */ /* Initialize. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[ i ] = 0.0; } /* Check the global error status. */ if ( !astOK ) return; /* Get the position of the earth at the given date in the AST__HAEC coord system. */ Earth( mjd, earth, status ); /* We need to find unit vectors parallel to the GSEC (X,Y,Z) axes, expressed in terms of the AST__HAEC (X,Y,Z) axes. The GSEC X axis starts at the earth and passes through the centre of the sun. This is just the normalized opposite of the earth's position vector. */ palDvn( earth, xgs, &len ); xgs[0] *= -1.0; xgs[1] *= -1.0; xgs[2] *= -1.0; /* The GSEC Y axis is perpendicular to both the X axis and the ecliptic north pole vector. So find the ecliptic north pole vector in AST__HAEC coords. */ pole[ 0 ] = 0.0; pole[ 1 ] = 0.0; pole[ 2 ] = 1.0; /* Find the GSEC Y axis by taking the vector product of the X axis and the ecliptic north pole vector, and then normalize it into a unit vector. */ palDvxv( pole, xgs, ytemp ); palDvn( ytemp, ygs, &len ); /* The GSEC Z axis is perpendicular to both X and Y axis, and forms a right-handed system. The resulting vector will be of unit length since the x and y vectors are both of unit length, and are perpendicular to each other. It therefore does not need to be normalized.*/ palDvxv( xgs, ygs, zgs ); /* The GSEC X, Y and Z unit vectors form the columns of the required matrix. */ for( i = 0; i < 3; i++ ) { mat[ i ][ 0 ] = xgs[ i ]; mat[ i ][ 1 ] = ygs[ i ]; mat[ i ][ 2 ] = zgs[ i ]; offset[i] = earth[ i ]; } } static void Haec( double mjd, double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Haec * Purpose: * Returns matrix and offset for converting AST__HAEC positions to AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Haec( double mjd, double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__HAEC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__HAEC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * mat * Matrix which rotates from AST__HAEC to AST__HAEC. * offset * The origin of the AST__HAEC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; /* Loop count */ int j; /* Loop count */ /* Return an identity matrix and a zero offset vector. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[ i ] = 0.0; } } static void Haqc( double mjd, double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Haqc * Purpose: * Returns matrix and offset for converting AST__HAQC positions to AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Haqc( double mjd, double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__HAQC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__HAQC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * mat * Matrix which rotates from AST__HAQC to AST__HAEC. * offset * The origin of the AST__HAQC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; /* Loop count */ int j; /* Loop count */ /* Initialise an identity matrix and a zero offset vector. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[ i ] = 0.0; } /* Check the global error status. */ if ( !astOK ) return; /* Return the required matrix. */ palEcmat( palEpj2d( 2000.0 ), mat ); return; } static void Hpcc( double mjd, double obs[3], double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Hpcc * Purpose: * Returns matrix and offset for converting AST__HPCC positions to * AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Hpcc( double mjd, double obs[3], double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__HPCC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__HPCC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * obs * The observers position, in AST__HAEC, or NULL if the observer is * at the centre of the earth. * mat * Matrix which rotates from AST__HPCC to AST__HAEC. * offset * The origin of the AST__HPCC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ double earth[3]; /* Earth position (heliocentric, AST__HAEC) */ double pole[3]; /* Solar pole vector (AST__HAEC) */ double len; /* Vector length */ double xhpc[3]; /* Unix X vector of AST__HPCC system in AST__HAEC */ double yhpc[3]; /* Unix Y vector of AST__HPCC system in AST__HAEC */ double ytemp[3]; /* Un-normalized Y vector */ double zhpc[3]; /* Unix Z vector of AST__HPCC system in AST__HAEC */ int i; /* Loop count */ int j; /* Loop count */ /* Initialize. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[i] = 0.0; } /* Check the global error status. */ if ( !astOK ) return; /* If no observers position was supplied, use the position of the earth at the specified date in AST__HAEC coords. */ if( !obs ) { Earth( mjd, earth, status ); obs = earth; } /* We need to find unit vectors parallel to the HPCC (X,Y,Z) axes, expressed in terms of the AST__HAEC (X,Y,Z) axes. The HPCC X axis starts at the observer and passes through the centre of the sun. This is just the normalized opposite of the supplied observer's position vector. */ palDvn( obs, xhpc, &len ); xhpc[0] *= -1.0; xhpc[1] *= -1.0; xhpc[2] *= -1.0; /* The HPC Y axis is perpendicular to both the X axis and the solar north pole vector. So find the solar north pole vector in AST__HAEC coords. */ SolarPole( mjd, pole, status ); /* Find the HPC Y axis by taking the vector product of the X axis and the solar north pole vector, and then normalize it into a unit vector. Note, HPC (X,Y,Z) axes form a left-handed system! */ palDvxv( xhpc, pole, ytemp ); palDvn( ytemp, yhpc, &len ); /* The HPC Z axis is perpendicular to both X and Y axis, and forms a left-handed system. The resulting vector will be of unit length since the x and y vectors are both of unit length, and are perpendicular to each other. It therefore does not need to be normalized.*/ palDvxv( yhpc, xhpc, zhpc ); /* The HPC X, Y and Z unit vectors form the columns of the required matrix. */ for( i = 0; i < 3; i++ ) { mat[ i ][ 0 ] = xhpc[ i ]; mat[ i ][ 1 ] = yhpc[ i ]; mat[ i ][ 2 ] = zhpc[ i ]; offset[i] = obs[ i ]; } } static void Hprc( double mjd, double obs[3], double mat[3][3], double offset[3], int *status ) { /* *+ * Name: * Hprc * Purpose: * Returns matrix and offset for converting AST__HPRC positions to * AST__HAEC. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void Hprc( double mjd, double obs[3], double mat[3][3], double offset[3], int *status ) * Class Membership: * SlaMap method. * Description: * This function returns a 3x3 matrix which rotates direction vectors * given in the AST__HPRC system to the AST__HAEC system at the * specified date. It also returns the position of the origin of the * AST__HPRC system as an AST__HAEC position. See astSTPConv for a * description of these coordinate systems. * Parameters: * mjd * Modified Julian date defining the coordinate systems. * obs * The observers position, in AST__HAEC, or NULL if the observer is * at the centre of the earth. * mat * Matrix which rotates from AST__HPRC to AST__HAEC. * offset * The origin of the AST__HPRC system within the AST__HAEC system. *- * status * Pointer to the inherited status variable. */ /* Local Variables: */ double pole[3]; /* Solar pole (AST__HAEC) */ double earth[3]; /* Earth position (heliocentric, AST__HAEC) */ double len; /* Vector length */ double xhpr[3]; /* Unix X vector of AST__HPRC system in AST__HAEC */ double yhpr[3]; /* Unix Y vector of AST__HPRC system in AST__HAEC */ double ytemp[3]; /* Un-normalized Y vector */ double zhpr[3]; /* Unix Z vector of AST__HPRC system in AST__HAEC */ int i; /* Loop count */ int j; /* Loop count */ /* Initialize. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) { mat[i][j] = (i==j)?1.0:0.0; } offset[i] = 0.0; } /* Check the global error status. */ if ( !astOK ) return; /* If no observers position was supplied, use the position of the earth at the specified date in AST__HAEC coords. */ if( !obs ) { Earth( mjd, earth, status ); obs = earth; } /* We need to find unit vectors parallel to the HPRC (X,Y,Z) axes, expressed in terms of the AST__HAEC (X,Y,Z) axes. The HPRC Z axis starts at the observer and passes through the centre of the sun. This is just the normalized opposite of the supplied observer's position vector. */ palDvn( obs, zhpr, &len ); zhpr[0] *= -1.0; zhpr[1] *= -1.0; zhpr[2] *= -1.0; /* The HPR Y axis is perpendicular to both the Z axis and the solar north pole vector. So find the solar north pole vector in AST__HAEC coords. */ SolarPole( mjd, pole, status ); /* Find the HPR Y axis by taking the vector product of the Z axis and the solar north pole vector, and then normalize it into a unit vector. Note, HPR (X,Y,Z) axes form a left-handed system! */ palDvxv( pole, zhpr, ytemp ); palDvn( ytemp, yhpr, &len ); /* The HPRC X axis is perpendicular to both Y and Z axis, and forms a left-handed system. The resulting vector will be of unit length since the y and z vectors are both of unit length, and are perpendicular to each other. It therefore does not need to be normalized.*/ palDvxv( zhpr, yhpr, xhpr ); /* The HPRC X, Y and Z unit vectors form the columns of the required matrix. */ for( i = 0; i < 3; i++ ) { mat[ i ][ 0 ] = xhpr[ i ]; mat[ i ][ 1 ] = yhpr[ i ]; mat[ i ][ 2 ] = zhpr[ i ]; offset[ i ] = obs[ i ]; } } static void J2000H( int forward, int npoint, double *alpha, double *delta, int *status ){ /* * Name: * J2000H * Purpose: * Convert dynamical J2000 equatorial coords to ICRS. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void J2000H( int forward, int npoint, double *alpha, double *delta, int *status ) * Class Membership: * SlaMap method. * Description: * This function converts the supplied dynamical J2000 equatorial coords * to ICRS (or vice-versa). * Parameters: * forward * Do forward transformation? * npoint * Number of points to transform. * alpha * Pointer to longitude values. * delta * Pointer to latitude values. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; /* Loop count */ double rmat[3][3]; /* J2000 -> ICRS rotation matrix */ double v1[3]; /* J2000 vector */ double v2[3]; /* ICRS vector */ /* Check the global error status. */ if ( !astOK ) return; /* Get the J2000 to ICRS rotation matrix (supplied by P.T. Wallace) */ palDeuler( "XYZ", -0.0068192*AS2R, 0.0166172*AS2R, 0.0146000*AS2R, rmat ); /* Loop round all points. */ for( i = 0; i < npoint; i++ ) { /* Convert from (alpha,delta) to 3-vector */ palDcs2c( alpha[ i ], delta[ i ], v1 ); /* Rotate the 3-vector */ if( forward ) { palDmxv( rmat, v1, v2 ); } else { palDimxv( rmat, v1, v2 ); } /* Convert from 3-vector to (alpha,delta) */ palDcc2s( v2, alpha + i, delta + i ); } } void astSTPConv1_( double mjd, int in_sys, double in_obs[3], double in[3], int out_sys, double out_obs[3], double out[3], int *status ){ /* *+ * Name: * astSTPConv1 * Purpose: * Converts a 3D solar system position between specified STP coordinate * systems. * Type: * Protected function. * Synopsis: * #include "slamap.h" * void astSTPConv1( double mjd, int in_sys, double in_obs[3], * double in[3], int out_sys, double out_obs[3], * double out[3] ) * Class Membership: * Frame method. * Description: * This function converts a single 3D solar-system position from the * specified input coordinate system to the specified output coordinate * system. See astSTPConv for a list of supported coordinate systems. * Parameters: * mjd * The Modified Julian Date to which the coordinate systems refer. * in_sys * The coordinate system in which the input positions are supplied. * in_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the input system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * in * A 3-element array holding the input position. * out_sys * The coordinate system in which the input positions are supplied. * out_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the output system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * out * A 3-element array holding the output position. * Notes: * - The "in" and "out" arrays may safely point to the same memory. * - Output longitude values are always in the range 0 - 2.PI. *- */ /* Local Variables: */ double *ins[ 3 ]; /* The input position */ double *outs[ 3 ]; /* The output position */ /* Store pointers to the supplied arrays suitable for passing to STPConv. */ ins[ 0 ] = in; ins[ 1 ] = in + 1; ins[ 2 ] = in + 2; outs[ 0 ] = out; outs[ 1 ] = out + 1; outs[ 2 ] = out + 2; /* Convert the position. */ STPConv( mjd, 0, 1, in_sys, in_obs, ins, out_sys, out_obs, outs, status ); } void astSTPConv_( double mjd, int n, int in_sys, double in_obs[3], double *in[3], int out_sys, double out_obs[3], double *out[3], int *status ){ /* *+ * Name: * astSTPConv * Purpose: * Converts a set of 3D solar system positions between specified STP * coordinate systems. * Type: * Protected function. * Synopsis: * #include "slamap.h" * void astSTPConv( double mjd, int n, int in_sys, double in_obs[3], * double *in[3], int out_sys, double out_obs[3], * double *out[3] ) * Class Membership: * Frame method. * Description: * This function converts a set of 3D solar-system positions from * the specified input coordinate system to the specified output * coordinate system. * Parameters: * mjd * The Modified Julian Date to which the coordinate systems refer. * in_sys * The coordinate system in which the input positions are supplied * (see below). * in_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the input system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * in * A 3-element array holding the input positions. Each of the 3 * elements should point to an array of "n" axis values. For spherical * input systems, in[3] can be supplied as NULL, in which case a * constant value of 1 AU will be used. * out_sys * The coordinate system in which the input positions are supplied * (see below). * out_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the output system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * out * A 3-element array holding the output positions. Each of the 3 * elements should point to an array of "n" axis values. If in[3] is * NULL, no values will be assigned to out[3]. * Notes: * - The "in" and "out" arrays may safely point to the same memory. * - Output longitude values are always in the range 0 - 2.PI. * Supported Coordinate Systems: * Coordinate systems are either spherical or Cartesian, and are right * handed (unless otherwise indicated). Spherical systems use axis 0 for * longitude, axis 1 for latitude, and axis 2 for radius. Cartesian systems * use 3 mutually perpendicular axes; X is axis 0 and points towards the * intersection of the equator and the zero longitude meridian of the * corresponding spherical system, Y is axis 1 and points towards longitude * of +90 degrees, Z is axis 2 and points twowards the north pole. All * angles are in radians and all distances are in metres. The following * systems are supported: * * - AST__HAE: Heliocentric-aries-ecliptic spherical coordinates. Centred * at the centre of the sun. The north pole points towards the J2000 * ecliptic north pole, and meridian of zero longitude includes the * J2000 equinox. * * - AST__HAEC: Heliocentric-aries-ecliptic cartesian coordinates. Origin * at the centre of the sun. The Z axis points towards the J2000 ecliptic * north pole, and the X axis points towards the J2000 equinox. * * - AST__HAQ: Heliocentric-aries-equatorial spherical coordinates. Centred * at the centre of the sun. The north pole points towards the FK5 J2000 * equatorial north pole, and meridian of zero longitude includes the * FK5 J2000 equinox. * * - AST__HAQC: Heliocentric-aries-equatorial cartesian coordinates. Origin * at the centre of the sun. The Z axis points towards the FK5 J2000 * equatorial north pole, and the X axis points towards the FK5 J2000 * equinox. * * - AST__HG: Heliographic spherical coordinates. Centred at the centre of * the sun. North pole points towards the solar north pole at the given * date. The meridian of zero longitude includes the sun-earth line at * the given date. * * - AST__HGC: Heliographic cartesian coordinates. Origin at the centre of * the sun. The Z axis points towards the solar north pole at the given * date. The X axis is in the plane spanned by the Z axis, and the * sun-earth line at the given date. * * - AST__HPC: Helioprojective-cartesian spherical coordinates. A * left-handed system (that is, longitude increases westwards), centred * at the specified observer position. The intersection of the * zero-longitude meridian and the equator coincides with the centre of * the sun as seen from the observers position. The zero longitude * meridian includes the solar north pole at the specified date. * * - AST__HPCC: Helioprojective-cartesian cartesian coordinates. A * left-handed system with origin at the specified observer position. The * X axis points towards the centre of the sun as seen from the observers * position. The X-Z plane includes the solar north pole at the specified * date. * * - AST__HPR: Helioprojective-radial spherical coordinates. A left-handed * system (that is, longitude increases westwards), centred at the * specified observer position. The north pole points towards the centre * of the sun as seen from the observers position. The zero longitude * meridian includes the solar north pole at the specified date. * * - AST__HPRC: Helioprojective-radial cartesian coordinates. A left-handed * system with origin at the specified observer position. The Z axis points * towards the centre of the sun as seen from the observers position. The * X-Z plane includes the solar north pole at the specified date. * * - AST__GSE: Geocentric-solar-ecliptic spherical coordinates. Centred at * the centre of the earth at the given date. The north pole points towards * the J2000 ecliptic north pole, and the meridian of zero longitude * includes the Sun. * * - AST__GSEC: Geocentric-solar-ecliptic cartesian coordinates. Origin at * the centre of the earth at the given date. The X axis points towards the * centre of sun, and the X-Z plane contains the J2000 ecliptic north * pole. Since the earth may not be exactly in the mean ecliptic of * J2000, the Z axis will not in general correspond exactly to the * ecliptic north pole. *- */ STPConv( mjd, 0, n, in_sys, in_obs, in, out_sys, out_obs, out, status ); } static void STPConv( double mjd, int ignore_origins, int n, int in_sys, double in_obs[3], double *in[3], int out_sys, double out_obs[3], double *out[3], int *status ){ /* * Name: * STPConv * Purpose: * Convert a set of 3D solar system positions between specified STP * coordinate systems. * Type: * Private member function. * Synopsis: * #include "slamap.h" * void STPConv( double mjd, int ignore_origins, int n, int in_sys, * double in_obs[3], double *in[3], int out_sys, * double out_obs[3], double *out[3], int *status ){ * Class Membership: * Frame method. * Description: * This function converts a set of 3D solar-system positions from * the specified input coordinate system to the specified output * coordinate system. See astSTPConv for a list of the available * coordinate systems. * Parameters: * mjd * The Modified Julian Date to which the coordinate systems refer. * ignore_origins * If non-zero, then the coordinate system definitions are modified so * that all cartesian systems have the origin at the centre of the * Sun. If zero, the correct origins are used for each individual * system. * n * The number of positions to transform. * in_sys * The coordinate system in which the input positions are supplied * in_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the input system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * in * A 3-element array holding the input positions. Each of the 3 * elements should point to an array of "n" axis values. For spherical * input systems, in[3] can be supplied as NULL, in which case a * constant value of 1 AU will be used. * out_sys * The coordinate system in which the input positions are supplied * (see "Supported Coordinate Systems" below). * out_obs * The position of the observer in AST__HAEC coordinates. This is only * needed if the output system is an observer-centric system. If this * is not the case, a NULL pointer can be supplied. A NULL pointer * can also be supplied to indicate that he observer is at the centre of * the earth at the specified date. * out * A 3-element array holding the input positions. Each of the 3 * elements should point to an array of "n" axis values. For spherical * output coordinates, out[2] may be NULL, in which case the output * radius values are thrown away. * status * Pointer to the inherited status variable. * Notes: * - Output longitude values are always in the range 0 - 2.PI. * - The "in" and "out" arrays may safely point to the same memory. * - The contents of the output array is left unchanged if an error * has already occurred. */ /* Local Variables: */ double *out2; /* Pointer to output third axis values */ double *px; /* Pointer to next X axis value */ double *py; /* Pointer to next Y axis value */ double *pz; /* Pointer to next Z axis value */ double lat; /* Latitude value */ double lng; /* Longitude value */ double mat1[3][3]; /* Input->HAEC rotation matrix */ double mat2[3][3]; /* Output->HAEC rotation matrix */ double mat3[3][3]; /* HAEC->output rotation matrix */ double mat4[3][3]; /* Input->output rotation matrix */ double off1[3]; /* Origin of input system in HAEC coords */ double off2[3]; /* Origin of output system in HAEC coords */ double off3[3]; /* HAEC vector from output origin to input origin */ double off4[3]; /* Position of input origin within output system */ double p[3]; /* Current position */ double q[3]; /* New position */ double radius; /* Radius value */ int cur_sys; /* Current system for output values */ int i; /* Loop count */ int j; /* Loop count */ int inCsys; /* Input cartesian system */ int outCsys; /* Output cartesian system */ size_t nbyte; /* Amount of memory to copy */ /* Check the global error status. */ if ( !astOK ) return; /* If out[2] was supplied as null, allocate memory to hold third axis values. Otherwise, use the supplied array. */ nbyte = n*sizeof( double ); if( !out[2] ) { out2 = (double *) astMalloc( nbyte ); } else { out2 = out[2]; } /* Copy the input data to the output data and note that the output values are currently in the same system as the input values. */ memcpy ( out[ 0 ], in[ 0 ], nbyte ); memcpy ( out[ 1 ], in[ 1 ], nbyte ); if( in[2] ) { memcpy ( out2, in[ 2 ], nbyte ); } else { for( i = 0; i < n; i++ ) out2[ i ] = AST__AU; } cur_sys = in_sys; /* Skip the next bit if the output values are now in the required system. */ if( cur_sys != out_sys ) { /* If the current system is spherical note the corresponding cartesian system. If the current system is cartesian, use it. */ if( cur_sys == AST__HG ){ inCsys = AST__HGC; } else if( cur_sys == AST__HAQ ){ inCsys = AST__HAQC; } else if( cur_sys == AST__HAE ){ inCsys = AST__HAEC; } else if( cur_sys == AST__GSE ){ inCsys = AST__GSEC; } else if( cur_sys == AST__HPC ){ inCsys = AST__HPCC; } else if( cur_sys == AST__HPR ){ inCsys = AST__HPRC; } else { inCsys = cur_sys; } /* Convert input spherical positions into the corresponding cartesian system, putting the results in the "out" arrays. Modify the input system accordingly. */ if( cur_sys != inCsys ) { px = out[ 0 ]; py = out[ 1 ]; pz = out2; for( i = 0; i < n; i++ ) { p[ 0 ] = *px; p[ 1 ] = *py; p[ 2 ] = *pz; if( p[ 0 ] != AST__BAD && p[ 1 ] != AST__BAD && p[ 2 ] != AST__BAD ) { palDcs2c( p[ 0 ], p[ 1 ], q ); *(px++) = q[ 0 ]*p[ 2 ]; *(py++) = q[ 1 ]*p[ 2 ]; *(pz++) = q[ 2 ]*p[ 2 ]; } else { *(px++) = AST__BAD; *(py++) = AST__BAD; *(pz++) = AST__BAD; } } cur_sys = inCsys; } } /* Skip the next bit if the output values are now in the required system. */ if( cur_sys != out_sys ) { /* If the required output system is spherical, note the corresponding cartesian system. If the required output system is cartesian, use it.*/ if( out_sys == AST__HG ){ outCsys = AST__HGC; } else if( out_sys == AST__HAQ ){ outCsys = AST__HAQC; } else if( out_sys == AST__HAE ){ outCsys = AST__HAEC; } else if( out_sys == AST__GSE ){ outCsys = AST__GSEC; } else if( out_sys == AST__HPC ){ outCsys = AST__HPCC; } else if( out_sys == AST__HPR ){ outCsys = AST__HPRC; } else { outCsys = out_sys; } /* Skip the next bit if the output values are already in the required output cartesian system. */ if( cur_sys != outCsys ) { /* Obtain an offset vector and a rotation matrix which moves positions from the current (Cartesian) system to the AST__HAEC system. The offset vector returned by these functions is the AST__HAEC coordinates of the origin of the current system. The matrix rotates direction vectors from the current system to the AST__HAEC system. */ if( cur_sys == AST__HGC ) { Hgc( mjd, mat1, off1, status ); } else if( cur_sys == AST__HAEC ) { Haec( mjd, mat1, off1, status ); } else if( cur_sys == AST__HAQC ) { Haqc( mjd, mat1, off1, status ); } else if( cur_sys == AST__GSEC ) { Gsec( mjd, mat1, off1, status ); } else if( cur_sys == AST__HPCC ) { Hpcc( mjd, in_obs, mat1, off1, status ); } else if( cur_sys == AST__HPRC ) { Hprc( mjd, in_obs, mat1, off1, status ); } else { astError( AST__INTER, "astSTPConv(SlaMap): Unsupported input " "cartesian coordinate system type %d (internal AST " "programming error).", status, cur_sys ); } /* Obtain an offset vector and a rotation matrix which moves positions from the required output Cartesian system to the AST__HAEC system. */ if( outCsys == AST__HGC ) { Hgc( mjd, mat2, off2, status ); } else if( outCsys == AST__HAEC ) { Haec( mjd, mat2, off2, status ); } else if( outCsys == AST__HAQC ) { Haqc( mjd, mat2, off2, status ); } else if( outCsys == AST__GSEC ) { Gsec( mjd, mat2, off2, status ); } else if( outCsys == AST__HPCC ) { Hpcc( mjd, out_obs, mat2, off2, status ); } else if( outCsys == AST__HPRC ) { Hprc( mjd, out_obs, mat2, off2, status ); } else { astError( AST__INTER, "astSTPConv(SlaMap): Unsupported output " "cartesian coordinate system type %d (internal AST " "programming error).", status, outCsys ); } /* Invert the second matrix to get the matrix which rotates AST__HAEC coords to the output cartesian system. This an be done simply by transposing it since all the matrices are 3D rotations. */ for( i = 0; i < 3; i++ ) { for( j = 0; j < 3; j++ ) mat3[ i ][ j ] = mat2[ j ][ i ]; /* Find the offset in AST__HAEC coords from the origin of the output cartesian system to the origin of the current system. */ off3[ i ] = off1[ i ] - off2[ i ]; } /* Unless the origins are being ignored, use the above matrix to rotate the above AST__HAEC offset into the output cartesian system. If origins are being ignored, use an offset of zero. */ if( ignore_origins ) { off4[ 0 ] = 0.0; off4[ 1 ] = 0.0; off4[ 2 ] = 0.0; } else { palDmxv( mat3, off3, off4 ); } /* Concatentate the two matrices to get the matrix which rotates from the current system to the output cartesian system. */ palDmxm( mat3, mat1, mat4 ); /* Use the matrix and offset to convert current positions to output cartesian positions. */ px = out[ 0 ]; py = out[ 1 ]; pz = out2; for( i = 0; i < n; i++ ) { p[ 0 ] = *px; p[ 1 ] = *py; p[ 2 ] = *pz; if( p[ 0 ] != AST__BAD && p[ 1 ] != AST__BAD && p[ 2 ] != AST__BAD ) { palDmxv( mat4, p, q ); *(px++) = q[ 0 ] + off4[ 0 ]; *(py++) = q[ 1 ] + off4[ 1 ]; *(pz++) = q[ 2 ] + off4[ 2 ]; } else { *(px++) = AST__BAD; *(py++) = AST__BAD; *(pz++) = AST__BAD; } } /* Indicate that the output values are now in the required output cartesian system. */ cur_sys = outCsys; } } /* Skip the next bit if the output values are now in the required system. */ if( cur_sys != out_sys ) { /* The only reason why the output values may not be in the required output system is because the output system is spherical. Convert output Cartesian positions to output spherical positions. */ px = out[ 0 ]; py = out[ 1 ]; pz = out2; for( i = 0; i < n; i++ ) { p[ 0 ] = *px; p[ 1 ] = *py; p[ 2 ] = *pz; if( p[ 0 ] != AST__BAD && p[ 1 ] != AST__BAD && p[ 2 ] != AST__BAD ) { palDvn( p, q, &radius ); palDcc2s( q, &lng, &lat ); *(px++) = palDranrm( lng ); *(py++) = lat; *(pz++) = radius; } else { *(px++) = AST__BAD; *(py++) = AST__BAD; *(pz++) = AST__BAD; } } } /* If out[2] was supplied as null, free the memory used to hold third axis values. */ if( !out[2] ) out2 = (double *) astFree( (void *) out2 ); } void astInitSlaMapVtab_( AstSlaMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSlaMapVtab * Purpose: * Initialise a virtual function table for a SlaMap. * Type: * Protected function. * Synopsis: * #include "slamap.h" * void astInitSlaMapVtab( AstSlaMapVtab *vtab, const char *name ) * Class Membership: * SlaMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SlaMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASlaMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->SlaAdd = SlaAdd; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "SlaMap", "Conversion between sky coordinate systems" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing an SlaMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * SlaMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated SlaMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated SlaMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated SlaMap which is to be merged with * its neighbours. This should be a cloned copy of the SlaMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * SlaMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated SlaMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *new; /* Pointer to replacement Mapping */ AstSlaMap *slamap; /* Pointer to SlaMap */ const char *argdesc[ MAX_SLA_ARGS ]; /* Argument descriptions (junk) */ const char *class; /* Pointer to Mapping class string */ const char *comment; /* Pointer to comment string (junk) */ double (*cvtargs)[ MAX_SLA_ARGS ]; /* Pointer to argument arrays */ int *cvttype; /* Pointer to transformation type codes */ int *narg; /* Pointer to argument count array */ int done; /* Finished (no further simplification)? */ int iarg; /* Loop counter for arguments */ int icvt1; /* Loop initial value */ int icvt2; /* Loop final value */ int icvt; /* Loop counter for transformation steps */ int ikeep; /* Index to store step being kept */ int imap1; /* Index of first SlaMap to merge */ int imap2; /* Index of last SlaMap to merge */ int imap; /* Loop counter for Mappings */ int inc; /* Increment for transformation step loop */ int invert; /* SlaMap applied in inverse direction? */ int istep; /* Loop counter for transformation steps */ int keep; /* Keep transformation step? */ int ngone; /* Number of Mappings eliminated */ int nstep0; /* Original number of transformation steps */ int nstep; /* Total number of transformation steps */ int result; /* Result value to return */ int simpler; /* Simplification possible? */ int unit; /* Replacement Mapping is a UnitMap? */ /* Initialise. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* SlaMaps can only be merged if they are in series (or if there is only one Mapping present, in which case it makes no difference), so do nothing if they are not. */ if ( series || ( *nmap == 1 ) ) { /* Initialise the number of transformation steps to be merged to equal the number in the nominated SlaMap. */ nstep = ( (AstSlaMap *) ( *map_list )[ where ] )->ncvt; /* Search adjacent lower-numbered Mappings until one is found which is not an SlaMap. Accumulate the number of transformation steps involved in any SlaMaps found. */ imap1 = where; while ( ( imap1 - 1 >= 0 ) && astOK ) { class = astGetClass( ( *map_list )[ imap1 - 1 ] ); if ( !astOK || strcmp( class, "SlaMap" ) ) break; nstep += ( (AstSlaMap *) ( *map_list )[ imap1 - 1 ] )->ncvt; imap1--; } /* Similarly search adjacent higher-numbered Mappings. */ imap2 = where; while ( ( imap2 + 1 < *nmap ) && astOK ) { class = astGetClass( ( *map_list )[ imap2 + 1 ] ); if ( !astOK || strcmp( class, "SlaMap" ) ) break; nstep += ( (AstSlaMap *) ( *map_list )[ imap2 + 1 ] )->ncvt; imap2++; } /* Remember the initial number of transformation steps. */ nstep0 = nstep; /* Allocate memory for accumulating a list of all the transformation steps involved in all the SlaMaps found. */ cvttype = astMalloc( sizeof( int ) * (size_t) nstep ); cvtargs = astMalloc( sizeof( double[ MAX_SLA_ARGS ] ) * (size_t) nstep ); narg = astMalloc( sizeof( int ) * (size_t) nstep ); /* Loop to obtain the transformation data for each SlaMap being merged. */ nstep = 0; for ( imap = imap1; astOK && ( imap <= imap2 ); imap++ ) { /* Obtain a pointer to the SlaMap and note if it is being applied in its inverse direction. */ slamap = (AstSlaMap *) ( *map_list )[ imap ]; invert = ( *invert_list )[ imap ]; /* Set up loop limits and an increment to scan the transformation steps in each SlaMap in either the forward or reverse direction, as dictated by the associated "invert" value. */ icvt1 = invert ? slamap->ncvt - 1 : 0; icvt2 = invert ? -1 : slamap->ncvt; inc = invert ? -1 : 1; /* Loop through each transformation step in the SlaMap. */ for ( icvt = icvt1; icvt != icvt2; icvt += inc ) { /* For simplicity, free any extra information stored with the conversion step (it will be recreated as and when necessary). */ slamap->cvtextra[ icvt ] = astFree( slamap->cvtextra[ icvt ] ); /* Store the transformation type code and use "CvtString" to determine the associated number of arguments. Then store these arguments. */ cvttype[ nstep ] = slamap->cvttype[ icvt ]; (void) CvtString( cvttype[ nstep ], &comment, narg + nstep, argdesc, status ); if ( !astOK ) break; for ( iarg = 0; iarg < narg[ nstep ]; iarg++ ) { cvtargs[ nstep ][ iarg ] = slamap->cvtargs[ icvt ][ iarg ]; } /* If the SlaMap is inverted, we must not only accumulate its transformation steps in reverse, but also apply them in reverse. For some steps this means swapping arguments, for some it means changing the transformation type code to a complementary value, and for others it means both. Define macros to perform each of these changes. */ /* Macro to swap the values of two nominated arguments if the transformation type code matches "code". */ #define SWAP_ARGS( code, arg1, arg2 ) \ if ( cvttype[ nstep ] == code ) { \ double tmp = cvtargs[ nstep ][ arg1 ]; \ cvtargs[ nstep ][ arg1 ] = cvtargs[ nstep ][ arg2 ]; \ cvtargs[ nstep ][ arg2 ] = tmp; \ } /* Macro to exchange a transformation type code for its inverse (and vice versa). */ #define SWAP_CODES( code1, code2 ) \ if ( cvttype[ nstep ] == code1 ) { \ cvttype[ nstep ] = code2; \ } else if ( cvttype[ nstep ] == code2 ) { \ cvttype[ nstep ] = code1; \ } /* Use these macros to apply the changes where needed. */ if ( invert ) { /* E-terms of aberration. */ /* ---------------------- */ /* Exchange addition and subtraction of E-terms. */ SWAP_CODES( AST__SLA_ADDET, AST__SLA_SUBET ) /* Bessel-Newcomb pre-IAU 1976 (FK4) precession model. */ /* --------------------------------------------------- */ /* Exchange the starting and ending Besselian epochs. */ SWAP_ARGS( AST__SLA_PREBN, 0, 1 ) /* IAU 1975 (FK5) precession model. */ /* -------------------------------- */ /* Exchange the starting and ending epochs. */ SWAP_ARGS( AST__SLA_PREC, 0, 1 ) /* FK4 to FK5 (no proper motion or parallax). */ /* ------------------------------------------ */ /* Exchange FK5 to FK4 conversion for its inverse, and vice versa. */ SWAP_CODES( AST__SLA_FK54Z, AST__SLA_FK45Z ) /* Geocentric apparent to mean place. */ /* ---------------------------------- */ /* Exchange the transformation code for its inverse and also exchange the order of the date and equinox arguments. */ SWAP_CODES( AST__SLA_AMP, AST__SLA_MAP ) SWAP_ARGS( AST__SLA_AMP, 0, 1 ) SWAP_ARGS( AST__SLA_MAP, 0, 1 ) /* Ecliptic coordinates to FK5 J2000.0 equatorial. */ /* ------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__SLA_ECLEQ, AST__SLA_EQECL ) /* Horizon to equatorial. */ /* ---------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__SLA_DH2E, AST__SLA_DE2H ) /* Galactic coordinates to FK5 J2000.0 equatorial. */ /* ------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__SLA_GALEQ, AST__SLA_EQGAL ) /* ICRS coordinates to FK5 J2000.0 equatorial. */ /* ------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__SLA_HFK5Z, AST__SLA_FK5HZ ) /* Galactic to supergalactic coordinates. */ /* -------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__SLA_GALSUP, AST__SLA_SUPGAL ) /* FK5 J2000 equatorial coordinates to Helioprojective-Cartesian. */ /* -------------------------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__EQHPC, AST__HPCEQ ) /* FK5 J2000 equatorial coordinates to Helioprojective-Radial. */ /* ----------------------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__EQHPR, AST__HPREQ ) /* FK5 J2000 equatorial coordinates to Helio-ecliptic. */ /* --------------------------------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__EQHE, AST__HEEQ ) /* Dynamical J2000.0 to ICRS. */ /* -------------------------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__J2000H, AST__HJ2000 ) /* HA to RA */ /* -------- */ /* Exchange the transformation code for its inverse. */ SWAP_CODES( AST__H2R, AST__R2H ) } /* Undefine the local macros. */ #undef SWAP_ARGS #undef SWAP_CODES /* Count the transformation steps. */ nstep++; } } /* Loop to simplify the sequence of transformation steps until no further improvement is possible. */ done = 0; while ( astOK && !done ) { /* Examine each remaining transformation step in turn. */ ikeep = -1; for ( istep = 0; istep < nstep; istep++ ) { /* Initially assume we will retain the current step. */ keep = 1; /* Eliminate redundant precession corrections. */ /* ------------------------------------------- */ /* First check if this is a redundant precession transformation (i.e. the starting and ending epochs are the same). If so, then note that it should not be kept. */ if ( ( ( cvttype[ istep ] == AST__SLA_PREBN ) || ( cvttype[ istep ] == AST__SLA_PREC ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep ][ 1 ] ) ) { keep = 0; /* The remaining simplifications act to combine adjacent transformation steps, so only apply them while there are at least 2 steps left. */ } else if ( istep < ( nstep - 1 ) ) { /* Define a macro to test if two adjacent transformation type codes have specified values. */ #define PAIR_CVT( code1, code2 ) \ ( ( cvttype[ istep ] == code1 ) && \ ( cvttype[ istep + 1 ] == code2 ) ) /* Combine adjacent precession corrections. */ /* ---------------------------------------- */ /* If two precession corrections are adjacent, and have an equinox value in common, then they may be combined into a single correction by eliminating the common equinox. */ if ( ( PAIR_CVT( AST__SLA_PREBN, AST__SLA_PREBN ) || PAIR_CVT( AST__SLA_PREC, AST__SLA_PREC ) ) && EQUAL( cvtargs[ istep ][ 1 ], cvtargs[ istep + 1 ][ 0 ] ) ) { /* Retain the second correction, changing its first argument, and eliminate the first correction. */ cvtargs[ istep + 1 ][ 0 ] = cvtargs[ istep ][ 0 ]; istep++; /* Eliminate redundant E-term handling. */ /* ------------------------------------ */ /* Check if adjacent steps implement a matching pair of corrections for the E-terms of aberration with the same argument value. If so, they will cancel, so eliminate them both. */ } else if ( ( PAIR_CVT( AST__SLA_SUBET, AST__SLA_ADDET ) || PAIR_CVT( AST__SLA_ADDET, AST__SLA_SUBET ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant FK4/FK5 conversions. */ /* ---------------------------------------- */ /* Similarly, check for a matching pair of FK4/FK5 conversions with the same argument value and eliminate them both if possible. */ } else if ( ( PAIR_CVT( AST__SLA_FK45Z, AST__SLA_FK54Z ) || PAIR_CVT( AST__SLA_FK54Z, AST__SLA_FK45Z ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant ICRS/FK5 conversions. */ /* ----------------------------------------- */ /* Similarly, check for a matching pair of ICRS/FK5 conversions with the same argument value and eliminate them both if possible. */ } else if ( ( PAIR_CVT( AST__SLA_HFK5Z, AST__SLA_FK5HZ ) || PAIR_CVT( AST__SLA_FK5HZ, AST__SLA_HFK5Z ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant geocentric apparent conversions. */ /* ---------------------------------------------------- */ /* As above, check for a matching pair of conversions with matching argument values (note the argument order reverses for the two directions) and eliminate them if possible. */ } else if ( ( PAIR_CVT( AST__SLA_AMP, AST__SLA_MAP ) || PAIR_CVT( AST__SLA_MAP, AST__SLA_AMP ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 1 ] ) && EQUAL( cvtargs[ istep ][ 1 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant ecliptic coordinate conversions. */ /* ---------------------------------------------------- */ /* This is handled in the same way as the FK4/FK5 case. */ } else if ( ( PAIR_CVT( AST__SLA_ECLEQ, AST__SLA_EQECL ) || PAIR_CVT( AST__SLA_EQECL, AST__SLA_ECLEQ ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant AzEl coordinate conversions. */ /* ------------------------------------------------ */ } else if ( ( PAIR_CVT( AST__SLA_DH2E, AST__SLA_DE2H ) || PAIR_CVT( AST__SLA_DE2H, AST__SLA_DH2E ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) && EQUAL( cvtargs[ istep ][ 1 ], cvtargs[ istep + 1 ][ 1 ] ) ) { istep++; keep = 0; /* Eliminate redundant galactic coordinate conversions. */ /* ---------------------------------------------------- */ /* This is handled as above, except that there are no arguments to check. */ } else if ( PAIR_CVT( AST__SLA_GALEQ, AST__SLA_EQGAL ) || PAIR_CVT( AST__SLA_EQGAL, AST__SLA_GALEQ ) ) { istep++; keep = 0; /* Eliminate redundant supergalactic coordinate conversions. */ /* --------------------------------------------------------- */ /* This is handled as above. */ } else if ( PAIR_CVT( AST__SLA_GALSUP, AST__SLA_SUPGAL ) || PAIR_CVT( AST__SLA_SUPGAL, AST__SLA_GALSUP ) ) { istep++; keep = 0; /* Eliminate redundant helioprojective-Cartesian coordinate conversions. */ /* --------------------------------------------------------------------- */ } else if ( ( PAIR_CVT( AST__HPCEQ, AST__EQHPC ) || PAIR_CVT( AST__EQHPC, AST__HPCEQ ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) && EQUAL( cvtargs[ istep ][ 1 ], cvtargs[ istep + 1 ][ 1 ] ) && EQUAL( cvtargs[ istep ][ 2 ], cvtargs[ istep + 1 ][ 2 ] ) && EQUAL( cvtargs[ istep ][ 3 ], cvtargs[ istep + 1 ][ 3 ] ) ) { istep++; keep = 0; /* Eliminate redundant helioprojective-Radial coordinate conversions. */ /* --------------------------------------------------------------------- */ } else if ( ( PAIR_CVT( AST__HPREQ, AST__EQHPR ) || PAIR_CVT( AST__EQHPR, AST__HPREQ ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) && EQUAL( cvtargs[ istep ][ 1 ], cvtargs[ istep + 1 ][ 1 ] ) && EQUAL( cvtargs[ istep ][ 2 ], cvtargs[ istep + 1 ][ 2 ] ) && EQUAL( cvtargs[ istep ][ 3 ], cvtargs[ istep + 1 ][ 3 ] ) ) { istep++; keep = 0; /* Eliminate redundant helio-ecliptic coordinate conversions. */ /* ---------------------------------------------------------- */ } else if ( ( PAIR_CVT( AST__EQHE, AST__HEEQ ) || PAIR_CVT( AST__HEEQ, AST__EQHE ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; /* Eliminate redundant dynamical J2000 coordinate conversions. */ /* ----------------------------------------------------------- */ } else if ( PAIR_CVT( AST__J2000H, AST__HJ2000 ) || PAIR_CVT( AST__HJ2000, AST__J2000H ) ) { istep++; keep = 0; /* Eliminate redundant Hour Angle conversions. */ /* ------------------------------------------- */ } else if ( ( PAIR_CVT( AST__R2H, AST__H2R ) || PAIR_CVT( AST__H2R, AST__R2H ) ) && EQUAL( cvtargs[ istep ][ 0 ], cvtargs[ istep + 1 ][ 0 ] ) ) { istep++; keep = 0; } /* Undefine the local macro. */ #undef PAIR_CVT } /* If the current transformation (possibly modified above) is being kept, then increment the index that identifies its new location in the list of transformation steps. */ if ( keep ) { ikeep++; /* If the new location is different to its current location, copy the transformation data into the new location. */ if ( ikeep != istep ) { cvttype[ ikeep ] = cvttype[ istep ]; for ( iarg = 0; iarg < narg[ istep ]; iarg++ ) { cvtargs[ ikeep ][ iarg ] = cvtargs[ istep ][ iarg ]; } narg[ ikeep ] = narg[ istep ]; } } } /* Note if no simplification was achieved on this iteration (i.e. the number of transformation steps was not reduced). This is the signal to quit. */ done = ( ( ikeep + 1 ) >= nstep ); /* Note how many transformation steps now remain. */ nstep = ikeep + 1; } /* Determine how many Mappings can be eliminated by condensing all those considered above into a single Mapping. */ if ( astOK ) { ngone = imap2 - imap1; /* Determine if the replacement Mapping can be a UnitMap (a null Mapping). This will only be the case if all the transformation steps were eliminated above. */ unit = ( nstep == 0 ); /* Determine if simplification is possible. This will be the case if (a) Mappings were eliminated ("ngone" is non-zero), or (b) the number of transformation steps was reduced, or (c) the SlaMap(s) can be replaced by a UnitMap, or (d) if there was initially only one SlaMap present, its invert flag was set (this flag will always be cleared in the replacement Mapping). */ simpler = ngone || ( nstep < nstep0 ) || unit || ( *invert_list )[ where ]; /* Do nothing more unless simplification is possible. */ if ( simpler ) { /* If the replacement Mapping is a UnitMap, then create it. */ if ( unit ) { new = (AstMapping *) astUnitMap( astGetNin( ( *map_list )[ where ] ), "", status ); /* Otherwise, create a replacement SlaMap and add each of the remaining transformation steps to it. */ } else { new = (AstMapping *) astSlaMap( 0, "", status ); for ( istep = 0; istep < nstep; istep++ ) { AddSlaCvt( (AstSlaMap *) new, cvttype[ istep ], cvtargs[ istep ], status ); } } /* Annul the pointers to the Mappings being eliminated. */ if ( astOK ) { for ( imap = imap1; imap <= imap2; imap++ ) { ( *map_list )[ imap ] = astAnnul( ( *map_list )[ imap ] ); } /* Insert the pointer and invert value for the new Mapping. */ ( *map_list )[ imap1 ] = new; ( *invert_list )[ imap1 ] = 0; /* Move any subsequent Mapping information down to close the gap. */ for ( imap = imap2 + 1; imap < *nmap; imap++ ) { ( *map_list )[ imap - ngone ] = ( *map_list )[ imap ]; ( *invert_list )[ imap - ngone ] = ( *invert_list )[ imap ]; } /* Blank out any information remaining at the end of the arrays. */ for ( imap = ( *nmap - ngone ); imap < *nmap; imap++ ) { ( *map_list )[ imap ] = NULL; ( *invert_list )[ imap ] = 0; } /* Decrement the Mapping count and return the index of the first Mapping which was eliminated. */ ( *nmap ) -= ngone; result = imap1; /* If an error occurred, annul the new Mapping pointer. */ } else { new = astAnnul( new ); } } } /* Free the memory used for the transformation steps. */ cvttype = astFree( cvttype ); cvtargs = astFree( cvtargs ); narg = astFree( narg ); } /* If an error occurred, clear the returned value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static void SlaAdd( AstSlaMap *this, const char *cvt, const double args[], int *status ) { /* *++ * Name: c astSlaAdd f AST_SLAADD * Purpose: * Add a celestial coordinate conversion to an SlaMap. * Type: * Public virtual function. * Synopsis: c #include "slamap.h" c void astSlaAdd( AstSlaMap *this, const char *cvt, const double args[] ) f CALL AST_SLAADD( THIS, CVT, ARGS, STATUS ) * Class Membership: * SlaMap method. * Description: c This function adds one of the standard celestial coordinate f This routine adds one of the standard celestial coordinate * system conversions provided by the SLALIB Positional Astronomy * Library (Starlink User Note SUN/67) to an existing SlaMap. * c When an SlaMap is first created (using astSlaMap), it simply f When an SlaMap is first created (using AST_SLAMAP), it simply c performs a unit (null) Mapping. By using astSlaAdd (repeatedly f performs a unit (null) Mapping. By using AST_SLAADD (repeatedly * if necessary), one or more coordinate conversion steps may then * be added, which the SlaMap will perform in sequence. This allows * multi-step conversions between a variety of celestial coordinate * systems to be assembled out of the building blocks provided by * SLALIB. * * Normally, if an SlaMap's Invert attribute is zero (the default), * then its forward transformation is performed by carrying out * each of the individual coordinate conversions specified by c astSlaAdd in the order given (i.e. with the most recently added f AST_SLAADD in the order given (i.e. with the most recently added * conversion applied last). * * This order is reversed if the SlaMap's Invert attribute is * non-zero (or if the inverse transformation is requested by any * other means) and each individual coordinate conversion is also * replaced by its own inverse. This process inverts the overall * effect of the SlaMap. In this case, the first conversion to be * applied would be the inverse of the one most recently added. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the SlaMap. c cvt f CVT = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string which identifies the f A character string which identifies the * celestial coordinate conversion to be added to the * SlaMap. See the "SLALIB Conversions" section for details of * those available. c args f ARGS( * ) = DOUBLE PRECISION (Given) * An array containing argument values for the celestial * coordinate conversion. The number of arguments required, and * hence the number of array elements used, depends on the * conversion specified (see the "SLALIB Conversions" * section). This array is ignored c and a NULL pointer may be supplied * if no arguments are needed. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - All coordinate values processed by an SlaMap are in * radians. The first coordinate is the celestial longitude and the * second coordinate is the celestial latitude. * - When assembling a multi-stage conversion, it can sometimes be * difficult to determine the most economical conversion path. For * example, converting to the standard FK5 coordinate system as an * intermediate stage is often sensible in formulating the problem, * but may introduce unnecessary extra conversion steps. A solution * to this is to include all the steps which are (logically) c necessary, but then to use astSimplify to simplify the resulting f necessary, but then to use AST_SIMPLIFY to simplify the resulting * SlaMap. The simplification process will eliminate any steps * which turn out not to be needed. c - This function does not check to ensure that the sequence of f - This routine does not check to ensure that the sequence of * coordinate conversions added to an SlaMap is physically * meaningful. * SLALIB Conversions: * The following strings (which are case-insensitive) may be supplied c via the "cvt" parameter to indicate which celestial coordinate f via the CVT argument to indicate which celestial coordinate * conversion is to be added to the SlaMap. Each string is derived * from the name of the SLALIB routine that performs the * conversion and the relevant documentation (SUN/67) should be * consulted for details. Where arguments are needed by * the conversion, they are listed in parentheses. Values for c these arguments should be given, via the "args" array, in the f these arguments should be given, via the ARGS array, in the * order indicated. The argument names match the corresponding * SLALIB routine arguments and their values should be given using * exactly the same units, time scale, calendar, etc. as described * in SUN/67: * * - "ADDET" (EQ): Add E-terms of aberration. * - "SUBET" (EQ): Subtract E-terms of aberration. * - "PREBN" (BEP0,BEP1): Apply Bessel-Newcomb pre-IAU 1976 (FK4) * precession model. * - "PREC" (EP0,EP1): Apply IAU 1975 (FK5) precession model. * - "FK45Z" (BEPOCH): Convert FK4 to FK5 (no proper motion or parallax). * - "FK54Z" (BEPOCH): Convert FK5 to FK4 (no proper motion or parallax). * - "AMP" (DATE,EQ): Convert geocentric apparent to mean place. * - "MAP" (EQ,DATE): Convert mean place to geocentric apparent. * - "ECLEQ" (DATE): Convert ecliptic coordinates to FK5 J2000.0 equatorial. * - "EQECL" (DATE): Convert equatorial FK5 J2000.0 to ecliptic coordinates. * - "GALEQ": Convert galactic coordinates to FK5 J2000.0 equatorial. * - "EQGAL": Convert FK5 J2000.0 equatorial to galactic coordinates. * - "HFK5Z" (JEPOCH): Convert ICRS coordinates to FK5 J2000.0 equatorial. * - "FK5HZ" (JEPOCH): Convert FK5 J2000.0 equatorial coordinates to ICRS. * - "GALSUP": Convert galactic to supergalactic coordinates. * - "SUPGAL": Convert supergalactic coordinates to galactic. * - "J2000H": Convert dynamical J2000.0 to ICRS. * - "HJ2000": Convert ICRS to dynamical J2000.0. * - "R2H" (LAST): Convert RA to Hour Angle. * - "H2R" (LAST): Convert Hour Angle to RA. * * For example, to use the "ADDET" conversion, which takes a single * argument EQ, you should consult the documentation for the SLALIB * routine SLA_ADDET. This describes the conversion in detail and * shows that EQ is the Besselian epoch of the mean equator and * equinox. c This value should then be supplied to astSlaAdd in args[0]. f This value should then be supplied to AST_SLAADD in ARGS(1). * * In addition the following strings may be supplied for more complex * conversions which do not correspond to any one single SLALIB routine * (DIURAB is the magnitude of the diurnal aberration vector in units * of "day/(2.PI)", DATE is the Modified Julian Date of the observation, * and (OBSX,OBSY,OBZ) are the Heliocentric-Aries-Ecliptic cartesian * coordinates, in metres, of the observer): * * - "HPCEQ" (DATE,OBSX,OBSY,OBSZ): Convert Helioprojective-Cartesian coordinates to J2000.0 equatorial. * - "EQHPC" (DATE,OBSX,OBSY,OBSZ): Convert J2000.0 equatorial coordinates to Helioprojective-Cartesian. * - "HPREQ" (DATE,OBSX,OBSY,OBSZ): Convert Helioprojective-Radial coordinates to J2000.0 equatorial. * - "EQHPR" (DATE,OBSX,OBSY,OBSZ): Convert J2000.0 equatorial coordinates to Helioprojective-Radial. * - "HEEQ" (DATE): Convert helio-ecliptic coordinates to J2000.0 equatorial. * - "EQHE" (DATE): Convert J2000.0 equatorial coordinates to helio-ecliptic. * - "H2E" (LAT,DIRUAB): Convert horizon coordinates to equatorial. * - "E2H" (LAT,DIURAB): Convert equatorial coordinates to horizon. * * Note, the "H2E" and "E2H" conversions convert between topocentric * horizon coordinates (azimuth,elevation), and apparent local equatorial * coordinates (hour angle,declination). Thus, the effects of diurnal * aberration are taken into account in the conversions but the effects * of atmospheric refraction are not. *-- */ /* Local Variables: */ int cvttype; /* Conversion type code */ /* Check the inherited status. */ if ( !astOK ) return; /* Validate the type string supplied and obtain the equivalent conversion type code. */ cvttype = CvtCode( cvt, status ); /* If the string was not recognised, then report an error. */ if ( astOK && ( cvttype == AST__SLA_NULL ) ) { astError( AST__SLAIN, "astSlaAdd(%s): Invalid SLALIB sky coordinate conversion " "type \"%s\".", status, astGetClass( this ), cvt ); } /* Add the new conversion to the SlaMap. */ AddSlaCvt( this, cvttype, args, status ); } static void SolarPole( double mjd, double pole[3], int *status ) { /* * Name: * SolarPole * Purpose: * Returns a unit vector along the solar north pole at the given date. * Type: * Private function. * Synopsis: * #include "slamap.h" * void SolarPole( double mjd, double pole[3], int *status ) * Class Membership: * SlaMap member function. * Description: * This function returns a unit vector along the solar north pole at * the given date, in the AST__HAEC coordinate system. * Parameters: * mjd * The date at which the solar north pole vector is required. * pole * An array holding the (X,Y,Z) components of the vector, in the * AST__HAEC system. * status * Pointer to the inherited status variable. * Notes: * - AST__BAD will be returned for all components of the vector if this * function is invoked with the global error status set, or if it should * fail for any reason. */ /* Local Variables: */ double omega; double sproj; double inc; double t1; /* Initialize. */ pole[0] = AST__BAD; pole[1] = AST__BAD; pole[2] = AST__BAD; /* Check the global error status. */ if ( !astOK ) return; /* First, we find the ecliptic longitude of the ascending node of the solar equator on the ecliptic at the required date. This is based on the equation in the "Explanatory Supplement to the Astronomical Alamanac", section "Physical Ephemeris of the Sun": Omega = 75.76 + 0.01397*T degrees Note, the text at the start of the chapter says that "T" is measured in centuries since J2000, but the equivalent expression in Table 15.4 is only consistent with the above equation if "T" is measured in days since J2000. We assume T is in days. The text does not explicitly say so, but we assume that this longitude value (Omega) is with respect to the mean equinox of J2000.0. */ omega = 75.76 + 0.01397*( palEpj(mjd) - 2000.0 ); /* Convert this to the ecliptic longitude of the projection of the sun's north pole onto the ecliptic, in radians. */ sproj = ( omega - 90.0 )*D2R; /* Obtain a unit vector parallel to the sun's north pole, in terms of the required ecliptic (X,Y,Z) axes, in which X points towards ecliptic longitude/latitude ( 0, 0 ), Y axis points towards ecliptic longitude/latitude ( 90, 0 ) degrees, and Z axis points towards the ecliptic north pole. The inclination of the solar axis to the ecliptic axis (7.25 degrees) is taken from the "Explanatory Supplement" section "The Physical Ephemeris of the Sun". */ inc = 7.25*D2R; t1 = sin( inc ); pole[ 0 ]= t1*cos( sproj ); pole[ 1 ] = t1*sin( sproj ); pole[ 2 ] = cos( inc ); } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply an SlaMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "slamap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * SlaMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes an SlaMap and a set of points encapsulated * in a PointSet and transforms the points so as to perform the * sequence of SLALIB sky coordinate conversions specified by * previous invocations of astSlaAdd. * Parameters: * this * Pointer to the SlaMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the SlaMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPointSet *result; /* Pointer to output PointSet */ AstSlaMap *map; /* Pointer to SlaMap to be applied */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *alpha; /* Pointer to longitude array */ double *args; /* Pointer to argument list for conversion */ double *extra; /* Pointer to intermediate values */ double *delta; /* Pointer to latitude array */ double *p[3]; /* Pointers to arrays to be transformed */ double *obs; /* Pointer to array holding observers position */ int cvt; /* Loop counter for conversions */ int ct; /* Conversion type */ int end; /* Termination index for conversion loop */ int inc; /* Increment for conversion loop */ int ncoord_in; /* Number of coordinates per input point */ int npoint; /* Number of points */ int point; /* Loop counter for points */ int start; /* Starting index for conversion loop */ int sys; /* STP coordinate system code */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Obtain a pointer to the SlaMap. */ map = (AstSlaMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the coordinate conversions needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ ncoord_in = astGetNcoord( in ); npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse transformation, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( this ) ) forward = !forward; /* Transform the coordinate values. */ /* -------------------------------- */ /* Use "alpha" and "delta" as synonyms for the arrays of longitude and latitude coordinate values stored in the output PointSet. */ if ( astOK ) { alpha = ptr_out[ 0 ]; delta = ptr_out[ 1 ]; /* Initialise the output coordinate values by copying the input ones. */ (void) memcpy( alpha, ptr_in[ 0 ], sizeof( double ) * (size_t) npoint ); (void) memcpy( delta, ptr_in[ 1 ], sizeof( double ) * (size_t) npoint ); /* We will loop to apply each SLALIB sky coordinate conversion in turn to the (alpha,delta) arrays. However, if the inverse transformation was requested, we must loop through these transformations in reverse order, so set up appropriate limits and an increment to control this loop. */ start = forward ? 0 : map->ncvt - 1; end = forward ? map->ncvt : -1; inc = forward ? 1 : -1; /* Loop through the coordinate conversions in the required order and obtain a pointer to the argument list for the current conversion. */ for ( cvt = start; cvt != end; cvt += inc ) { args = map->cvtargs[ cvt ]; extra = map->cvtextra[ cvt ]; /* Define a local macro as a shorthand to apply the code given as "function" (the macro argument) to each element of the (alpha,delta) arrays in turn. Before applying this conversion function, each element is first checked for "bad" coordinates (indicated by the value AST__BAD) and appropriate "bad" result values are assigned if necessary. */ #define TRAN_ARRAY(function) \ for ( point = 0; point < npoint; point++ ) { \ if ( ( alpha[ point ] == AST__BAD ) || \ ( delta[ point ] == AST__BAD ) ) { \ alpha[ point ] = AST__BAD; \ delta[ point ] = AST__BAD; \ } else { \ function \ } \ } /* Classify the SLALIB sky coordinate conversion to be applied. */ ct = map->cvttype[ cvt ]; switch ( ct ) { /* Add E-terms of aberration. */ /* -------------------------- */ /* Add or subtract (for the inverse) the E-terms from each coordinate pair in turn, returning the results to the same arrays. */ case AST__SLA_ADDET: if ( forward ) { TRAN_ARRAY(palAddet( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } else { TRAN_ARRAY(palSubet( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } break; /* Subtract E-terms of aberration. */ /* ------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_SUBET: if ( forward ) { TRAN_ARRAY(palSubet( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } else { TRAN_ARRAY(palAddet( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } break; /* Apply Bessel-Newcomb pre-IAU 1976 (FK4) precession model. */ /* --------------------------------------------------------- */ /* Since we are transforming a sequence of points, first set up the required precession matrix, swapping the argument order to get the inverse matrix if required. */ case AST__SLA_PREBN: { double epoch1 = forward ? args[ 0 ] : args[ 1 ]; double epoch2 = forward ? args[ 1 ] : args[ 0 ]; double precess_matrix[ 3 ][ 3 ]; double vec1[ 3 ]; double vec2[ 3 ]; palPrebn( epoch1, epoch2, precess_matrix ); /* For each point in the (alpha,delta) arrays, convert to Cartesian coordinates, apply the precession matrix, convert back to polar coordinates and then constrain the longitude result to lie in the range 0 to 2*pi (palDcc2s doesn't do this itself). */ TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDmxv( precess_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm( alpha[ point ] );) } break; /* Apply IAU 1975 (FK5) precession model. */ /* -------------------------------------- */ /* This is handled in the same way as above, but using the appropriate FK5 precession matrix. */ case AST__SLA_PREC: { double epoch1 = forward ? args[ 0 ] : args[ 1 ]; double epoch2 = forward ? args[ 1 ] : args[ 0 ]; double precess_matrix[ 3 ][ 3 ]; double vec1[ 3 ]; double vec2[ 3 ]; palPrec( epoch1, epoch2, precess_matrix ); TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDmxv( precess_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm( alpha[ point ] );) } break; /* Convert FK4 to FK5 (no proper motion or parallax). */ /* -------------------------------------------------- */ /* Apply the conversion to each point. */ case AST__SLA_FK45Z: if ( forward ) { TRAN_ARRAY(palFk45z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) /* The inverse transformation is also straightforward, except that we need a couple of dummy variables as function arguments. */ } else { double dr1950; double dd1950; TRAN_ARRAY(palFk54z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point, &dr1950, &dd1950 );) } break; /* Convert FK5 to FK4 (no proper motion or parallax). */ /* -------------------------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_FK54Z: if ( forward ) { double dr1950; double dd1950; TRAN_ARRAY(palFk54z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point, &dr1950, &dd1950 );) } else { TRAN_ARRAY(palFk45z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } break; /* Convert geocentric apparent to mean place. */ /* ------------------------------------------ */ /* Since we are transforming a sequence of points, first set up the required parameter array. Than apply this to each point in turn. */ case AST__SLA_AMP: { if( !extra ) { if( args[ 1 ] != eq_cache || args[ 0 ] != ep_cache ) { eq_cache = args[ 1 ]; ep_cache = args[ 0 ]; palMappa( eq_cache, ep_cache, amprms_cache ); } extra = astStore( NULL, amprms_cache, sizeof( double )*21 ); map->cvtextra[ cvt ] = extra; } if ( forward ) { TRAN_ARRAY(palAmpqk( alpha[ point ], delta[ point ], extra, alpha + point, delta + point );) /* The inverse uses the same parameter array but converts from mean place to geocentric apparent. */ } else { TRAN_ARRAY(palMapqkz( alpha[ point ], delta[ point ], extra, alpha + point, delta + point );) } } break; /* Convert mean place to geocentric apparent. */ /* ------------------------------------------ */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_MAP: { if( !extra ) { if( args[ 0 ] != eq_cache || args[ 1 ] != ep_cache ) { eq_cache = args[ 0 ]; ep_cache = args[ 1 ]; palMappa( eq_cache, ep_cache, amprms_cache ); } extra = astStore( NULL, amprms_cache, sizeof( double )*21 ); map->cvtextra[ cvt ] = extra; } if ( forward ) { TRAN_ARRAY(palMapqkz( alpha[ point ], delta[ point ], extra, alpha + point, delta + point );) } else { TRAN_ARRAY(palAmpqk( alpha[ point ], delta[ point ], extra, alpha + point, delta + point );) } } break; /* Convert ecliptic coordinates to J2000.0 equatorial. */ /* --------------------------------------------------- */ /* Since we are transforming a sequence of points, first set up the required conversion matrix (the conversion is a rotation). */ case AST__SLA_ECLEQ: { double convert_matrix[ 3 ][ 3 ]; double precess_matrix[ 3 ][ 3 ]; double rotate_matrix[ 3 ][ 3 ]; double vec1[ 3 ]; double vec2[ 3 ]; /* Obtain the matrix that precesses equatorial coordinates from J2000.0 to the required date. Also obtain the rotation matrix that converts from equatorial to ecliptic coordinates. */ palPrec( 2000.0, palEpj( args[ 0 ] ), precess_matrix ); palEcmat( args[ 0 ], rotate_matrix ); /* Multiply these matrices to give the overall matrix that converts from equatorial J2000.0 coordinates to ecliptic coordinates for the required date. */ palDmxm( rotate_matrix, precess_matrix, convert_matrix ); /* Apply the conversion by transforming from polar to Cartesian coordinates, multiplying by the inverse conversion matrix and converting back to polar coordinates. Then constrain the longitude result to lie in the range 0 to 2*pi (palDcc2s doesn't do this itself). */ if ( forward ) { TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDimxv( convert_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm ( alpha[ point ] );) /* The inverse conversion is the same except that we multiply by the forward conversion matrix (palDmxv instead of palDimxv). */ } else { TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDmxv( convert_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm ( alpha[ point ] );) } } break; /* Convert equatorial J2000.0 to ecliptic coordinates. */ /* --------------------------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_EQECL: { double convert_matrix[ 3 ][ 3 ]; double precess_matrix[ 3 ][ 3 ]; double rotate_matrix[ 3 ][ 3 ]; double vec1[ 3 ]; double vec2[ 3 ]; /* Create the conversion matrix. */ palPrec( 2000.0, palEpj( args[ 0 ] ), precess_matrix ); palEcmat( args[ 0 ], rotate_matrix ); palDmxm( rotate_matrix, precess_matrix, convert_matrix ); /* Apply it. */ if ( forward ) { TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDmxv( convert_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm ( alpha[ point ] );) } else { TRAN_ARRAY(palDcs2c( alpha[ point ], delta[ point ], vec1 ); palDimxv( convert_matrix, vec1, vec2 ); palDcc2s( vec2, alpha + point, delta + point ); alpha[ point ] = palDranrm ( alpha[ point ] );) } } break; /* Convert ICRS to J2000.0 equatorial. */ /* ----------------------------------- */ /* Apply the conversion to each point. */ case AST__SLA_HFK5Z: if ( forward ) { double dr5; double dd5; TRAN_ARRAY(palHfk5z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point, &dr5, &dd5 );) /* The inverse simply uses the inverse SLALIB function. */ } else { TRAN_ARRAY(palFk5hz( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) } break; /* Convert J2000.0 to ICRS equatorial. */ /* ----------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_FK5HZ: if ( forward ) { TRAN_ARRAY(palFk5hz( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point );) /* The inverse simply uses the inverse SLALIB function. */ } else { double dr5; double dd5; TRAN_ARRAY(palHfk5z( alpha[ point ], delta[ point ], args[ 0 ], alpha + point, delta + point, &dr5, &dd5 );) } break; /* Convert horizon to equatorial. */ /* ------------------------------ */ /* Apply the conversion to each point. */ case AST__SLA_DH2E: if ( forward ) { TRAN_ARRAY(Dh2e( alpha[ point ], delta[ point ], args[ 0 ], args[ 1 ], alpha + point, delta + point, status );) /* The inverse simply uses the inverse SLALIB function. */ } else { TRAN_ARRAY(De2h( alpha[ point ], delta[ point ], args[ 0 ], args[ 1 ], alpha + point, delta + point, status );) } break; /* Convert equatorial to horizon. */ /* ------------------------------ */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_DE2H: if ( forward ) { TRAN_ARRAY(De2h( alpha[ point ], delta[ point ], args[ 0 ], args[ 1 ], alpha + point, delta + point, status );) /* The inverse simply uses the inverse SLALIB function. */ } else { TRAN_ARRAY(Dh2e( alpha[ point ], delta[ point ], args[ 0 ], args[ 1 ], alpha + point, delta + point, status );) } break; /* Convert galactic coordinates to J2000.0 equatorial. */ /* --------------------------------------------------- */ /* Apply the conversion to each point. */ case AST__SLA_GALEQ: if ( forward ) { TRAN_ARRAY(palGaleq( alpha[ point ], delta[ point ], alpha + point, delta + point );) /* The inverse simply uses the inverse SLALIB function. */ } else { TRAN_ARRAY(palEqgal( alpha[ point ], delta[ point ], alpha + point, delta + point );) } break; /* Convert J2000.0 equatorial to galactic coordinates. */ /* --------------------------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_EQGAL: if ( forward ) { TRAN_ARRAY(palEqgal( alpha[ point ], delta[ point ], alpha + point, delta + point );) } else { TRAN_ARRAY(palGaleq( alpha[ point ], delta[ point ], alpha + point, delta + point );) } break; /* Convert galactic to supergalactic coordinates. */ /* ---------------------------------------------- */ /* Apply the conversion to each point. */ case AST__SLA_GALSUP: if ( forward ) { TRAN_ARRAY(palGalsup( alpha[ point ], delta[ point ], alpha + point, delta + point );) /* The inverse simply uses the inverse SLALIB function. */ } else { TRAN_ARRAY(palSupgal( alpha[ point ], delta[ point ], alpha + point, delta + point );) } break; /* Convert supergalactic coordinates to galactic. */ /* ---------------------------------------------- */ /* This is the same as above, but with the forward and inverse cases transposed. */ case AST__SLA_SUPGAL: if ( forward ) { TRAN_ARRAY(palSupgal( alpha[ point ], delta[ point ], alpha + point, delta + point );) } else { TRAN_ARRAY(palGalsup( alpha[ point ], delta[ point ], alpha + point, delta + point );) } break; /* If the conversion type was not recognised, then report an error (this should not happen unless validation in astSlaAdd has failed to detect a bad value previously). */ default: astError( AST__SLAIN, "astTransform(%s): Corrupt %s contains " "invalid SLALIB sky coordinate conversion code (%d).", status, astGetClass( this ), astGetClass( this ), (int) ct ); break; /* Convert any STP coordinates to J2000 equatorial. */ /* ------------------------------------------------ */ case AST__HPCEQ: case AST__HPREQ: case AST__HEEQ: { /* Get the code for the appropriate 3D STP coordinate system to use. Also, get a point to the observer position, if needed. */ if( ct == AST__HPCEQ ) { sys = AST__HPC; obs = args + 1; } else if( ct == AST__HPREQ ) { sys = AST__HPR; obs = args + 1; } else { sys = AST__GSE; obs = NULL; } /* Store the 3D positions to be transformed. The supplied arrays are used for the longitude and latitude values. No radius values are supplied. (a value of 1AU will be used in the transformation). */ p[0] = alpha; p[1] = delta; p[2] = NULL; /* Convert the supplied positions to (or from) AST__HEQ, ignoring the distinction between the origin of the input and output systems (which is appropriate since we are considering points at an infinite distance from the observer). */ if( forward ) { STPConv( args[ 0 ], 1, npoint, sys, obs, p, AST__HAQ, NULL, p, status ); } else { STPConv( args[ 0 ], 1, npoint, AST__HAQ, NULL, p, sys, obs, p, status ); } } break; /* Convert J2000 equatorial to any STP coordinates. */ /* ------------------------------------------------ */ /* Same as above, but with forward and inverse cases transposed. */ case AST__EQHPC: case AST__EQHPR: case AST__EQHE: { /* Get the code for the appropriate 3D STP coordinate system to use. Also, get a point to the observer position, if needed. */ if( ct == AST__EQHPC ) { sys = AST__HPC; obs = args + 1; } else if( ct == AST__EQHPR ) { sys = AST__HPR; obs = args + 1; } else { sys = AST__GSE; obs = NULL; } /* Store the 3D positions to be transformed. The supplied arrays are used for the longitude and latitude values. No radius values are supplied. (a value of 1AU will be used in the transformation). */ p[0] = alpha; p[1] = delta; p[2] = NULL; /* Convert the supplied positions from (or to) AST__HEQ, ignoring the distinction between the origin of the input and output systems (which is appropriate since we are considering points at an infinite distance from the observer). */ if( forward ) { STPConv( args[ 0 ], 1, npoint, AST__HAQ, NULL, p, sys, obs, p, status ); } else { STPConv( args[ 0 ], 1, npoint, sys, obs, p, AST__HAQ, NULL, p, status ); } } break; /* Convert dynamical J2000.0 to ICRS. */ /* ---------------------------------- */ /* Apply the conversion to each point. */ case AST__J2000H: J2000H( forward, npoint, alpha, delta, status ); break; /* Convert ICRS to dynamical J2000.0 */ /* ---------------------------------- */ case AST__HJ2000: J2000H( !(forward), npoint, alpha, delta, status ); break; /* Convert HA to RA, or RA to HA */ /* ----------------------------- */ /* The forward and inverse transformations are the same. */ case AST__H2R: case AST__R2H: TRAN_ARRAY( alpha[ point ] = args[ 0 ] - alpha[ point ]; ) break; } } } /* If an error has occurred and a new PointSet may have been created, then clean up by annulling it. In any case, ensure that a NULL result is returned.*/ if ( !astOK ) { if ( !out ) result = astAnnul( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; /* Undefine macros local to this function. */ #undef TRAN_ARRAY } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for SlaMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for SlaMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstSlaMap *in; /* Pointer to input SlaMap */ AstSlaMap *out; /* Pointer to output SlaMap */ int cvt; /* Loop counter for coordinate conversions */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output SlaMap structures. */ in = (AstSlaMap *) objin; out = (AstSlaMap *) objout; /* For safety, first clear any references to the input memory from the output SlaMap. */ out->cvtargs = NULL; out->cvtextra = NULL; out->cvttype = NULL; /* Allocate memory for the output array of argument list pointers. */ out->cvtargs = astMalloc( sizeof( double * ) * (size_t) in->ncvt ); /* Allocate memory for the output array of extra (intermediate) values. */ out->cvtextra = astMalloc( sizeof( double * ) * (size_t) in->ncvt ); /* If necessary, allocate memory and make a copy of the input array of sky coordinate conversion codes. */ if ( in->cvttype ) out->cvttype = astStore( NULL, in->cvttype, sizeof( int ) * (size_t) in->ncvt ); /* If OK, loop through each conversion in the input SlaMap and make a copy of its argument list, storing the new pointer in the output argument list array. */ if ( astOK ) { for ( cvt = 0; cvt < in->ncvt; cvt++ ) { out->cvtargs[ cvt ] = astStore( NULL, in->cvtargs[ cvt ], astSizeOf( in->cvtargs[ cvt ] ) ); out->cvtextra[ cvt ] = astStore( NULL, in->cvtextra[ cvt ], astSizeOf( in->cvtextra[ cvt ] ) ); } /* If an error occurred while copying the argument lists, loop through the conversions again and clean up by ensuring that the new memory allocated for each argument list is freed. */ if ( !astOK ) { for ( cvt = 0; cvt < in->ncvt; cvt++ ) { out->cvtargs[ cvt ] = astFree( out->cvtargs[ cvt ] ); } } } /* If an error occurred, free all other memory allocated above. */ if ( !astOK ) { out->cvtargs = astFree( out->cvtargs ); out->cvtextra = astFree( out->cvtextra ); out->cvttype = astFree( out->cvttype ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for SlaMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for SlaMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstSlaMap *this; /* Pointer to SlaMap */ int cvt; /* Loop counter for coordinate conversions */ /* Obtain a pointer to the SlaMap structure. */ this = (AstSlaMap *) obj; /* Loop to free the memory containing the argument list for each sky coordinate conversion. */ for ( cvt = 0; cvt < this->ncvt; cvt++ ) { this->cvtargs[ cvt ] = astFree( this->cvtargs[ cvt ] ); this->cvtextra[ cvt ] = astFree( this->cvtextra[ cvt ] ); } /* Free the memory holding the array of conversion types and the array of argument list pointers. */ this->cvtargs = astFree( this->cvtargs ); this->cvtextra = astFree( this->cvtextra ); this->cvttype = astFree( this->cvttype ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SlaMap objects. * Type: * Private function. * Synopsis: * #include "slamap.h" * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the SlaMap class to an output Channel. * Parameters: * this * Pointer to the SlaMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstSlaMap *this; /* Pointer to the SlaMap structure */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */ const char *argdesc[ MAX_SLA_ARGS ]; /* Pointers to argument descriptions */ const char *comment; /* Pointer to comment string */ const char *sval; /* Pointer to string value */ int iarg; /* Loop counter for arguments */ int icvt; /* Loop counter for conversion steps */ int ival; /* Integer value */ int nargs; /* Number of conversion arguments */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SlaMap structure. */ this = (AstSlaMap *) this_object; /* Write out values representing the instance variables for the SlaMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Number of conversion steps. */ /* --------------------------- */ /* Regard this as "set" if it is non-zero. */ ival = this->ncvt; set = ( ival != 0 ); astWriteInt( channel, "Nsla", set, 0, ival, "Number of conversion steps" ); /* Write out data for each conversion step... */ for ( icvt = 0; icvt < this->ncvt; icvt++ ) { /* Conversion type. */ /* ---------------- */ /* Change each conversion type code into an equivalent string and obtain associated descriptive information. If the conversion code was not recognised, report an error and give up. */ if ( astOK ) { sval = CvtString( this->cvttype[ icvt ], &comment, &nargs, argdesc, status ); if ( astOK && !sval ) { astError( AST__SLAIN, "astWrite(%s): Corrupt %s contains invalid SLALIB " "sky coordinate conversion code (%d).", status, astGetClass( channel ), astGetClass( this ), (int) this->cvttype[ icvt ] ); break; } /* Create an appropriate keyword and write out the conversion code information. */ (void) sprintf( key, "Sla%d", icvt + 1 ); astWriteString( channel, key, 1, 1, sval, comment ); /* Write out data for each conversion argument... */ for ( iarg = 0; iarg < nargs; iarg++ ) { /* Arguments. */ /* ---------- */ /* Create an appropriate keyword and write out the argument value, accompanied by the descriptive comment obtained above. */ (void) sprintf( key, "Sla%d%c", icvt + 1, ALPHABET[ iarg ] ); astWriteDouble( channel, key, 1, 1, this->cvtargs[ icvt ][ iarg ], argdesc[ iarg ] ); } /* Quit looping if an error occurs. */ if ( !astOK ) break; } } /* Undefine macros local to this function. */ #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASlaMap and astCheckSlaMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SlaMap,Mapping) astMAKE_CHECK(SlaMap) AstSlaMap *astSlaMap_( int flags, const char *options, int *status, ...) { /* *++ * Name: c astSlaMap f AST_SLAMAP * Purpose: * Create an SlaMap. * Type: * Public function. * Synopsis: c #include "slamap.h" c AstSlaMap *astSlaMap( int flags, const char *options, ... ) f RESULT = AST_SLAMAP( FLAGS, OPTIONS, STATUS ) * Class Membership: * SlaMap constructor. * Description: * This function creates a new SlaMap and optionally initialises * its attributes. * * An SlaMap is a specialised form of Mapping which can be used to * represent a sequence of conversions between standard celestial * (longitude, latitude) coordinate systems. * * When an SlaMap is first created, it simply performs a unit c (null) Mapping on a pair of coordinates. Using the astSlaAdd f (null) Mapping on a pair of coordinates. Using the AST_SLAADD c function, a series of coordinate conversion steps may then be f routine, a series of coordinate conversion steps may then be * added, selected from those provided by the SLALIB Positional * Astronomy Library (Starlink User Note SUN/67). This allows * multi-step conversions between a variety of celestial coordinate * systems to be assembled out of the building blocks provided by * SLALIB. * * For details of the individual coordinate conversions available, c see the description of the astSlaAdd function. f see the description of the AST_SLAADD routine. * Parameters: c flags f FLAGS = INTEGER (Given) c This parameter is reserved for future use and should currently f This argument is reserved for future use and should currently * always be set to zero. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SlaMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SlaMap. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSlaMap() f AST_SLAMAP = INTEGER * A pointer to the new SlaMap. * Notes: * - The Nin and Nout attributes (number of input and output * coordinates) for an SlaMap are both equal to 2. The first * coordinate is the celestial longitude and the second coordinate * is the celestial latitude. All coordinate values are in radians. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSlaMap *new; /* Pointer to the new SlaMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SlaMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSlaMap( NULL, sizeof( AstSlaMap ), !class_init, &class_vtab, "SlaMap", flags ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SlaMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new SlaMap. */ return new; } AstSlaMap *astSlaMapId_( int flags, const char *options, ... ) { /* * Name: * astSlaMapId_ * Purpose: * Create an SlaMap. * Type: * Private function. * Synopsis: * #include "slamap.h" * AstSlaMap *astSlaMapId_( int flags, const char *options, ... ) * Class Membership: * SlaMap constructor. * Description: * This function implements the external (public) interface to the * astSlaMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astSlaMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astSlaMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astSlaMap_. * Returned Value: * The ID value associated with the new SlaMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSlaMap *new; /* Pointer to the new SlaMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SlaMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSlaMap( NULL, sizeof( AstSlaMap ), !class_init, &class_vtab, "SlaMap", flags ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SlaMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new SlaMap. */ return astMakeId( new ); } AstSlaMap *astInitSlaMap_( void *mem, size_t size, int init, AstSlaMapVtab *vtab, const char *name, int flags, int *status ) { /* *+ * Name: * astInitSlaMap * Purpose: * Initialise an SlaMap. * Type: * Protected function. * Synopsis: * #include "slamap.h" * AstSlaMap *astInitSlaMap( void *mem, size_t size, int init, * AstSlaMapVtab *vtab, const char *name, * int flags ) * Class Membership: * SlaMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new SlaMap object. It allocates memory (if necessary) to accommodate * the SlaMap plus any additional data associated with the derived class. * It then initialises an SlaMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for an SlaMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SlaMap is to be initialised. * This must be of sufficient size to accommodate the SlaMap data * (sizeof(SlaMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the SlaMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the SlaMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the SlaMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new SlaMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astClass * method). * flags * This parameter is reserved for future use. It is currently ignored. * Returned Value: * A pointer to the new SlaMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstSlaMap *new; /* Pointer to the new SlaMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSlaMapVtab( vtab, name ); /* Initialise a Mapping structure (the parent class) as the first component within the SlaMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstSlaMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, 2, 2, 1, 1 ); if ( astOK ) { /* Initialise the SlaMap data. */ /* --------------------------- */ /* The initial state is with no SLALIB conversions set, in which condition the SlaMap simply implements a unit mapping. */ new->ncvt = 0; new->cvtargs = NULL; new->cvtextra = NULL; new->cvttype = NULL; /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstSlaMap *astLoadSlaMap_( void *mem, size_t size, AstSlaMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSlaMap * Purpose: * Load a SlaMap. * Type: * Protected function. * Synopsis: * #include "slamap.h" * AstSlaMap *astLoadSlaMap( void *mem, size_t size, * AstSlaMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * SlaMap loader. * Description: * This function is provided to load a new SlaMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SlaMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a SlaMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the SlaMap is to be * loaded. This must be of sufficient size to accommodate the * SlaMap data (sizeof(SlaMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SlaMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SlaMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSlaMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SlaMap. If this is NULL, a pointer to * the (static) virtual function table for the SlaMap class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SlaMap" is used instead. * Returned Value: * A pointer to the new SlaMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstSlaMap *new; /* Pointer to the new SlaMap */ char *sval; /* Pointer to string value */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */ const char *argdesc[ MAX_SLA_ARGS ]; /* Pointers to argument descriptions */ const char *comment; /* Pointer to comment string */ int iarg; /* Loop counter for arguments */ int icvt; /* Loop counter for conversion steps */ int nargs; /* Number of conversion arguments */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SlaMap. In this case the SlaMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSlaMap ); vtab = &class_vtab; name = "SlaMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSlaMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SlaMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SlaMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Number of conversion steps. */ /* --------------------------- */ /* Read the number of conversion steps and allocate memory to hold data for each step. */ new->ncvt = astReadInt( channel, "nsla", 0 ); if ( new->ncvt < 0 ) new->ncvt = 0; new->cvttype = astMalloc( sizeof( int ) * (size_t) new->ncvt ); new->cvtargs = astMalloc( sizeof( double * ) * (size_t) new->ncvt ); new->cvtextra = astMalloc( sizeof( double * ) * (size_t) new->ncvt ); /* If an error occurred, ensure that all allocated memory is freed. */ if ( !astOK ) { new->cvttype = astFree( new->cvttype ); new->cvtargs = astFree( new->cvtargs ); new->cvtextra = astFree( new->cvtextra ); /* Otherwise, initialise the argument pointer array. */ } else { for ( icvt = 0; icvt < new->ncvt; icvt++ ) { new->cvtargs[ icvt ] = NULL; new->cvtextra[ icvt ] = NULL; } /* Read in data for each conversion step... */ for ( icvt = 0; icvt < new->ncvt; icvt++ ) { /* Conversion type. */ /* ---------------- */ /* Create an appropriate keyword and read the string representation of the conversion type. */ (void) sprintf( key, "sla%d", icvt + 1 ); sval = astReadString( channel, key, NULL ); /* If no value was read, report an error. */ if ( astOK ) { if ( !sval ) { astError( AST__BADIN, "astRead(%s): An SLALIB sky coordinate conversion " "type is missing from the input SlaMap data.", status, astGetClass( channel ) ); /* Otherwise, convert the string representation into the required conversion type code. */ } else { new->cvttype[ icvt ] = CvtCode( sval, status ); /* If the string was not recognised, report an error. */ if ( new->cvttype[ icvt ] == AST__SLA_NULL ) { astError( AST__BADIN, "astRead(%s): Invalid SLALIB sky conversion " "type \"%s\" in SlaMap data.", status, astGetClass( channel ), sval ); } } /* Free the memory holding the string value. */ sval = astFree( sval ); } /* Obtain the number of arguments associated with the conversion and allocate memory to hold them. */ (void) CvtString( new->cvttype[ icvt ], &comment, &nargs, argdesc, status ); new->cvtargs[ icvt ] = astMalloc( sizeof( double ) * (size_t) nargs ); /* Read in data for each argument... */ if ( astOK ) { for ( iarg = 0; iarg < nargs; iarg++ ) { /* Arguments. */ /* ---------- */ /* Create an appropriate keyword and read each argument value. */ (void) sprintf( key, "sla%d%c", icvt + 1, ALPHABET[ iarg ] ); new->cvtargs[ icvt ][ iarg ] = astReadDouble( channel, key, AST__BAD ); } } /* Quit looping if an error occurs. */ if ( !astOK ) break; } } /* If an error occurred, clean up by deleting the new SlaMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new SlaMap pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astSlaAdd_( AstSlaMap *this, const char *cvt, const double args[], int *status ) { if ( !astOK ) return; (**astMEMBER(this,SlaMap,SlaAdd))( this, cvt, args, status ); } ./ast-7.3.3/fshiftmap.c0000644000175000017500000000612212262533650013270 0ustar olesoles/* *+ * Name: * fshiftmap.c * Purpose: * Define a FORTRAN 77 interface to the AST ShiftMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the ShiftMap class. * Routines Defined: * AST_ISASHIFTMAP * AST_SHIFTMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 18-AUG-2003 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "shiftmap.h" /* C interface to the ShiftMap class */ F77_LOGICAL_FUNCTION(ast_isashiftmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASHIFTMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAShiftMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_shiftmap)( INTEGER(NAXES), DOUBLE(SHIFT), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NAXES) GENPTR_DOUBLE(SHIFT) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_SHIFTMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astShiftMap( *NAXES, SHIFT, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/ffluxframe.c0000644000175000017500000000620612262533650013451 0ustar olesoles/* *+ * Name: * ffluxframe.c * Purpose: * Define a FORTRAN 77 interface to the AST FluxFrame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the FluxFrame class. * Routines Defined: * AST_ISAFLUXFRAME * AST_FLUXFRAME * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 1-DEC-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "fluxframe.h" /* C interface to the FluxFrame class */ F77_LOGICAL_FUNCTION(ast_isafluxframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAFLUXFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsAFluxFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_fluxframe)( DOUBLE(SPECVAL), INTEGER(SPECFRM), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_DOUBLE(SPECVAL) GENPTR_INTEGER(SPECFRM) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_FLUXFRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astFluxFrame( *SPECVAL, astI2P( *SPECFRM ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/config.guess0000755000175000017500000012633312245363436013476 0ustar olesoles#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-05-15' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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 # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit ;; sgi:OpenBSD:*:*) echo mips64-unknown-openbsd${UNAME_RELEASE} exit ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:* | i*:windows32*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ./ast-7.3.3/ast_test.c0000644000175000017500000000640612262533650013142 0ustar olesoles/* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "ast.h" /* AST C interface definition */ /* C header files. */ /* --------------- */ #include /* Main function. */ /* ============== */ int main( int argc, char *argv[] ) { /* *+ * Name: * ast_test * Purpose: * Test installation of the AST library. * Type: * C program. * Description: * This program performs a simple test (without using graphics) of * the AST library, to check that it is correctly installed. It is * not an exhaustive test of the system. * Arguments: * None. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 19-NOV-1997 (RFWS); * Original version. *- */ /* Local Constants: */ #define NCOORD 10 /* Number of coordinates to transform */ /* Local Variables: */ AstFrameSet *cvt; /* Pointer to conversion FrameSet */ AstSkyFrame *sky1; /* Pointer to first SkyFrame */ AstSkyFrame *sky2; /* Pointer to second SkyFrame */ double xin[ NCOORD ]; /* Input coordinate array */ double xout[ NCOORD ]; /* Output coordinate array */ double yin[ NCOORD ]; /* Input coordinate array */ double yout[ NCOORD ]; /* Output coordinate array */ int i; /* Loop counter for coordinates */ /* Begin an AST context. */ astBegin; /* Create two SkyFrames. */ sky1 = astSkyFrame( "system = FK4_NO_E, equinox = B1920, epoch = B1958" ); sky2 = astSkyFrame( "system = ecliptic, equinox = J2001" ); /* Create a FrameSet describing the conversion between them. */ cvt = astConvert( sky1, sky2, "" ); /* If successful, set up some input coordinates. */ if ( cvt != AST__NULL ) { for ( i = 0; i < NCOORD; i++ ) { xin[ i ] = 0.1 * (double) i; yin[ i ] = 0.2 * (double) i; } /* Display the FrameSet. */ astShow( cvt ); printf( "\n"); /* Activate reporting of coordinate transformations. */ astSet( cvt, "Report = 1" ); /* Perform the forward transformation. */ astTran2( cvt, 10, xin, yin, 1, xout, yout ); printf( "\n"); /* Perform the inverse transformation. */ astTran2( cvt, 10, xout, yout, 0, xin, yin ); } /* End the AST context. */ astEnd; /* Return an error status. */ return astOK ? 0 : 1; /* Undefine local macros. */ #undef NCOORD } ./ast-7.3.3/fspecmap.c0000644000175000017500000000710212262533650013104 0ustar olesoles/* *+ * Name: * fspecmap.c * Purpose: * Define a FORTRAN 77 interface to the AST SpecMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the SpecMap class. * Routines Defined: * AST_ISASPECMAP * AST_SPECADD * AST_SPECMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 11-NOV-2002 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "specmap.h" /* C interface to the SpecMap class */ F77_LOGICAL_FUNCTION(ast_isaspecmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASPECMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsASpecMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_specadd)( INTEGER(THIS), CHARACTER(CVT), DOUBLE_ARRAY(ARGS), INTEGER(STATUS) TRAIL(CVT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(CVT) GENPTR_DOUBLE_ARRAY(ARGS) char *cvt; astAt( "AST_SPECADD", NULL, 0 ); astWatchSTATUS( cvt = astString( CVT, CVT_length ); astSpecAdd( astI2P( *THIS ), cvt, ARGS ); astFree( cvt ); ) } F77_INTEGER_FUNCTION(ast_specmap)( INTEGER(NIN), INTEGER(FLAGS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NIN) GENPTR_INTEGER(FLAGS) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_SPECMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astSpecMap( *NIN, *FLAGS, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/frameset.h0000644000175000017500000006756312262533650013142 0ustar olesoles/* *+ * Name: * frameset.h * Type: * C include file. * Purpose: * Define the interface to the FrameSet class. * Invocation: * #include "frameset.h" * Description: * This include file defines the interface to the FrameSet class and * provides the type definitions, function prototypes and macros, etc. * needed to use this class. * * A FrameSet consists of a set of one or more Frames, which are * inter-related by Mappings in such a way that it is possible to * obtain a Mapping between any pair of the Frames. The Frames are * identified by an integer index, with Frames being numbered * consecutively from one as they are added to the FrameSet. * * At any time, there is a "base" Frame and a "current" Frame * (which are allowed to be the same). Any of the Frames may be * nominated to hold these positions, and the choice is determined * by the values of the FrameSet's Base and Current attributes * which hold the indices of the relevant Frames. By default, the * first Frame added to a FrameSet is its base Frame, and the last * one added is its current Frame. * * The base Frame describes the "native" coordinate system of * whatever the FrameSet is used to calibrate (e.g. the pixel * coordinates of an image) and the current Frame describes the * "apparent" coordinate system in which it should be viewed * (e.g. displayed, etc.). The other Frames represent alternative * coordinate systems which may be selected by making them current. * * When Frame methods are invoked on a FrameSet (e.g. to obtain a * Title value or to determine the number of axes), they are * applied to the current Frame. Thus, a FrameSet may be used in * place of its current Frame in most situations. * * When Mapping methods are invoked on a FrameSet, the Mapping used * is the one between its base Frame and its current Frame. Thus, a * FrameSet may be used to convert "native" coordinates into * "apparent" ones, and vice versa. A FrameSet may also be * inverted, which has the effect of interchanging its base and * current Frames (and hence of reversing the Mapping between * them). * * The FrameSet class also defines methods of its own, which are * used to manage the Frames and Mappings that it contains and to * convert between coordinate systems described by different * FrameSets. * Inheritance: * The FrameSet class inherits from the Frame class. * Attributes Over-Ridden: * Digits (integer) * Direction(axis) (integer) * Domain (string) * Format(axis) (string) * Label(axis) (string) * MatchEnd (integer) * MaxAxes (integer) * MinAxes (integer) * Naxes (integer) * Permute (integer) * PreserveAxes (integer) * Symbol(axis) (string) * Title (string) * Unit(axis) (string) * The FrameSet acquires all of these attributes from its * current Frame, so their meanings, values and defaults are * determined by this Frame and may change if a different * current Frame is selected. * Nin (integer) * Nout (integer) * TranForward (integer) * TranInverse (integer) * The FrameSet interprets all of these as applying to the * Mapping that converts coordinates between its base Frame and * its current Frame, so their values may change if a different * base or current Frame is selected. * Invert (integer) * Report (integer) * The FrameSet interprets these as applying to the Mapping that * converts coordinates between its base Frame and its current * Frame, but their values are not affected by selecing a * different base or current Frame. * New Attributes Defined: * Base (integer) * The (one-based) index of the Frame which is to be regarded as * the base Frame in the FrameSet. By default, this is the first * Frame added to the FrameSet (i.e. when it was created), * unless the Frameset has been inverted, in which case it is * the last Frame added. Inverting a FrameSet interchanges the * values of its Base and Current attributes. * Current (integer) * The (one-based) index of the Frame which is to be regarded as * the current Frame in the FrameSet. By default, this is the * last Frame added to the FrameSet, unless the Frameset has * been inverted, in which case it is the first Frame added * (i.e. when the FrameSet was created). Inverting a FrameSet * interchanges the values of its Base and Current attributes. * Nframe (integer) * A read-only value giving the number of Frames in a * FrameSet. This value will change as Frames are added or * removed. * Methods Over-Ridden: * Public: * astClear * Clear attribute values for a FrameSet. * astConvert * Determine how to convert between two coordinate systems. * astDistance * Calculate the distance between two points. * astFindFrame * Find a coordinate system with specified characteristics * astFormat * Format a coordinate value for a FrameSet axis. * astGetAxis * Obtain a pointer to a specified Axis from a FrameSet. * astGetNaxes * Determine how many axes a FrameSet has. * astGetNin * Get the number of input coordinates for a FrameSet. * astGetNout * Get the number of output coordinates for a FrameSet. * astNorm * Normalise a set of FrameSet coordinates. * astOffset * Calculate an offset along a geodesic curve. * astPermAxes * Permute the order of a FrameSet's axes. * astPickAxes * Create a new Frame by picking axes from a FrameSet. * astSetAxis * Set a new Axis for a FrameSet. * astSimplify * Simplify the Mappings in a FrameSet. * astTransform * Transform a set of points. * astUnformat * Read a formatted coordinate value for a FrameSet axis. * * Protected: * astAbbrev * Abbreviate a formatted FrameSet axis value by skipping leading * fields. * astClearDigits * Clear the value of the Digits attribute for a FrameSet. * astClearDirection * Clear the value of the Direction attribute for a FrameSet axis. * astClearDomain * Clear the value of the Domain attribute for a FrameSet. * astClearFormat * Clear the value of the Format attribute for a FrameSet axis. * astClearLabel * Clear the value of the Label attribute for a FrameSet axis. * astClearMatchEnd * Clear the value of the MatchEnd attribute for a FrameSet. * astClearMaxAxes * Clear the value of the MaxAxes attribute for a FrameSet. * astClearMinAxes * Clear the value of the MinAxes attribute for a FrameSet. * astClearPermute * Clear the value of the Permute attribute for a FrameSet. * astClearPreserveAxes * Clear the value of the PreserveAxes attribute for a FrameSet. * astClearSymbol * Clear the value of the Symbol attribute for a FrameSet axis. * astClearTitle * Clear the value of the Title attribute for a FrameSet. * astClearUnit * Clear the value of the Unit attribute for a FrameSet axis. * astConvertX * Determine how to convert between two coordinate systems. * astGap * Find a "nice" gap for tabulating FrameSet axis values. * astGetDigits * Get the value of the Digits attribute for a FrameSet. * astGetDirection * Get the value of the Direction attribute for a FrameSet axis. * astGetDomain * Get the value of the Domain attribute for a FrameSet. * astGetFormat * Get the value of the Format attribute for a FrameSet axis. * astGetLabel * Get the value of the Label attribute for a FrameSet axis. * astGetMatchEnd * Get the value of the MatchEnd attribute for a FrameSet. * astGetMaxAxes * Get the value of the MaxAxes attribute for a FrameSet. * astGetMinAxes * Get the value of the MinAxes attribute for a FrameSet. * astGetPerm * Access the axis permutation array for the current Frame of * a FrameSet. * astGetPermute * Get the value of the Permute attribute for a FrameSet. * astGetPreserveAxes * Get the value of the PreserveAxes attribute for a FrameSet. * astGetSymbol * Get the value of the Symbol attribute for a FrameSet axis. * astGetTitle * Get the value of the Title attribute for a FrameSet. * astGetTranForward * Determine if a Mapping can perform a "forward" coordinate * transformation. * astGetTranInverse * Determine if a Mapping can perform an "inverse" coordinate * transformation. * astGetUnit * Get the value of the Unit attribute for a FrameSet axis. * astMatch * Determine if conversion is possible between two coordinate systems. * astOverlay * Overlay the attributes of a template FrameSet on to another Frame. * astPrimaryFrame * Uniquely identify a primary Frame and one of its axes. * astReportPoints * Report the effect of transforming a set of points using a FrameSet. * astSetAttrib * Set an attribute value for a FrameSet. * astSetDigits * Set the value of the Digits attribute for a FrameSet. * astSetDirection * Set the value of the Direction attribute for a FrameSet axis. * astSetDomain * Set the value of the Domain attribute for a FrameSet. * astSetFormat * Set the value of the Format attribute for a FrameSet axis. * astSetLabel * Set the value of the Label attribute for a FrameSet axis. * astSetMatchEnd * Set the value of the MatchEnd attribute for a FrameSet. * astSetMaxAxes * Set the value of the MaxAxes attribute for a FrameSet. * astSetMinAxes * Set the value of the MinAxes attribute for a FrameSet. * astSetPermute * Set the value of the Permute attribute for a FrameSet. * astSetPreserveAxes * Set the value of the PreserveAxes attribute for a FrameSet. * astSetSymbol * Set the value of the Symbol attribute for a FrameSet axis. * astSetTitle * Set the value of the Title attribute for a FrameSet. * astSetUnit * Set the value of the Unit attribute for a FrameSet axis. * astSubFrame * Select axes from a FrameSet and convert to the new coordinate * system. * astTestDigits * Test if a value has been set for the Digits attribute of a * FrameSet. * astTestDirection * Test if a value has been set for the Direction attribute of a * FrameSet axis. * astTestDomain * Test if a value has been set for the Domain attribute of a * FrameSet. * astTestFormat * Test if a value has been set for the Format attribute of a * FrameSet axis. * astTestLabel * Test if a value has been set for the Label attribute of a * FrameSet axis. * astTestMatchEnd * Test if a value has been set for the MatchEnd attribute of a * FrameSet. * astTestMaxAxes * Test if a value has been set for the MaxAxes attribute of a * FrameSet. * astTestMinAxes * Test if a value has been set for the MinAxes attribute of a * FrameSet. * astTestPermute * Test if a value has been set for the Permute attribute of a * FrameSet. * astTestPreserveAxes * Test if a value has been set for the PreserveAxes attribute of a * FrameSet. * astTestSymbol * Test if a value has been set for the Symbol attribute of a * FrameSet axis. * astTestTitle * Test if a value has been set for the Title attribute of a FrameSet. * astTestUnit * Test if a value has been set for the Unit attribute of a FrameSet * axis. * astValidateAxis * Validate and permute a FrameSet's axis index. * astVSet * Set values for a FrameSet's attributes. * New Methods Defined: * Public: * astAddFrame * Add a Frame to a FrameSet to define a new coordinate system. * astGetFrame * Obtain a pointer to a specified Frame in a FrameSet. * astGetMapping * Obtain a Mapping between two Frames in a FrameSet. * astRemapFrame * Modify a Frame's relationshp to the other Frames in a FrameSet. * astRemoveFrame * Remove a Frame from a FrameSet. * * Protected: * astClearBase * Clear the value of the Base attribute for a FrameSet. * astClearCurrent * Clear the value of the Current attribute for a FrameSet. * astGetBase * Obtain the value of the Base attribute for a FrameSet. * astGetCurrent * Obtain the value of the Current attribute for a FrameSet. * astGetNframe * Determine the number of Frames in a FrameSet. * astSetBase * Set the value of the Base attribute for a FrameSet. * astSetCurrent * Set the value of the Current attribute for a FrameSet. * astTestBase * Test if a value has been set for the Base attribute of a FrameSet. * astTestCurrent * Test if a value has been set for the Current attribute of a * FrameSet. * astValidateFrameIndex * Validate a FrameSet Frame index number. * Other Class Functions: * Public: * astFrameSet * Create a FrameSet. * astIsAFrameSet * Test class membership. * * Protected: * astCheckFrameSet * Validate class membership. * astInitFrameSet * Initialise a FrameSet. * astInitFrameSetVtab * Initialise the virtual function table for the FrameSet class. * astLoadFrameSet * Load a FrameSet. * Macros: * None. * Type Definitions: * Public: * AstFrameSet * FrameSet object type. * Protected: * AstFrameSetVtab * FrameSet virtual function table type. * Macros: * Public: * AST__BASE * Expands to a constant int that may be used as a Frame index to * refer to a FrameSet's base Frame. * AST__CURRENT * Expands to a constant int that may be used as a Frame index to * refer to a FrameSet's current Frame. * AST__NOFRAME * Expands to a constant int that is guaranteed not to be valid when * used as a Frame index for a FrameSet. * * Protected: * None. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 16-FEB-1996 (RFWS): * Original version. * 5-JUN-1996 (RFWS): * Tidied up, etc. * 12-AUG-1996 (RFWS): * Added support for the public interface. * 25-SEP-1996 (RFWS): * Added I/O facilities. * 20-JAN-1998 (RFWS): * Implemented preservation of FrameSet integrity when attribute * values associated with the current Frame are modified. * 25-FEB-1998 (RFWS): * Over-ride the astUnformat method. * 8-JAN-2003 (DSB): * Added protected astInitFrameSetVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "frame.h" /* Parent Frame class */ /* Note that the usual setting of the FRAMESET_INCLUDED flag, which prevents this file being included more than once, must be deferred until after including the "frame.h" file. This is because "frame.h" needs to include the present interface definition (as a form of "forward reference") in order to have access to FrameSets itself. */ #if !defined( FRAMESET_INCLUDED ) #define FRAMESET_INCLUDED /* Macros. */ /* ======= */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif #define AST__BASE (0) /* Identify base Frame */ #define AST__CURRENT (-1) /* Identify current Frame */ #define AST__NOFRAME (-99) /* An invalid Frame index */ #define AST__ALLFRAMES (-199) /* A value representing all Frames */ #define AST__FRAMESET_GETALLVARIANTS_BUFF_LEN 200 /* Length for AllVariants buffer */ #define AST__FRAMESET_GETATTRIB_BUFF_LEN 200 /* Length for GetAtribb buffer */ /* Type Definitions. */ /* ================= */ /* FrameSet structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstFrameSet { /* Attributes inherited from the parent class. */ AstFrame parent; /* Parent class structure */ /* Attributes specific to objects in this class. */ AstFrame **frame; /* Array of Frame pointers */ AstMapping **map; /* Array of Mapping pointers */ int *varfrm; /* Array of variants Frames indicies */ int *invert; /* Array of Mapping Invert values */ int *link; /* Parent node index for each node */ int *node; /* Index of node associated with Frame */ int base; /* Index of base Frame */ int current; /* Index of current Frame */ int nframe; /* Number of Frames */ int nnode; /* Number of nodes */ } AstFrameSet; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstFrameSetVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstFrameVtab frame_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ AstFrame *(* GetFrame)( AstFrameSet *, int, int * ); AstMapping *(* GetMapping)( AstFrameSet *, int, int, int * ); int (* GetBase)( AstFrameSet *, int * ); int (* GetCurrent)( AstFrameSet *, int * ); int (* GetNframe)( AstFrameSet *, int * ); int (* TestBase)( AstFrameSet *, int * ); int (* TestCurrent)( AstFrameSet *, int * ); int (* ValidateFrameIndex)( AstFrameSet *, int, const char *, int * ); void (* AddFrame)( AstFrameSet *, int, AstMapping *, AstFrame *, int * ); void (* AddVariant)( AstFrameSet *, AstMapping *, const char *, int * ); void (* MirrorVariants)( AstFrameSet *, int, int * ); void (* ClearBase)( AstFrameSet *, int * ); void (* ClearCurrent)( AstFrameSet *, int * ); void (* RemapFrame)( AstFrameSet *, int, AstMapping *, int * ); void (* RemoveFrame)( AstFrameSet *, int, int * ); void (* SetBase)( AstFrameSet *, int, int * ); void (* SetCurrent)( AstFrameSet *, int, int * ); void (* ClearVariant)( AstFrameSet *, int * ); const char *(* GetVariant)( AstFrameSet *, int * ); void (* SetVariant)( AstFrameSet *, const char *, int * ); int (* TestVariant)( AstFrameSet *, int * ); const char *(* GetAllVariants)( AstFrameSet *, int * ); } AstFrameSetVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstFrameSetGlobals { AstFrameSetVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ AST__FRAMESET_GETATTRIB_BUFF_LEN + 1 ]; char GetAllVariants_Buff[ AST__FRAMESET_GETALLVARIANTS_BUFF_LEN + 1 ]; AstFrame *Integrity_Frame; const char *Integrity_Method; int Integrity_Lost; } AstFrameSetGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(FrameSet) /* Check class membership */ astPROTO_ISA(FrameSet) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected */ AstFrameSet *astFrameSet_( void *, const char *, int *, ...); #else AstFrameSet *astFrameSetId_( void *, const char *, ... )__attribute__((format(printf,2,3))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstFrameSet *astInitFrameSet_( void *, size_t, int, AstFrameSetVtab *, const char *, AstFrame *, int * ); /* Vtab initialiser. */ void astInitFrameSetVtab_( AstFrameSetVtab *, const char *, int * ); /* Loader. */ AstFrameSet *astLoadFrameSet_( void *, size_t, AstFrameSetVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitFrameSetGlobals_( AstFrameSetGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ AstFrame *astGetFrame_( AstFrameSet *, int, int * ); AstMapping *astGetMapping_( AstFrameSet *, int, int, int * ); void astAddFrame_( AstFrameSet *, int , AstMapping *, AstFrame *, int * ); void astAddVariant_( AstFrameSet *, AstMapping *, const char *, int * ); void astMirrorVariants_( AstFrameSet *, int, int * ); void astRemapFrame_( AstFrameSet *, int, AstMapping *, int * ); void astRemoveFrame_( AstFrameSet *, int, int * ); #if defined(astCLASS) /* Protected */ const char *astGetAllVariants_( AstFrameSet *, int * ); int astGetBase_( AstFrameSet *, int * ); int astGetCurrent_( AstFrameSet *, int * ); int astGetNframe_( AstFrameSet *, int * ); int astTestBase_( AstFrameSet *, int * ); int astTestCurrent_( AstFrameSet *, int * ); int astValidateFrameIndex_( AstFrameSet *, int, const char *, int * ); void astClearBase_( AstFrameSet *, int * ); void astClearCurrent_( AstFrameSet *, int * ); void astSetBase_( AstFrameSet *, int, int * ); void astSetCurrent_( AstFrameSet *, int, int * ); void astClearVariant_( AstFrameSet *, int * ); const char *astGetVariant_( AstFrameSet *, int * ); void astSetVariant_( AstFrameSet *, const char *, int * ); int astTestVariant_( AstFrameSet *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckFrameSet(this) astINVOKE_CHECK(FrameSet,this,0) #define astVerifyFrameSet(this) astINVOKE_CHECK(FrameSet,this,1) /* Test class membership. */ #define astIsAFrameSet(this) astINVOKE_ISA(FrameSet,this) /* Constructor. */ #if defined(astCLASS) /* Protected */ #define astFrameSet astINVOKE(F,astFrameSet_) #else #define astFrameSet astINVOKE(F,astFrameSetId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitFrameSet(mem,size,init,vtab,name,frame) \ astINVOKE(O,astInitFrameSet_(mem,size,init,vtab,name,astCheckFrame(frame),STATUS_PTR)) /* Vtab Initialiser. */ #define astInitFrameSetVtab(vtab,name) astINVOKE(V,astInitFrameSetVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadFrameSet(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadFrameSet_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckFrameSet to validate FrameSet pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #define astAddFrame(this,iframe,map,frame) \ astINVOKE(V,astAddFrame_(astCheckFrameSet(this),iframe,(((iframe)!=AST__ALLFRAMES)?astCheckMapping(map):NULL),astCheckFrame(frame),STATUS_PTR)) #define astAddVariant(this,map,name) \ astINVOKE(V,astAddVariant_(astCheckFrameSet(this),map?astCheckMapping(map):NULL,name,STATUS_PTR)) #define astMirrorVariants(this,iframe) \ astINVOKE(V,astMirrorVariants_(astCheckFrameSet(this),iframe,STATUS_PTR)) #define astGetFrame(this,iframe) \ astINVOKE(O,astGetFrame_(astCheckFrameSet(this),iframe,STATUS_PTR)) #define astGetMapping(this,iframe1,iframe2) \ astINVOKE(O,astGetMapping_(astCheckFrameSet(this),iframe1,iframe2,STATUS_PTR)) #define astRemapFrame(this,iframe,map) \ astINVOKE(V,astRemapFrame_(astCheckFrameSet(this),iframe,astCheckMapping(map),STATUS_PTR)) #define astRemoveFrame(this,iframe) \ astINVOKE(V,astRemoveFrame_(astCheckFrameSet(this),iframe,STATUS_PTR)) /* Interfaces to protected member functions. */ /* ----------------------------------------- */ #if defined(astCLASS) /* Protected */ #define astClearBase(this) \ astINVOKE(V,astClearBase_(astCheckFrameSet(this),STATUS_PTR)) #define astClearCurrent(this) \ astINVOKE(V,astClearCurrent_(astCheckFrameSet(this),STATUS_PTR)) #define astGetBase(this) \ astINVOKE(V,astGetBase_(astCheckFrameSet(this),STATUS_PTR)) #define astGetCurrent(this) \ astINVOKE(V,astGetCurrent_(astCheckFrameSet(this),STATUS_PTR)) #define astGetNframe(this) \ astINVOKE(V,astGetNframe_(astCheckFrameSet(this),STATUS_PTR)) #define astSetBase(this,ibase) \ astINVOKE(V,astSetBase_(astCheckFrameSet(this),ibase,STATUS_PTR)) #define astSetCurrent(this,icurrent) \ astINVOKE(V,astSetCurrent_(astCheckFrameSet(this),icurrent,STATUS_PTR)) #define astTestBase(this) \ astINVOKE(V,astTestBase_(astCheckFrameSet(this),STATUS_PTR)) #define astTestCurrent(this) \ astINVOKE(V,astTestCurrent_(astCheckFrameSet(this),STATUS_PTR)) #define astValidateFrameIndex(this,iframe,method) \ astINVOKE(V,astValidateFrameIndex_(astCheckFrameSet(this),iframe,method,STATUS_PTR)) #define astClearVariant(this) \ astINVOKE(V,astClearVariant_(astCheckFrameSet(this),STATUS_PTR)) #define astGetVariant(this) \ astINVOKE(V,astGetVariant_(astCheckFrameSet(this),STATUS_PTR)) #define astSetVariant(this,variant) \ astINVOKE(V,astSetVariant_(astCheckFrameSet(this),variant,STATUS_PTR)) #define astTestVariant(this) \ astINVOKE(V,astTestVariant_(astCheckFrameSet(this),STATUS_PTR)) #define astGetAllVariants(this) \ astINVOKE(V,astGetAllVariants_(astCheckFrameSet(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/circle.h0000644000175000017500000001714012262533650012557 0ustar olesoles#if !defined( CIRCLE_INCLUDED ) /* Include this file only once */ #define CIRCLE_INCLUDED /* *+ * Name: * circle.h * Type: * C include file. * Purpose: * Define the interface to the Circle class. * Invocation: * #include "circle.h" * Description: * This include file defines the interface to the Circle class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The Circle class implement a Region which represents a simple interval * on each axis of the encapsulated Frame * Inheritance: * The Circle class inherits from the Region class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 31-AUG-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "region.h" /* Coordinate regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* Circle structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstCircle { /* Attributes inherited from the parent class. */ AstRegion region; /* Parent class structure */ /* Attributes specific to objects in this class. */ double *centre; /* Circle centre coords */ double radius; /* Circle radius */ double *lb; /* Lower limits of mesh bounding box */ double *ub; /* Upper limit of mesh bounding box */ int stale; /* Is Cached information stale? */ } AstCircle; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstCircleVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstRegionVtab region_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* CirclePars)( AstCircle *, double *, double *, double *, int * ); } AstCircleVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstCircleGlobals { AstCircleVtab Class_Vtab; int Class_Init; } AstCircleGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitCircleGlobals_( AstCircleGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Circle) /* Check class membership */ astPROTO_ISA(Circle) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstCircle *astCircle_( void *, int, const double[], const double[], AstRegion *, const char *, int *, ...); #else AstCircle *astCircleId_( void *, int, const double[], const double[], AstRegion *, const char *, ... )__attribute__((format(printf,6,7))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstCircle *astInitCircle_( void *, size_t, int, AstCircleVtab *, const char *, AstFrame *, int, const double[], const double[], AstRegion *, int * ); /* Vtab initialiser. */ void astInitCircleVtab_( AstCircleVtab *, const char *, int * ); /* Loader. */ AstCircle *astLoadCircle_( void *, size_t, AstCircleVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astCirclePars_( AstCircle *, double *, double *, double *, int * ); # if defined(astCLASS) /* Protected */ AstRegion *astBestCircle_( AstPointSet *, double *, AstRegion *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckCircle(this) astINVOKE_CHECK(Circle,this,0) #define astVerifyCircle(this) astINVOKE_CHECK(Circle,this,1) /* Test class membership. */ #define astIsACircle(this) astINVOKE_ISA(Circle,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astCircle astINVOKE(F,astCircle_) #else #define astCircle astINVOKE(F,astCircleId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitCircle(mem,size,init,vtab,name,frame,form,p1,p2,unc) \ astINVOKE(O,astInitCircle_(mem,size,init,vtab,name,frame,form,p1,p2,unc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitCircleVtab(vtab,name) astINVOKE(V,astInitCircleVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadCircle(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadCircle_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckCircle to validate Circle pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astCirclePars(this,centre,radius,p1) \ astINVOKE(V,astCirclePars_(astCheckCircle(this),centre,radius,p1,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astBestCircle(pset,cen,unc) astBestCircle_(pset,cen,unc,STATUS_PTR) #endif #endif ./ast-7.3.3/polygon.c0000644000175000017500000057210612262533650013010 0ustar olesoles/* *class++ * Name: * Polygon * Purpose: * A polygonal region within a 2-dimensional Frame. * Constructor Function: c astPolygon f AST_POLYGON * Description: * The Polygon class implements a polygonal area, defined by a * collection of vertices, within a 2-dimensional Frame. The vertices * are connected together by geodesic curves within the encapsulated Frame. * For instance, if the encapsulated Frame is a simple Frame then the * geodesics will be straight lines, but if the Frame is a SkyFrame then * the geodesics will be great circles. Note, the vertices must be * supplied in an order such that the inside of the polygon is to the * left of the boundary as the vertices are traversed. Supplying them * in the reverse order will effectively negate the polygon. * * Within a SkyFrame, neighbouring vertices are always joined using the * shortest path. Thus if an edge of 180 degrees or more in length is * required, it should be split into section each of which is less * than 180 degrees. The closed path joining all the vertices in order * will divide the celestial sphere into two disjoint regions. The * inside of the polygon is the region which is circled in an * anti-clockwise manner (when viewed from the inside of the celestial * sphere) when moving through the list of vertices in the order in * which they were supplied when the Polygon was created (i.e. the * inside is to the left of the boundary when moving through the * vertices in the order supplied). * Inheritance: * The Polygon class inherits from the Region class. * Attributes: * The Polygon class does not define any new attributes beyond * those which are applicable to all Regions. * Functions: c In addition to those functions applicable to all Regions, the c following functions may also be applied to all Polygons: f In addition to those routines applicable to all Regions, the f following routines may also be applied to all Polygons: * c - astDownsize: Reduce the number of vertices in a Polygon. f - AST_DOWNSIZE: Reduce the number of vertices in a Polygon. c - astOutline: Create a Polygon outlining values in a pixel array f - AST_OUTLINE: Create a Polygon outlining values in a pixel array * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 26-OCT-2004 (DSB): * Original version. * 28-MAY-2009 (DSB): * Added astDownsize. * 29-MAY-2009 (DSB): * Added astOutline. * 30-JUN-2009 (DSB): * Override astGetBounded. * 4-NOV-2013 (DSB): * Modify RegPins so that it can handle uncertainty regions that straddle * a discontinuity. Previously, such uncertainty Regions could have a huge * bounding box resulting in matching region being far too big. * 6-DEC-2013 (DSB): * Reverse the order of the vertices when the Polygon is created, * if necessary, to ensure that the unnegated Polygon is bounded. * The parent Region class assumes that unnegated regions are * bounded. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Polygon /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E9*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Macros specifying whether a point is inside, outside or on the boundary of the polygon. */ #define UNKNOWN 0 #define IN 1 #define OUT 2 #define ON 3 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "region.h" /* Coordinate regions (parent class) */ #include "channel.h" /* I/O channels */ #include "box.h" /* Box Regions */ #include "wcsmap.h" /* Definitons of AST__DPI etc */ #include "polygon.h" /* Interface definition for this class */ #include "mapping.h" /* Position mappings */ #include "unitmap.h" /* Unit Mapping */ #include "pal.h" /* SLALIB library interface */ #include "frame.h" /* Coordinate system description */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Type definitions. */ /* ================= */ /* A structure that holds information about an edge of the new Polygon being created by astDownsize. The edge is a line betweeen two of the vertices of the original Polygon. */ typedef struct Segment { int i1; /* Index of starting vertex within old Polygon */ int i2; /* Index of ending vertex within old Polygon */ double error; /* Max geodesic distance from any old vertex to the line */ int imax; /* Index of the old vertex at which max error is reached */ struct Segment *next;/* Pointer to next Segment in a double link list */ struct Segment *prev;/* Pointer to previous Segment in a double link list */ } Segment; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstMapping *(* parent_simplify)( AstMapping *, int * ); static void (* parent_setregfs)( AstRegion *, AstFrame *, int * ); static void (* parent_resetcache)( AstRegion *, int * ); #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Polygon) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(Polygon,Class_Init) #define class_vtab astGLOBAL(Polygon,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstPolygonVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstPolygon *astPolygonId_( void *, int, int, const double *, void *, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ /* Define a macro that expands to a single prototype for function FindInsidePoint for a given data type and operation. */ #define FINDINSIDEPOINT_PROTO0(X,Xtype,Oper) \ static void FindInsidePoint##Oper##X( Xtype, const Xtype *, const int[2], const int[2], int *, int *, int *, int * ); /* Define a macro that expands to a set of prototypes for all operations for function FindInsidePoint for a given data type. */ #define FINDINSIDEPOINT_PROTO(X,Xtype) \ FINDINSIDEPOINT_PROTO0(X,Xtype,LT) \ FINDINSIDEPOINT_PROTO0(X,Xtype,LE) \ FINDINSIDEPOINT_PROTO0(X,Xtype,EQ) \ FINDINSIDEPOINT_PROTO0(X,Xtype,GE) \ FINDINSIDEPOINT_PROTO0(X,Xtype,GT) \ FINDINSIDEPOINT_PROTO0(X,Xtype,NE) /* Use the above macros to define all FindInsidePoint prototypes for all data types and operations. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ FINDINSIDEPOINT_PROTO(LD,long double) #endif FINDINSIDEPOINT_PROTO(D,double) FINDINSIDEPOINT_PROTO(L,long int) FINDINSIDEPOINT_PROTO(UL,unsigned long int) FINDINSIDEPOINT_PROTO(I,int) FINDINSIDEPOINT_PROTO(UI,unsigned int) FINDINSIDEPOINT_PROTO(S,short int) FINDINSIDEPOINT_PROTO(US,unsigned short int) FINDINSIDEPOINT_PROTO(B,signed char) FINDINSIDEPOINT_PROTO(UB,unsigned char) FINDINSIDEPOINT_PROTO(F,float) /* Define a macro that expands to a single prototype for function TraceEdge for a given data type and operation. */ #define TRACEEDGE_PROTO0(X,Xtype,Oper) \ static AstPointSet *TraceEdge##Oper##X( Xtype, const Xtype *, const int[2], const int[2], int, int, int, int, int, int * ); /* Define a macro that expands to a set of prototypes for all operations for function TraceEdge for a given data type. */ #define TRACEEDGE_PROTO(X,Xtype) \ TRACEEDGE_PROTO0(X,Xtype,LT) \ TRACEEDGE_PROTO0(X,Xtype,LE) \ TRACEEDGE_PROTO0(X,Xtype,EQ) \ TRACEEDGE_PROTO0(X,Xtype,GE) \ TRACEEDGE_PROTO0(X,Xtype,GT) \ TRACEEDGE_PROTO0(X,Xtype,NE) /* Use the above macros to define all TraceEdge prototypes for all data types and operations. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ TRACEEDGE_PROTO(LD,long double) #endif TRACEEDGE_PROTO(D,double) TRACEEDGE_PROTO(L,long int) TRACEEDGE_PROTO(UL,unsigned long int) TRACEEDGE_PROTO(I,int) TRACEEDGE_PROTO(UI,unsigned int) TRACEEDGE_PROTO(S,short int) TRACEEDGE_PROTO(US,unsigned short int) TRACEEDGE_PROTO(B,signed char) TRACEEDGE_PROTO(UB,unsigned char) TRACEEDGE_PROTO(F,float) /* Non-generic function prototypes. */ static AstMapping *Simplify( AstMapping *, int * ); static AstPointSet *DownsizePoly( AstPointSet *, double, int, AstFrame *, int * ); static AstPointSet *RegBaseMesh( AstRegion *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstPolygon *Downsize( AstPolygon *, double, int, int * ); static Segment *AddToChain( Segment *, Segment *, int * ); static Segment *NewSegment( Segment *, int, int, int, int * ); static Segment *RemoveFromChain( Segment *, Segment *, int * ); static double Polywidth( AstFrame *, AstLineDef **, int, int, double[ 2 ], int * ); static int GetBounded( AstRegion *, int * ); static int IntCmp( const void *, const void * ); static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); static int RegTrace( AstRegion *, int, double *, double **, int * ); static void Cache( AstPolygon *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void EnsureInside( AstPolygon *, int * ); static void FindMax( Segment *, AstFrame *, double *, double *, int, int, int * ); static void RegBaseBox( AstRegion *this, double *, double *, int * ); static void ResetCache( AstRegion *this, int * ); static void SetPointSet( AstPolygon *, AstPointSet *, int * ); static void SetRegFS( AstRegion *, AstFrame *, int * ); static void SmoothPoly( AstPointSet *, int, double, int * ); /* Member functions. */ /* ================= */ static Segment *AddToChain( Segment *head, Segment *seg, int *status ){ /* * Name: * AddToChain * Purpose: * Add a Segment into the linked list of Segments, maintaining the * required order in the list. * Type: * Private function. * Synopsis: * #include "polygon.h" * Segment *AddToChain( Segment *head, Segment *seg, int *status ) * Class Membership: * Polygon member function * Description: * The linked list of Segments maintained by astDownsize is searched * from the high error end (the head), until a Segment is foound which * has a lower error than the supplied segment. The supplied Segment * is then inserted into the list at that point. * Parameters: * head * The Segment structure at the head of the list (i.e. the segment * with maximum error). * seg * The Segment to be added into the list. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the link head (which will have changed if "seg" has a * higher error than the original head). */ /* Local Variables: */ Segment *tseg; /* Check the global error status. */ if ( !astOK ) return head; /* If the list is empty, return the supplied segment as the new list head. */ if( !head ) { head = seg; /* If the supplied segment has a higher error than the original head, insert the new segment in front of the original head. */ } else if( seg->error > head->error ){ seg->next = head; head->prev = seg; head = seg; /* Otherwise, move down the list from the head until a segment is found which has a lower error than the supplied Segment. Then insert the supplied segment into the list in front of it. */ } else { tseg = head; seg->next = NULL; while( tseg->next ) { if( seg->error > tseg->next->error ) { seg->next = tseg->next; seg->prev = tseg; tseg->next->prev = seg; tseg->next = seg; break; } tseg = tseg->next; } if( !seg->next ) { tseg->next = seg; seg->prev = tseg; } } /* Return the new head. */ return head; } static void Cache( AstPolygon *this, int *status ){ /* * Name: * Cache * Purpose: * Calculate intermediate values and cache them in the Polygon structure. * Type: * Private function. * Synopsis: * #include "polygon.h" * void Cache( AstPolygon *this, int *status ) * Class Membership: * Polygon member function * Description: * This function uses the PointSet stored in the parent Region to calculate * some intermediate values which are useful in other methods. These * values are stored within the Polygon structure. * Parameters: * this * Pointer to the Polygon. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *frm; /* Pointer to base Frame in Polygon */ double **ptr; /* Pointer to data in the encapsulated PointSet */ double end[ 2 ]; /* Start position for edge */ double maxwid; /* Maximum polygon width found so far */ double polcen[ 2 ]; /* Polygon centre perpendicular to current edge */ double polwid; /* Polygon width perpendicular to current edge */ double start[ 2 ]; /* Start position for edge */ int i; /* Axis index */ int nv; /* Number of vertices in Polygon */ /* Check the global error status. */ if ( !astOK ) return; /* Do nothing if the cached information is up to date. */ if( this->stale ) { /* Get a pointer to the base Frame. */ frm = astGetFrame( ((AstRegion *) this)->frameset, AST__BASE ); /* Get the number of vertices. */ nv = astGetNpoint( ((AstRegion *) this)->points ); /* Get pointers to the coordinate data in the parent Region structure. */ ptr = astGetPoints( ((AstRegion *) this)->points ); /* Free any existing edge information in the Polygon structure. */ if( this->edges ) { for( i = 0; i < nv; i++ ) { this->edges[ i ] = astFree( this->edges[ i ] ); } /* Allocate memory to store new edge information if necessary. */ } else { this->edges = astMalloc( sizeof( AstLineDef *)*(size_t) nv ); this->startsat = astMalloc( sizeof( double )*(size_t) nv ); } /* Check pointers can be used safely. */ if( this->edges ) { /* Create and store a description of each edge. Also form the total distance round the polygon, and the distance from the first vertex at which each edge starts. */ this->totlen = 0.0; start[ 0 ] = ptr[ 0 ][ nv - 1 ]; start[ 1 ] = ptr[ 1 ][ nv - 1 ]; for( i = 0; i < nv; i++ ) { end[ 0 ] = ptr[ 0 ][ i ]; end[ 1 ] = ptr[ 1 ][ i ]; this->edges[ i ] = astLineDef( frm, start, end ); start[ 0 ] = end[ 0 ]; start[ 1 ] = end[ 1 ]; this->startsat[ i ] = this->totlen; this->totlen += this->edges[ i ]->length; } /* We now look for a point that is inside the polygon. We want a point that is well within the polygon, since points that are only just inside the polygon can give numerical problems. Loop round each edge with non-zero length. */ maxwid = -1.0; for( i = 0; i < nv; i++ ) { if( this->edges[ i ]->length > 0.0 ) { /* We define another line perpendicular to the current edge, passing through the mid point of the edge, extending towards the inside of the polygon. The following function returns the distance we can travel along this line before we hit any of the other polygon edges. It also puts the position corresponding to half that distance into "polcen". */ polwid = Polywidth( frm, this->edges, i, nv, polcen, status ); /* If the width of the polygon perpendicular to the current edge is greater than the width perpdeicular to any other edge, record the width and also store the current polygon centre. */ if( polwid > maxwid && polwid != AST__BAD ) { maxwid = polwid; (this->in)[ 0 ] = polcen[ 0 ]; (this->in)[ 1 ] = polcen[ 1 ]; } } } /* If no width was found it probably means that the polygon vertices were given in clockwise order, resulting in the above process probing the infinite extent outside the polygonal hole. In this case any point outside the hole will do, so we use the current contents of the "polcen" array. Set a flag indicating if the vertices are stored in anti-clockwise order. */ if( maxwid < 0.0 ) { (this->in)[ 0 ] = polcen[ 0 ]; (this->in)[ 1 ] = polcen[ 1 ]; this->acw = 0; } else { this->acw = 1; } } /* Free resources */ frm = astAnnul( frm ); /* Indicate cached information is up to date. */ this->stale = 0; } } static AstPolygon *Downsize( AstPolygon *this, double maxerr, int maxvert, int *status ) { /* *++ * Name: c astDownsize f AST_DOWNSIZE * Purpose: * Reduce the number of vertices in a Polygon. * Type: * Public virtual function. * Synopsis: c #include "polygon.h" c AstPolygon *astDownsize( AstPolygon *this, double maxerr, int maxvert ) f RESULT = AST_DOWNSIZE( THIS, MAXERR, MAXVERT, STATUS ) * Class Membership: * Polygon method. * Description: * This function returns a pointer to a new Polygon that contains a * subset of the vertices in the supplied Polygon. The subset is * chosen so that the returned Polygon is a good approximation to * the supplied Polygon, within the limits specified by the supplied * parameter values. That is, the density of points in the returned * Polygon is greater at points where the curvature of the boundary of * the supplied Polygon is greater. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Polygon. c maxerr f MAXERR = DOUBLE PRECISION (Given) * The maximum allowed discrepancy between the supplied and * returned Polygons, expressed as a geodesic distance within the * Polygon's coordinate frame. If this is zero or less, the * returned Polygon will have the number of vertices specified by c maxvert. f MAXVERT. c maxvert f MAXVERT = INTEGER (Given) * The maximum allowed number of vertices in the returned Polygon. * If this is less than 3, the number of vertices in the returned * Polygon will be the minimum needed to achieve the maximum * discrepancy specified by c maxerr. f MAXERR. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astDownsize() f AST_DOWNSIZE = INTEGER * Pointer to the new Polygon. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstFrame *frm; /* Base Frame from the Polygon */ AstPointSet *pset; /* PointSet holding vertices of downsized polygon */ AstPolygon *result; /* Returned pointer to new Polygon */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the base Frame of the Polygon. */ frm = astGetFrame( ((AstRegion *) this)->frameset, AST__BASE ); /* Create a PointSet holding the vertices of the downsized polygon. */ pset = DownsizePoly( ((AstRegion *) this)->points, maxerr, maxvert, frm, status ); /* Take a deep copy of the supplied Polygon. */ result = astCopy( this ); /* Change the PointSet within the result Polygon to the one created above. */ \ SetPointSet( result, pset, status ); \ /* Free resources. */ frm = astAnnul( frm ); pset = astAnnul( pset ); /* If an error occurred, annul the returned Polygon. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *DownsizePoly( AstPointSet *pset, double maxerr, int maxvert, AstFrame *frm, int *status ) { /* * Name: * DownsizePoly * Purpose: * Reduce the number of vertices in a Polygon. * Type: * Private function. * Synopsis: * #include "polygon.h" * AstPointSet *DownsizePoly( AstPointSet *pset, double maxerr, int maxvert, * AstFrame *frm, int *status ) * Class Membership: * Polygon member function. * Description: * This function returns a pointer to a new PointSet that contains a * subset of the vertices in the supplied PointSet. The subset is * chosen so that the returned polygon is a good approximation to * the supplied polygon, within the limits specified by the supplied * parameter values. That is, the density of points in the returned * polygon is greater at points where the curvature of the boundary of * the supplied polygon is greater. * Parameters: * pset * Pointer to the PointSet holding the polygon vertices. * maxerr * The maximum allowed discrepancy between the supplied and * returned Polygons, expressed as a geodesic distance within the * Polygon's coordinate frame. If this is zero or less, the * returned Polygon will have the number of vertices specified by * maxvert. * maxvert * The maximum allowed number of vertices in the returned Polygon. * If this is less than 3, the number of vertices in the returned * Polygon will be the minimum needed to achieve the maximum * discrepancy specified by * maxerr. * frm * Pointer to the Frame in which the polygon is defined. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the new PointSet. * Notes: * - A null Object pointer (AST__NULL) will be returned if this * function is invoked with the AST error status set, or if it * should fail for any reason. */ /* Local Variables: */ AstPointSet *result; /* Returned pointer to new PointSet */ Segment *head; /* Pointer to new polygon edge with highest error */ Segment *seg1; /* Pointer to new polygon edge */ Segment *seg2; /* Pointer to new polygon edge */ Segment *seg3; /* Pointer to new polygon edge */ double **ptr; /* Pointer to arrays of axis values */ double *x; /* Pointer to array of X values for old Polygon */ double *xnew; /* Pointer to array of X values for new Polygon */ double *y; /* Pointer to array of Y values for old Polygon */ double *ynew; /* Pointer to array of Y values for new Polygon */ double x1; /* Lowest X value at any vertex */ double x2; /* Highest X value at any vertex */ double y1; /* Lowest Y value at any vertex */ double y2; /* Highest Y value at any vertex */ int *newpoly; /* Holds indices of retained input vertices */ int i1; /* Index of first vertex added to output polygon */ int i1x; /* Index of vertex with lowest X */ int i1y; /* Index of vertex with lowest Y */ int i2; /* Index of second vertex added to output polygon */ int i2x; /* Index of vertex with highest X */ int i2y; /* Index of vertex with highest Y */ int i3; /* Index of third vertex added to output polygon */ int iadd; /* Normalised vertex index */ int iat; /* Index at which to store new vertex index */ int newlen; /* Number of vertices currently in new Polygon */ int nv; /* Number of vertices in old Polygon */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get the number of vertices in the supplied polygon. */ nv = astGetNpoint( pset ); /* If the maximum error allowed is zero, and the maximum number of vertices is equal to or greater than the number in the supplied polygon, just return a deep copy of the supplied PointSet. */ if( maxerr <= 0.0 && ( maxvert < 3 || maxvert >= nv ) ) { result = astCopy( pset ); /* Otherwise... */ } else { /* Get pointers to the X and Y arrays holding the vertex coordinates in the supplied polygon. */ ptr = astGetPoints( pset ); x = ptr[ 0 ]; y = ptr[ 1 ]; /* Allocate memory for an array to hold the original indices of the vertices to be used to create the returned Polygon. This array is expanded as needed. */ newpoly = astMalloc( 10*sizeof( int ) ); /* Check the pointers can be used safely. */ if( astOK ) { /* We first need to decide on three widely spaced vertices which form a reasonable triangular approximation to the whole polygon. First find the vertices with the highest and lowest Y values, and the highest and lowest X values. */ x1 = DBL_MAX; x2 = -DBL_MAX; y1 = DBL_MAX; y2 = -DBL_MAX; i1y = i1x = 0; i2y = i2x = nv/2; for( i3 = 0; i3 < nv; i3++ ) { if( y[ i3 ] < y1 ) { y1 = y[ i3 ]; i1y = i3; } else if( y[ i3 ] > y2 ) { y2 = y[ i3 ]; i2y = i3; } if( x[ i3 ] < x1 ) { x1 = x[ i3 ]; i1x = i3; } else if( x[ i3 ] > x2 ) { x2 = x[ i3 ]; i2x = i3; } } /* Use the axis which spans the greater range. */ if( y2 - y1 > x2 - x1 ) { i1 = i1y; i2 = i2y; } else { i1 = i1x; i2 = i2x; } /* The index with vertex i1 is definitely going to be one of our three vertices. We are going to use the line from i1 to i2 to choose the two other vertices to use. Create a structure describing the segment of the Polygon from the lowest value on the selected axis (X or Y) to the highest value. As always, the polygons is traversed in an anti-clockwise direction. */ seg1 = NewSegment( NULL, i1, i2, nv, status ); /* Find the vertex within this segment which is furthest away from the line on the right hand side (as moving from vertex i1 to vertex i2). */ FindMax( seg1, frm, x, y, nv, 0, status ); /* Likewise, create a structure describing the remained of the Polygon (i.e. the segment from the highest value on the selected axis to the lowest value). Then find the vertex within this segment which is furthest away from the line on the right hand side. */ seg2 = NewSegment( NULL, i2, i1, nv, status ); FindMax( seg2, frm, x, y, nv, 0, status ); /* Select the segment for which the found vertex is furthest from the line. */ if( seg2->error > seg1->error ) { /* If the second segment, we will use the vertex that is farthest from the line as one of our threee vertices. To ensure that movement from vertex i1 to i2 to i3 is anti-clockwise, we must use this new vertex as vertex i3, not i2. */ i3 = seg2->imax; /* Create a description of the polygon segment from vertex i1 to i3, and find the vertex which is furthest to the right of the line joining the two vertices. We use this as the middle vertex (i2). */ seg1 = NewSegment( seg1, i1, i3, nv, status ); FindMax( seg1, frm, x, y, nv, 0, status ); i2 = seg1->imax; /* Do the same if we are choosing the other segment, ordering the vertices to retain anti-clockwise movement from i1 to i2 to i3. */ } else { i2 = seg1->imax; seg1 = NewSegment( seg1, i2, i1, nv, status ); FindMax( seg1, frm, x, y, nv, 0, status ); i3 = seg1->imax; } /* Ensure the vertex indices are in the first cycle. */ if( i2 >= nv ) i2 -= nv; if( i3 >= nv ) i3 -= nv; /* Create Segment structures to describe each of these three edges. */ seg1 = NewSegment( seg1, i1, i2, nv, status ); seg2 = NewSegment( seg2, i2, i3, nv, status ); seg3 = NewSegment( NULL, i3, i1, nv, status ); /* Record these 3 vertices in an array holding the original indices of the vertices to be used to create the returned Polygon. */ newpoly[ 0 ] = i1; newpoly[ 1 ] = i2; newpoly[ 2 ] = i3; /* Indicate the new polygon currently has 3 vertices. */ newlen = 3; /* Search the old vertices between the start and end of segment 3, looking for the vertex which lies furthest from the line of segment 3. The residual between this point and the line is stored in the Segment structure, as is the index of the vertex at which this maximum residual occurred. */ FindMax( seg3, frm, x, y, nv, 1, status ); /* The "head" variable points to the head of a double linked list of Segment structures. This list is ordered by residual, so that the Segment with the maximum residual is at the head, and the Segment with the minimum residual is at the tail. Initially "seg3" is at the head. */ head = seg3; /* Search the old vertices between the start and end of segment 1, looking for the vertex which lies furthest from the line of segment 1. The residual between this point and the line is stored in the Segment structure, as is the index of the vertex at which this maximum residual occurred. */ FindMax( seg1, frm, x, y, nv, 1, status ); /* Insert segment 1 into the linked list of Segments, at a position that maintains the ordering of the segments by error. Thus the head of the list will still have the max error. */ head = AddToChain( head, seg1, status ); /* Do the same for segment 2. */ FindMax( seg2, frm, x, y, nv, 1, status ); head = AddToChain( head, seg2, status ); /* If the maximum allowed number of vertices in the output Polygon is less than 3, allow any number of vertices up to the number in the input Polygon (termination will then be determined just by "maxerr"). */ if( maxvert < 3 ) maxvert = nv; /* Loop round adding an extra vertex to the returned Polygon until the maximum residual between the new and old polygons is no more than "maxerr". Abort early if the specified maximum number of vertices is reached. */ while( head->error > maxerr && newlen < maxvert ) { /* The segment at the head of the list has the max error (that is, it is the segment that departs most from the supplied Polygon). To make the new polygon a better fit to the old polygon, we add the vertex that is furthest away from this segment to the new polygon. Remember that a polygon is cyclic so if the vertex has an index that is greater than the number of vertices in the old polygon, reduce the index by the number of vertices in the old polygon. */ iadd = head->imax; if( iadd >= nv ) iadd -= nv; iat = newlen++; newpoly = astGrow( newpoly, newlen, sizeof( int ) ); if( !astOK ) break; newpoly[ iat ] = iadd; /* We now split the segment that had the highest error into two segments. The split occurs at the vertex that had the highest error. */ seg1 = NewSegment( NULL, head->imax, head->i2, nv, status ); seg2 = head; seg2->i2 = head->imax; /* We do not know where these two new segments should be in the ordered linked list, so remove them from the list. */ head = RemoveFromChain( head, seg1, status ); head = RemoveFromChain( head, seg2, status ); /* Find the vertex that deviates most from the first of these two new segments, and then add the segment into the list of vertices, using the maximum deviation to determine the position of the segment within the list. */ FindMax( seg1, frm, x, y, nv, 1, status ); head = AddToChain( head, seg1, status ); /* Do the same for the second new segment. */ FindMax( seg2, frm, x, y, nv, 1, status ); head = AddToChain( head, seg2, status ); } /* Now we have reached the required accuracy, free resources. */ while( head ) { seg1 = head; head = head->next; seg1 = astFree( seg1 ); } /* If no vertices have been left out, return a deep copy of the supplied PointSet. */ if( newlen == nv ) { result = astCopy( pset ); /* Otherwise, sort the indices of the vertices to be retained so that they are in the same order as they were in the supplied Polygon. */ } else if( astOK ){ qsort( newpoly, newlen, sizeof( int ), IntCmp ); /* Create a new PointSet and get pointers to its axis values. */ result = astPointSet( newlen, 2, " ", status ); ptr = astGetPoints( result ); xnew = ptr[ 0 ]; ynew = ptr[ 1 ]; /* Copy the axis values for the retained vertices from the old to the new PointSet. */ if( astOK ) { for( iat = 0; iat < newlen; iat++ ) { *(xnew++) = x[ newpoly[ iat ] ]; *(ynew++) = y[ newpoly[ iat ] ]; } } } } /* Free resources. */ newpoly = astFree( newpoly ); } /* If an error occurred, annul the returned PointSet. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static void EnsureInside( AstPolygon *this, int *status ){ /* * Name: * EnsureInside * Purpose: * Ensure the unnegated Polygon represents the inside of the polygon. * Type: * Private function. * Synopsis: * #include "polygon.h" * void EnsureInside( AstPolygon *this, int *status ) * Class Membership: * Polygon member function * Description: * Reversing the order of the vertices of a Polygon is like negating * the Polygon. But the parent Region class assumes that an unnegated * region bounded by closed curves (e.g. boxes, circles, ellipses, etc) * is bounded. So we need to have a way to ensure that a Polygon also * follows this convention. So this function reverses the order of the * vertices in the Polygon, if necessary, to ensure that the unnegated * Polygon is bounded. * Parameters: * this * The Polygon. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRegion *this_region; double **ptr; double *p; double *q; double tmp; int bounded; int i; int j; int jmid; int negated; int np; /* Check the global error status. */ if ( !astOK ) return; /* Is the unnegated Polygon unbounded? If so, we need to reverse the vertices. */ bounded = astGetBounded( this ); negated = astGetNegated( this ); if( ( bounded && negated ) || ( !bounded && !negated ) ) { this_region = (AstRegion *) this; /* Get a pointer to the arrays holding the coordinates at the Polygon vertices. */ ptr = astGetPoints( this_region->points ); /* Get the number of vertices. */ np = astGetNpoint( this_region->points ); /* Store the index of the last vertex to swap. For odd "np" the central vertex does not need to be swapped. */ jmid = np/2; /* Loop round the two axes spanned by the Polygon. */ for( i = 0; i < 2; i++ ) { /* Get pointers to the first pair of axis values to be swapped - i.e. the first and last axis values. */ p = ptr[ i ]; q = p + np - 1; /* Loop round all pairs of axis values. */ for( j = 0; j < jmid; j++ ) { /* Swap the pair. */ tmp = *p; *(p++) = *q; *(q--) = tmp; } } /* Invert the value of the "Negated" attribute to cancel out the effect of the above vertex reversal. */ astNegate( this ); /* Indicate the cached information in the Polygon structure is stale. */ this->stale = 1; } } /* * Name: * FindInsidePoint * Purpose: * Find a point that is inside the required outline. * Type: * Private function. * Synopsis: * #include "polygon.h" * void FindInsidePoint( value, const array[], * const int lbnd[ 2 ], const int ubnd[ 2 ], * int *inx, int *iny, int *iv, * int *status ); * Class Membership: * Polygon member function * Description: * The central pixel in the array is checked to see if its value meets * the requirements implied by and "value". If so, its pixel * indices and vector index are returned> if not, a spiral search is * made until such a pixel value is found. * Parameters: * value * The data value defining valid pixels. * array * The data array. * lbnd * The lower pixel index bounds of the array. * ubnd * The upper pixel index bounds of the array. * inx * Pointer to an int in which to return the X pixel index of the * first point that meets the requirements implied by and * "value". * iny * Pointer to an int in which to return the Y pixel index of the * first point that meets the requirements implied by and * "value". * iv * Pointer to an int in which to return the vector index of the * first point that meets the requirements implied by and * "value". * status * Pointer to the inherited status variable. * Notes: * - must be one of LT, LE, EQ, NE, GE, GT. */ /* Define a macro to implement the function for a specific data type and operation. */ #define MAKE_FINDINSIDEPOINT(X,Xtype,Oper,OperI) \ static void FindInsidePoint##Oper##X( Xtype value, const Xtype array[], \ const int lbnd[ 2 ], const int ubnd[ 2 ], \ int *inx, int *iny, int *iv, \ int *status ){ \ \ /* Local Variables: */ \ const Xtype *pv; /* Pointer to next data value to test */ \ const char *text; /* Pointer to text describing oper */ \ int cy; /* Central row index */ \ int iskin; /* Index of spiral layer being searched */ \ int nskin; /* Number of spiral layers to search */ \ int nx; /* Pixel per row */ \ int tmp; /* Temporary storage */ \ int xhi; /* High X pixel index bound of current skin */ \ int xlo; /* Low X pixel index bound of current skin */ \ int yhi; /* High X pixel index bound of current skin */ \ int ylo; /* Low X pixel index bound of current skin */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Find number of pixels in one row of the array. */ \ nx = ( ubnd[ 0 ] - lbnd[ 0 ] + 1 ); \ \ /* Find the pixel indices of the central pixel */ \ *inx = ( ubnd[ 0 ] + lbnd[ 0 ] )/2; \ *iny = ( ubnd[ 1 ] + lbnd[ 1 ] )/2; \ \ /* Initialise the vector index and pointer to refer to the central pixel. */ \ *iv = ( *inx - lbnd[ 0 ] ) + nx*( *iny - lbnd[ 1 ] ) ; \ pv = array + (*iv); \ \ /* Test the pixel value, returning if it is valid. This \ relies on the compiler optimisation to remove the "if" statements \ for all but the operation appropriate to the function being defined. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* The central pixel is invalid if we arrive here. So we need to do a \ spiral search out from the centre looking for a valid pixel. Record \ the central row index (this is the row at which we jump to the next \ outer skin when doing the spiral search below). */ \ cy = *iny; \ \ /* Find how many skins can be searched as part of the spiral search \ before the edge of the array is encountered. */ \ nskin = ubnd[ 0 ] - *inx; \ tmp = *inx - lbnd[ 0 ]; \ if( tmp < nskin ) nskin = tmp; \ tmp = ubnd[ 1 ] - *iny; \ if( tmp < nskin ) nskin = tmp; \ tmp = *iny - lbnd[ 1 ]; \ if( tmp < nskin ) nskin = tmp; \ \ /* Initialise the skin box bounds to be just the central pixel. */ \ xlo = xhi = *inx; \ ylo = yhi = *iny; \ \ /* Loop round each skin looking for a valid test pixel. */ \ for( iskin = 0; iskin < nskin; iskin++ ) { \ \ /* Increment the upper and lower bounds of the box forming the next \ skin. */ \ xhi++; \ xlo--; \ yhi++; \ ylo--; \ \ /* Initialise things for the first pixel in the new skin by moving one \ pixel to the right. */ \ pv++; \ (*iv)++; \ (*inx)++; \ \ /* Move up the right hand edge of the box corresponding to the current \ skin. We start at the middle of the right hand edge. */ \ for( *iny = cy; *iny <= yhi; (*iny)++ ) { \ \ /* Test the pixel value, returning if it is valid. This relies on the \ compiler optimisation to remove the "if" statements for all but the \ operation appropriate to the function being defined. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* Move up a pixel. */ \ pv += nx; \ *iv += nx; \ } \ \ /* Move down a pixel so that *iny == yhi. */ \ pv -= nx; \ *iv -= nx; \ (*iny)--; \ \ /* Move left along the top edge of the box corresponding to the current \ skin. */ \ for( *inx = xhi; *inx >= xlo; (*inx)-- ) { \ \ /* Test the pixel value, returning if it is valid. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* Move left a pixel. */ \ pv--; \ (*iv)--; \ } \ \ /* Move right a pixel so that *inx == xlo. */ \ pv++; \ (*iv)++; \ (*inx)++; \ \ /* Move down along the left hand edge of the box corresponding to the current \ skin. */ \ for( *iny = yhi; *iny >= ylo; (*iny)-- ) { \ \ /* Test the pixel value, returning if it is valid. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* Move down a pixel. */ \ pv -= nx; \ *iv -= nx; \ } \ \ /* Move up a pixel so that *iny == ylo. */ \ pv += nx; \ *iv += nx; \ (*iny)++; \ \ /* Move right along the bottom edge of the box corresponding to the current \ skin. */ \ for( *inx = xlo; *inx <= xhi; (*inx)++ ) { \ \ /* Test the pixel value, returning if it is valid. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* Move right a pixel. */ \ pv++; \ (*iv)++; \ } \ \ /* Move left a pixel so that *inx == xhi. */ \ pv--; \ (*iv)--; \ (*inx)--; \ \ /* Move up the right hand edge of the box correspionding to the current \ skin. We stop just below the middle of the right hand edge. */ \ for( *iny = ylo; *iny < cy; (*iny)++ ) { \ \ /* Test the pixel value, returning if it is valid. This relies on the \ compiler optimisation to remove the "if" statements for all but the \ operation appropriate to the function being defined. */ \ if( OperI == AST__LT ) { \ if( *pv < value ) return; \ \ } else if( OperI == AST__LE ) { \ if( *pv <= value ) return; \ \ } else if( OperI == AST__EQ ) { \ if( *pv == value ) return; \ \ } else if( OperI == AST__NE ) { \ if( *pv != value ) return; \ \ } else if( OperI == AST__GE ) { \ if( *pv >= value ) return; \ \ } else { \ if( *pv > value ) return; \ } \ \ /* Move up a pixel. */ \ pv += nx; \ *iv += nx; \ } \ } \ \ /* Report an error if no inside pooint could be found. */ \ if( OperI == AST__LT ) { \ text = "less than"; \ } else if( OperI == AST__LE ) { \ text = "less than or equal to"; \ } else if( OperI == AST__EQ ) { \ text = "equal to"; \ } else if( OperI == AST__NE ) { \ text = "not equal to"; \ } else if( OperI == AST__GE ) { \ text = "greater than or equal to"; \ } else { \ text = "greater than"; \ } \ astError( AST__NONIN, "astOutline"#X": Could not find a pixel value %s " \ "%g in the supplied array.", status, text, (double) value ); \ } /* Define a macro that uses the above macro to to create implementations of FindInsidePoint for all operations. */ #define MAKEALL_FINDINSIDEPOINT(X,Xtype) \ MAKE_FINDINSIDEPOINT(X,Xtype,LT,AST__LT) \ MAKE_FINDINSIDEPOINT(X,Xtype,LE,AST__LE) \ MAKE_FINDINSIDEPOINT(X,Xtype,EQ,AST__EQ) \ MAKE_FINDINSIDEPOINT(X,Xtype,GE,AST__GE) \ MAKE_FINDINSIDEPOINT(X,Xtype,GT,AST__GT) \ MAKE_FINDINSIDEPOINT(X,Xtype,NE,AST__NE) /* Expand the above macro to generate a function for each required data type and operation. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ MAKEALL_FINDINSIDEPOINT(LD,long double) #endif MAKEALL_FINDINSIDEPOINT(D,double) MAKEALL_FINDINSIDEPOINT(L,long int) MAKEALL_FINDINSIDEPOINT(UL,unsigned long int) MAKEALL_FINDINSIDEPOINT(I,int) MAKEALL_FINDINSIDEPOINT(UI,unsigned int) MAKEALL_FINDINSIDEPOINT(S,short int) MAKEALL_FINDINSIDEPOINT(US,unsigned short int) MAKEALL_FINDINSIDEPOINT(B,signed char) MAKEALL_FINDINSIDEPOINT(UB,unsigned char) MAKEALL_FINDINSIDEPOINT(F,float) /* Undefine the macros. */ #undef MAKE_FINDINSIDEPOINT #undef MAKEALL_FINDINSIDEPOINT static void FindMax( Segment *seg, AstFrame *frm, double *x, double *y, int nv, int abs, int *status ){ /* * Name: * FindMax * Purpose: * Find the maximum discrepancy between a given line segment and the * Polygon being downsized. * Type: * Private function. * Synopsis: * #include "polygon.h" * void FindMax( Segment *seg, AstFrame *frm, double *x, double *y, * int nv, int abs, int *status ) * Class Membership: * Polygon member function * Description: * The supplied Segment structure describes a range of vertices in * the polygon being downsized. This function checks each of these * vertices to find the one that lies furthest from the line joining the * first and last vertices in the segment. The maximum error, and the * vertex index at which this maximum error is found, is stored in the * Segment structure. * Parameters: * seg * The structure describing the range of vertices to check. It * corresponds to a candidate edge in the downsized polygon. * frm * The Frame in which the positions are defined. * x * Pointer to the X axis values in the original Polygon. * y * Pointer to the Y axis values in the original Polygon. * nv * Total number of vertics in the old Polygon.. * abs * If non-zero, then the stored maximum is the position with * maximum absolute error. Otherwise, the stored maximum is the * position with maximum positive error (positive errors are to the * right when travelling from start to end of the segment). * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPointSet *pset1; /* PointSet holding vertex positions */ AstPointSet *pset2; /* PointSet holding offset par/perp components */ double **ptr1; /* Pointers to "pset1" data arrays */ double **ptr2; /* Pointers to "pset2" data arrays */ double *px; /* Pointer to next X value */ double *py; /* Pointer to next Y value */ double ax; /* X value at start */ double ay; /* Y value at start */ double ba; /* Distance between a and b */ double bax; /* X increment from a to b */ double bay; /* Y increment from a to b */ double cax; /* X increment from a to c */ double cay; /* Y increment from a to c */ double end[ 2 ]; /* Position of starting vertex */ double error; /* Error value for current vertex */ double start[ 2 ]; /* Position of starting vertex */ int i1; /* Starting index (always in first cycle) */ int i2; /* Ending index converted to first cycle */ int i2b; /* Upper vertex limit in first cycle */ int i; /* Loop count */ int n; /* Number of vertices to check */ /* Check the global error status. */ if ( !astOK ) return; /* Stuff needed for handling cyclic redundancy of vertex indices. */ i1 = seg->i1; i2 = seg->i2; n = i2 - i1 - 1; i2b = i2; if( i2 >= nv ) { i2 -= nv; i2b = nv; } /* If the segment has no intermediate vertices, set the segment error to zero and return. */ if( n < 1 ) { seg->error = 0.0; seg->imax = i1; /* For speed, we use simple plane geometry if the Polygon is defined in a simple Frame. */ } else if( !strcmp( astGetClass( frm ), "Frame" ) ) { /* Point "a" is the vertex that marks the start of the segment. Point "b" is the vertex that marks the end of the segment. */ ax = x[ i1 ]; ay = y[ i1 ]; bax = x[ i2 ] - ax; bay = y[ i2 ] - ay; ba = sqrt( bax*bax + bay*bay ); /* Initialise the largest error found so far. */ seg->error = -1.0; /* Check the vertices from the start (plus one) up to the end (minus one) or the last vertex (which ever comes first). */ for( i = i1 + 1; i < i2b; i++ ) { /* Position "c" is the vertex being tested. Find the squared distance from "c" to the line joining "a" and "b". */ cax = x[ i ] - ax; cay = y[ i ] - ay; error = ( bay*cax - cay*bax )/ba; if( abs ) error = fabs( error ); /* If this is the largest value found so far, record it. Note the error here is a squared distance. */ if( error > seg->error ) { seg->error = error; seg->imax = i; } } /* If the end vertex is in the next cycle, check the remaining vertex posI would have thought a telentitions in the same way. */ if( i2b != i2 ) { for( i = 0; i < i2; i++ ) { cax = x[ i ] - ax; cay = y[ i ] - ay; error = ( bay*cax - cay*bax )/ba; if( abs ) error = fabs( error ); if( error > seg->error ) { seg->error = error; seg->imax = i + i2b; } } } /* If the polygon is not defined in a simple Frame, we use the overloaded Frame methods to do the geometry. */ } else { /* Create a PointSet to hold the positions of the vertices to test. We do not need to test the start or end vertex. */ pset1 = astPointSet( n, 2, " ", status ); ptr1 = astGetPoints( pset1 ); if( astOK ) { /* Copy the vertex axis values form the start (plus one) up to the end (minus one) vertex or the last vertex (which ever comes first). */ px = ptr1[ 0 ]; py = ptr1[ 1 ]; for( i = i1 + 1; i < i2b; i++ ){ *(px++) = x[ i ]; *(py++) = y[ i ]; } /* If the end vertex is in the next cycle, copy the remaining vertex positions into the PointSet. */ if( i2b != i2 ) { for( i = 0; i < i2; i++ ) { *(px++) = x[ i ]; *(py++) = y[ i ]; } } /* Record the start and end vertex positions. */ start[ 0 ] = x[ i1 ]; start[ 1 ] = y[ i1 ]; end[ 0 ] = x[ i2 ]; end[ 1 ] = y[ i2 ]; /* Resolve the vector from the start to each vertex into two components, parallel and perpendicular to the start->end vector. */ pset2 = astResolvePoints( frm, start, end, pset1, NULL ); ptr2 = astGetPoints( pset2 ); if( astOK ) { /* Find the vertex with largest perpendicular component. */ seg->error = -1.0; py = ptr2[ 1 ]; for( i = 1; i <= n; i++ ) { error = *(py++); if( abs ) error = fabs( error ); if( error > seg->error ) { seg->error = error; seg->imax = i + i1; } } } /* Free resources. */ pset2 = astAnnul( pset2 ); } pset1 = astAnnul( pset1 ); } } static int GetBounded( AstRegion *this, int *status ) { /* * Name: * GetBounded * Purpose: * Is the Region bounded? * Type: * Private function. * Synopsis: * #include "polygon.h" * int GetBounded( AstRegion *this, int *status ) * Class Membership: * Polygon method (over-rides the astGetBounded method inherited from * the Region class). * Description: * This function returns a flag indicating if the Region is bounded. * The implementation provided by the base Region class is suitable * for Region sub-classes representing the inside of a single closed * curve (e.g. Circle, Interval, Box, etc). Other sub-classes (such as * CmpRegion, PointList, etc ) may need to provide their own * implementations. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Region is bounded. Zero otherwise. */ /* Local Variables: */ int neg; /* Has the Polygon been negated? */ int result; /* Returned result */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Ensure cached information is available. */ Cache( (AstPolygon *) this, status ); /* See if the Polygon has been negated. */ neg = astGetNegated( this ); /* If the polygon vertices are stored in anti-clockwise order, then the polygon is bounded if it has not been negated. */ if( ( (AstPolygon *) this)->acw ) { result = (! neg ); /* If the polygon vertices are stored in clockwise order, then the polygon is bounded if it has been negated. */ } else { result = neg; } /* Return the result. */ return result; } void astInitPolygonVtab_( AstPolygonVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitPolygonVtab * Purpose: * Initialise a virtual function table for a Polygon. * Type: * Protected function. * Synopsis: * #include "polygon.h" * void astInitPolygonVtab( AstPolygonVtab *vtab, const char *name ) * Class Membership: * Polygon vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Polygon class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstRegionVtab *region; /* Pointer to Region component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitRegionVtab( (AstRegionVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAPolygon) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstRegionVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->Downsize = Downsize; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ mapping = (AstMappingVtab *) vtab; region = (AstRegionVtab *) vtab; parent_transform = mapping->Transform; mapping->Transform = Transform; parent_simplify = mapping->Simplify; mapping->Simplify = Simplify; parent_setregfs = region->SetRegFS; region->SetRegFS = SetRegFS; parent_resetcache = region->ResetCache; region->ResetCache = ResetCache; region->RegPins = RegPins; region->RegBaseMesh = RegBaseMesh; region->RegBaseBox = RegBaseBox; region->RegTrace = RegTrace; region->GetBounded = GetBounded; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ /* Declare the copy constructor, destructor and class dump functions. */ astSetDump( vtab, Dump, "Polygon", "Polygonal region" ); astSetDelete( vtab, Delete ); astSetCopy( vtab, Copy ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int IntCmp( const void *a, const void *b ){ /* * Name: * IntCmp * Purpose: * An integer comparison function for the "qsort" function. * Type: * Private function. * Synopsis: * #include "polygon.h" * int IntCmp( const void *a, const void *b ) * Class Membership: * Polygon member function * Description: * See the docs for "qsort". * Parameters: * a * Pointer to the first int * b * Pointer to the second int * Returnd Value: * Positive, negative or zero, depending on whether a is larger than, * equal to, or less than b. */ return *((int*)a) - *((int*)b); } static Segment *NewSegment( Segment *seg, int i1, int i2, int nvert, int *status ){ /* * Name: * NewSegment * Purpose: * Initialise a structure describing a segment of the new Polygon * created by astDownsize. * Type: * Private function. * Synopsis: * #include "polygon.h" * Segment *NewSegment( Segment *seg, int i1, int i2, int nvert, * int *status ) * Class Membership: * Polygon member function * Description: * This function initialises the contents of a structure describing * the specified range of vertices within a Polygon. The cyclic nature * of vertex indices is taken into account. * * If no structure is supplied, memory is allocated to hold a new * structure. * Parameters: * seg * Pointer to a structure to initialise, or NULL if a new structure * is to be allocated. * i1 * The index of a vertex within the old Polygon (supplied to * astDownsize) that marks the start of the new line segment in * the downsized polygon. * i2 * The index of a vertex within the old Polygon (supplied to * astDownsize) that marks the end of the new line segment in * the downsized polygon. * nvert * Total number of vertics in the old Polygon.. * status * Pointer to the inherited status variable. * Returnd Value: * Pointer to the initialised Segment structure. It should be freed using * astFree when no longer needed. */ /* Local Variables: */ Segment *result; /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure to be initialised, allocating memory for a new structure if none was supplied. */ result = seg ? seg : astMalloc( sizeof( Segment ) ); /* Check the pointer can be used safely. */ if( result ) { /* If the supplied ending index is less than the starting index, the ending index must have gone all the way round the polygon and started round again. Increase the ending index by the number of vertices to put it in the same cycle as the starting index. */ if( i2 < i1 ) i2 += nvert; /* If the supplied starting index is within the first cycle (i.e. zero -> nvert-1 ), use the indices as they are (which may mean that the ending index is greater than nvert, but this is handled correctly by other functions). */ if( i1 < nvert ) { result->i1 = i1; result->i2 = i2; /* If the supplied starting index is within the second cycle (i.e. nvert or greater) the ending index will be even greater, so we can reduce both by "nvert" to put them both in the first cycle. The goal is that the starting index should always be in the first cycle, but the ending index may possibly be in the second cycle. */ } else { result->i1 = i1 - nvert; result->i2 = i2 - nvert; } /* Nullify the links to other Segments */ result->next = NULL; result->prev = NULL; } /* Return the pointer to the new Segment structure. */ return result; } /* *++ * Name: c astOutline f AST_OUTLINE * Purpose: * Create a new Polygon outling values in a 2D data grid. * Type: * Public function. * Synopsis: c #include "polygon.h" c AstPolygon *astOutline( value, int oper, const array[], c const int lbnd[2], const int ubnd[2], double maxerr, c int maxvert, const int inside[2], int starpix ) f RESULT = AST_OUTLINE( VALUE, OPER, ARRAY, LBND, UBND, MAXERR, f MAXVERT, INSIDE, STARPIX, STATUS ) * Class Membership: * Polygon method. * Description: * This is a set of functions that create a Polygon enclosing a single * contiguous set of pixels that have a specified value within a gridded * 2-dimensional data array (e.g. an image). * * A basic 2-dimensional Frame is used to represent the pixel coordinate * system in the returned Polygon. The Domain attribute is set to * "PIXEL", the Title attribute is set to "Pixel coordinates", and the * Unit attribute for each axis is set to "pixel". All other * attributes are left unset. The nature of the pixel coordinate system * is determined by parameter c "starpix". f STARPIX. * * The c "maxerr" and "maxvert" f MAXERR and MAXVERT * parameters can be used to control how accurately the returned * Polygon represents the required region in the data array. The * number of vertices in the returned Polygon will be the minimum * needed to achieve the required accuracy. * * You should use a function which matches the numerical type of the * data you are processing by replacing in the generic function * name c astOutline f AST_OUTLINE c by an appropriate 1- or 2-character type code. For example, if you * are procesing data with type c "float", you should use the function astOutlineF f REAL, you should use the function AST_OUTLINER * (see the "Data Type Codes" section below for the codes appropriate to * other numerical types). * Parameters: c value f VALUE = (Given) * A data value that specifies the pixels to be outlined. c oper f OPER = INTEGER (Given) * Indicates how the c "value" f VALUE * parameter is used to select the outlined pixels. It can * have any of the following values: c - AST__LT: outline pixels with value less than "value". c - AST__LE: outline pixels with value less than or equal to "value". c - AST__EQ: outline pixels with value equal to "value". c - AST__NE: outline pixels with value not equal to "value". c - AST__GE: outline pixels with value greater than or equal to "value". c - AST__GT: outline pixels with value greater than "value". f - AST__LT: outline pixels with value less than VALUE. f - AST__LE: outline pixels with value less than or equal to VALUE. f - AST__EQ: outline pixels with value equal to VALUE. f - AST__NE: outline pixels with value not equal to VALUE. f - AST__GE: outline pixels with value greater than or equal to VALUE. f - AST__GT: outline pixels with value greater than VALUE. c array f ARRAY( * ) = (Given) c Pointer to a f A * 2-dimensional array containing the data to be processed. The * numerical type of this array should match the 1- or * 2-character type code appended to the function name (e.g. if c you are using astOutlineF, the type of each array element c should be "float"). f you are using AST_OUTLINER, the type of each array element f should be REAL). * * The storage order of data within this array should be such * that the index of the first grid dimension varies most * rapidly and that of the second dimension least rapidly c (i.e. Fortran array indexing is used). f (i.e. normal Fortran array storage order). c lbnd f LBND( 2 ) = INTEGER (Given) c Pointer to an array of two integers f An array * containing the coordinates of the centre of the first pixel * in the input grid along each dimension. c ubnd f UBND( 2) = INTEGER (Given) c Pointer to an array of two integers f An array * containing the coordinates of the centre of the last pixel in * the input grid along each dimension. * c Note that "lbnd" and "ubnd" together define the shape f Note that LBND and UBND together define the shape * and size of the input grid, its extent along a particular c (j'th) dimension being ubnd[j]-lbnd[j]+1 (assuming the c index "j" to be zero-based). They also define f (J'th) dimension being UBND(J)-LBND(J)+1. They also define * the input grid's coordinate system, each pixel having unit * extent along each dimension with integral coordinate values * at its centre or upper corner, as selected by parameter c "starpix". f STARPIX. c maxerr f MAXERR = DOUBLE PRECISION (Given) * Together with c "maxvert", f MAXVERT, * this determines how accurately the returned Polygon represents * the required region of the data array. It gives the target * discrepancy between the returned Polygon and the accurate outline * in the data array, expressed as a number of pixels. Insignificant * vertices are removed from the accurate outline, one by one, until * the number of vertices remaining in the returned Polygon equals c "maxvert", f MAXVERT, * or the largest discrepancy between the accurate outline and the * returned Polygon is greater than c "maxerr". If "maxerr" f MAXERR. If MAXERR * is zero or less, its value is ignored and the returned Polygon will * have the number of vertices specified by c "maxvert". f MAXVERT. c maxvert f MAXVERT = INTEGER (Given) * Together with c "maxerr", f MAXERR, * this determines how accurately the returned Polygon represents * the required region of the data array. It gives the maximum * allowed number of vertices in the returned Polygon. Insignificant * vertices are removed from the accurate outline, one by one, until * the number of vertices remaining in the returned Polygon equals c "maxvert", f MAXVERT, * or the largest discrepancy between the accurate outline and the * returned Polygon is greater than c "maxerr". If "maxvert" f MAXERR. If MAXVERT * is less than 3, its value is ignored and the number of vertices in * the returned Polygon will be the minimum needed to ensure that the * discrepancy between the accurate outline and the returned * Polygon is less than c "maxerr". f MAXERR. c inside f INSIDE( 2 ) = INTEGER (Given) c Pointer to an array of two integers f An array * containing the indices of a pixel known to be inside the * required region. This is needed because the supplied data * array may contain several disjoint areas of pixels that satisfy * the criterion specified by c "value" and "oper". f VALUE and OPER. * In such cases, the area described by the returned Polygon will * be the one that contains the pixel specified by c "inside". f INSIDE. * If the specified pixel is outside the bounds given by c "lbnd" and "ubnd", f LBND and UBND, * or has a value that does not meet the criterion specified by c "value" and "oper", f VALUE and OPER, * then this function will search for a suitable pixel. The search * starts at the central pixel and proceeds in a spiral manner until * a pixel is found that meets the specified crierion. c starpix f STARPIX = LOGICAL (Given) * A flag indicating the nature of the pixel coordinate system used * to describe the vertex positions in the returned Polygon. If c non-zero, f .TRUE., * the standard Starlink definition of pixel coordinate is used in * which a pixel with integer index I spans a range of pixel coordinate * from (I-1) to I (i.e. pixel corners have integral pixel coordinates). c If zero, f If .FALSE., * the definition of pixel coordinate used by other AST functions c such as astResample, astMask, f such as AST_RESAMPLE, AST_MASK, * etc., is used. In this definition, a pixel with integer index I * spans a range of pixel coordinate from (I-0.5) to (I+0.5) (i.e. * pixel centres have integral pixel coordinates). c boxsize f BOXSIZE = INTEGER (Given) * The full width in pixels of a smoothing box to be applied to the * polygon vertices before downsizing the polygon to a smaller number * of vertices. If an even number is supplied, the next larger odd * number is used. Values of one or zero result in no smoothing. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astOutline() f AST_OUTLINE = INTEGER * The number of pixels to which a value of c "badval" f BADVAL * has been assigned. * Notes: * - This function proceeds by first finding a very accurate polygon, * and then removing insignificant vertices from this fine polygon * using c astDownsize. f AST_DOWNSIZE. * - The returned Polygon is the outer boundary of the contiguous set * of pixels that includes ths specified "inside" point, and satisfy * the specified value requirement. This set of pixels may potentially * include "holes" where the pixel values fail to meet the specified * value requirement. Such holes will be ignored by this function. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * Data Type Codes: * To select the appropriate masking function, you should c replace in the generic function name astOutline with a f replace in the generic function name AST_OUTLINE with a * 1- or 2-character data type code, so as to match the numerical * type of the data you are processing, as follows: c - D: double c - F: float c - L: long int c - UL: unsigned long int c - I: int c - UI: unsigned int c - S: short int c - US: unsigned short int c - B: byte (signed char) c - UB: unsigned byte (unsigned char) f - D: DOUBLE PRECISION f - R: REAL f - I: INTEGER f - UI: INTEGER (treated as unsigned) f - S: INTEGER*2 (short integer) f - US: INTEGER*2 (short integer, treated as unsigned) f - B: BYTE (treated as signed) f - UB: BYTE (treated as unsigned) * c For example, astOutlineD would be used to process "double" c data, while astOutlineS would be used to process "short int" c data, etc. f For example, AST_OUTLINED would be used to process DOUBLE f PRECISION data, while AST_OUTLINES would be used to process f short integer data (stored in an INTEGER*2 array), etc. f f For compatibility with other Starlink facilities, the codes W f and UW are provided as synonyms for S and US respectively (but f only in the Fortran interface to AST). *-- */ /* Define a macro to implement the function for a specific data type. Note, this function cannot be a virtual function since the argument list does not include a Polygon, and so no virtual function table is available. */ #define MAKE_OUTLINE(X,Xtype) \ AstPolygon *astOutline##X##_( Xtype value, int oper, const Xtype array[], \ const int lbnd[2], const int ubnd[2], double maxerr, \ int maxvert, const int inside[2], int starpix, \ int *status ) { \ \ /* Local Variables: */ \ AstFrame *frm; /* Frame in which to define the Polygon */ \ AstPointSet *candidate; /* Candidate polygon vertices */ \ AstPointSet *pset; /* PointSet holding downsized polygon vertices */ \ AstPolygon *result; /* Result value to return */ \ const Xtype *pv; /* Pointer to next test point */ \ Xtype v; /* Value of current pixel */ \ double **ptr; /* Pointers to PointSet arrays */ \ int boxsize; /* Half width of smoothign box in vertices */ \ int inx; /* X index of inside point */ \ int iny; /* Y index of inside point */ \ int iv; /* Vector index of next test pixel */ \ int ixv; /* X pixel index of next test point */ \ int nv0; /* Number of vertices in accurate outline */ \ int nx; /* Length of array x axis */ \ int smooth; /* Do we need to smooth the polygon? */ \ int stop_at_invalid; /* Indicates when to stop rightwards search */ \ int tmp; /* Alternative boxsize */ \ int valid; /* Does current pixel meet requirements? */ \ static double junk[ 6 ] = {0.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; /* Junk poly */ \ \ /* Initialise. */ \ result = NULL; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Avoid compiler warnings. */ \ iv = 0; \ \ /* If we are going to be smoothing the polygon before downsizing it, we \ need to ensure that the full polygon is retained within TraceEdge. if \ this is not the case, TraceEdge can remove all vertices from straight \ lines, except for the vertices that mark the beinning and end of the \ straight line. */ \ smooth = ( maxerr > 0.0 || maxvert > 2 ); \ \ /* Store the X dimension of the array. */ \ nx = ubnd[ 0 ] - lbnd[ 0 ] + 1; \ \ /* See if a valid inside point was supplied. It must be inside the bounds \ of the array, and must have a pixel value that meets the specified \ requirement. */ \ inx = inside[ 0 ]; \ iny = inside[ 1 ]; \ valid = ( inx >= lbnd[ 0 ] && inx <= ubnd[ 0 ] && \ iny >= lbnd[ 1 ] && iny <= ubnd[ 1 ] ); \ \ if( valid ) { \ iv = ( inx - lbnd[ 0 ] ) + (iny - lbnd[ 1 ] )*nx; \ v = array[ iv ]; \ \ if( oper == AST__LT ) { \ valid = ( v < value ); \ \ } else if( oper == AST__LE ) { \ valid = ( v <= value ); \ \ } else if( oper == AST__EQ ) { \ valid = ( v == value ); \ \ } else if( oper == AST__NE ) { \ valid = ( v != value ); \ \ } else if( oper == AST__GE ) { \ valid = ( v >= value ); \ \ } else if( oper == AST__GT ) { \ valid = ( v > value ); \ \ } else if( astOK ){ \ astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \ "(%d) supplied (programming error).", status, oper ); \ } \ } \ \ /* If no valid inside point was supplied, find one now. */ \ if( !valid ) { \ \ if( oper == AST__LT ) { \ FindInsidePointLT##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( oper == AST__LE ) { \ FindInsidePointLE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( oper == AST__EQ ) { \ FindInsidePointEQ##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( oper == AST__NE ) { \ FindInsidePointNE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( oper == AST__GE ) { \ FindInsidePointGE##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( oper == AST__GT ) { \ FindInsidePointGT##X( value, array, lbnd, ubnd, &inx, &iny, &iv, status ); \ \ } else if( astOK ){ \ astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \ "(%d) supplied (programming error).", status, oper ); \ } \ } \ \ /* We now need to find a point on the boundary of the region containing \ the inside point. Starting at the inside point, move to the right \ through the array until a pixel is found which fails to meet the value \ requirement or the edge of the array is reached. */ \ \ candidate = NULL; \ pv = array + iv; \ ixv = inx; \ stop_at_invalid = 1; \ \ while( ++ixv <= ubnd[ 0 ] ) { \ \ /* Get the next pixel value. */ \ v = *(++pv); \ \ /* See if it meets the value requirement. */ \ if( oper == AST__LT ) { \ valid = ( v < value ); \ \ } else if( oper == AST__LE ) { \ valid = ( v <= value ); \ \ } else if( oper == AST__EQ ) { \ valid = ( v == value ); \ \ } else if( oper == AST__NE ) { \ valid = ( v != value ); \ \ } else if( oper == AST__GE ) { \ valid = ( v >= value ); \ \ } else if( oper == AST__GT ) { \ valid = ( v > value ); \ \ } else if( astOK ){ \ astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \ "(%d) supplied (programming error).", status, oper ); \ break; \ } \ \ /* If we are currently looking for the next invalid pixel, and this pixel \ is invalid... */ \ if( stop_at_invalid ) { \ if( ! valid ) { \ \ /* The current pixel may be on the required polygon, or it may be on the \ edge of a hole contained within the region being outlined. We would \ like to jump over such holes so that we can continue to look for the \ real edge of the region being outlined. In order to determine if we \ have reached a hole, we trace the edge that passes through the current \ pixel, forming a candidate polygon in the process. In the process, We \ see if the inside point falls within this candidate polygon. If it does \ then the polygon is accepted as the required polygon. Otherwise, it is \ rejected as a mere hole, and we continue moving away from the inside \ point, looking for a new edge. */ \ if( oper == AST__LT ) { \ candidate = TraceEdgeLT##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__LE ) { \ candidate = TraceEdgeLE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__EQ ) { \ candidate = TraceEdgeEQ##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__NE ) { \ candidate = TraceEdgeNE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__GE ) { \ candidate = TraceEdgeGE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__GT ) { \ candidate = TraceEdgeGT##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( astOK ){ \ astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \ "(%d) supplied (programming error).", status, oper ); \ } \ \ /* If the candidate polygon is the required polygon, break out of the \ loop. Otherwise, indicate that we want to continue moving right, \ across the hole, until we reach the far side of the hole (i.e. find \ the next valid pixel). */ \ if( candidate ) { \ break; \ } else { \ stop_at_invalid = 0; \ } \ } \ \ /* If we are currently looking for the next valid pixel, and the current \ pixel is valid... */ \ } else if( valid ) { \ \ /* We have reached the far side of a hole. Continue moving right, looking \ now for the next invalid pixel (which may be on the required polygon). */ \ stop_at_invalid = 1; \ } \ } \ \ /* If we have not yet found the required polygon, we must have reached \ the right hand edge of the array. So we now follow the edge of the \ array round until we meet the boundary of the required region. */ \ if( !candidate ) { \ if( oper == AST__LT ) { \ candidate = TraceEdgeLT##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__LE ) { \ candidate = TraceEdgeLE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__EQ ) { \ candidate = TraceEdgeEQ##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__NE ) { \ candidate = TraceEdgeNE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__GE ) { \ candidate = TraceEdgeGE##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( oper == AST__GT ) { \ candidate = TraceEdgeGT##X( value, array, lbnd, ubnd, iv - 1, \ ixv - 1, iny, starpix, smooth, status ); \ \ } else if( astOK ){ \ astError( AST__OPRIN, "astOutline"#X": Invalid operation code " \ "(%d) supplied (programming error).", status, oper ); \ } \ } \ \ /* If required smooth the full resolution polygon before downsizing it. */ \ if( smooth ) { \ \ /* Initially, set the boxsize to be equal to the required accouracy. */ \ if( maxerr > 0 ) { \ boxsize = (int) maxerr; \ } else { \ boxsize = INT_MAX; \ } \ \ /* Determine a second box size equal to the average number of vertices in \ the accurate outline, per vertex in the returned Polygon. */ \ nv0 = astGetNpoint( candidate ); \ if( maxvert > 2 ) { \ tmp = nv0/(2*maxvert); \ } else { \ tmp = INT_MAX; \ } \ \ /* Use the minimum of the two box sizes. */ \ if( tmp < boxsize ) boxsize = tmp; \ \ /* Ensure the box is sufficiently small to allow at least 10 full boxes \ (=20 half boxes) around the polygon. */ \ tmp = nv0/20; \ if( tmp < boxsize ) boxsize = tmp; \ if( boxsize == 0 ) boxsize = 1; \ \ /* Smooth the polygon. */ \ SmoothPoly( candidate, boxsize, 1.0, status ); \ } \ \ /* Reduce the number of vertices in the outline. */ \ frm = astFrame( 2, "Domain=PIXEL,Unit(1)=pixel,Unit(2)=pixel," \ "Title=Pixel coordinates", status ); \ pset = DownsizePoly( candidate, maxerr, maxvert, frm, status ); \ \ /* Create a default Polygon with 3 junk vertices. */ \ result = astPolygon( frm, 3, 3, junk, NULL, " ", status ); \ \ /* Change the PointSet within the Polygon to the one created above. */ \ SetPointSet( result, pset, status ); \ \ /* Free resources. Note, we need to free the arrays within the candidate \ PointSet explicitly, since they were not created as part of the \ construction of the PointSet (see TraceEdge). */ \ pset = astAnnul( pset ); \ frm = astAnnul( frm ); \ ptr = astGetPoints( candidate ); \ if( astOK ) { \ astFree( ptr[ 0 ] ); \ astFree( ptr[ 1 ] ); \ } \ candidate = astAnnul( candidate ); \ \ /* If an error occurred, clear the returned result. */ \ if ( !astOK ) result = astAnnul( result ); \ \ /* Return the result. */ \ return result; \ } /* Expand the above macro to generate a function for each required data type. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ MAKE_OUTLINE(LD,long double) #endif MAKE_OUTLINE(D,double) MAKE_OUTLINE(L,long int) MAKE_OUTLINE(UL,unsigned long int) MAKE_OUTLINE(I,int) MAKE_OUTLINE(UI,unsigned int) MAKE_OUTLINE(S,short int) MAKE_OUTLINE(US,unsigned short int) MAKE_OUTLINE(B,signed char) MAKE_OUTLINE(UB,unsigned char) MAKE_OUTLINE(F,float) /* Undefine the macros. */ #undef MAKE_OUTLINE static double Polywidth( AstFrame *frm, AstLineDef **edges, int i, int nv, double cen[ 2 ], int *status ){ /* * Name: * Polywidth * Purpose: * Find the width of a polygon perpendicular to a given edge. * Type: * Private function. * Synopsis: * #include "polygon.h" * double Polywidth( AstFrame *frm, AstLineDef **edges, int i, int nv, * double cen[ 2 ], int *status ) * Class Membership: * Polygon member function * Description: * This function defines a line perpendicular to a given polygon edge, * passing through the mid point of the edge, extending towards the * inside of the polygon. It returns the distance that can be travelled * along this line before any of the other polygon edges are hit (the * "width" of the polygon perpendicular to the given edge). It also * puts the position corresponding to half that distance into "cen". * Parameters: * frm * The Frame in which the lines are defined. * edges * Array of "nv" pointers to AstLineDef structures, each defining an * edge of the polygon. * i * The index of the edge that is to define the polygon width. * nv * Total number of edges. * cen * An array into which are put the coords of the point half way * along the polygon width line. * status * Pointer to the inherited status variable. * Returnd Value: * The width of the polygon perpendicular to the given edge, or * AST__BAD if the width cannot be determined (usually because the * vertices been supplied in a clockwise direction, effectively * negating the Polygon). */ /* Local Variables: */ AstLineDef *line; double *cross; double d; double end[ 2 ]; double l1; double l2; double result; double start[ 2 ]; int j; /* Check the global error status. */ result = AST__BAD; if ( !astOK ) return result; /* Create a Line description for a line perpendicular to the specified edge, passing through the mid point of the edge, and extending towards the inside of the polygon. First move away from the start along the line to the mid point. This gives the start of the new line. */ l1 = 0.5*( edges[ i ]->length ); astLineOffset( frm, edges[ i ], l1, 0.0, start ); /* We now move away from this position at right angles to the line. We start off by moving 5 times the length of the specified edge. For some Frames (e.g. SkyFrames) this may result in a position that is much too close (i.e. if it goes all the way round the great circle and comes back to the beginning). Therefore, we check that the end point is the requested distance from the start point, and if not, we halve the length of the line and try again. */ l2 = 10.0*l1; while( 1 ) { astLineOffset( frm, edges[ i ], l1, l2, end ); d = astDistance( frm, start, end ); if( d != AST__BAD && fabs( d - l2 ) < 1.0E-6*l2 ) break; l2 *= 0.5; } /* Create a description of the required line. */ line = astLineDef( frm, start, end ); /* Loop round every edge, except for the supplied edge. */ for( j = 0; j < nv; j++ ) { if( j != i ) { /* Find the position at which the line created above crosses the current edge. Skip to the next edge if the line does not intersect the edge within the length of the edge. */ if( astLineCrossing( frm, line, edges[ j ], &cross ) ) { /* Find the distance between the crossing point and the line start. */ d = astDistance( frm, start, cross ); /* If this is less than the smallest found so far, record it. */ if( d != AST__BAD && ( d < result || result == AST__BAD ) ) { result = d; } } /* Free resources */ cross = astFree( cross ); } } line = astFree( line ); /* If a width was found, return the point half way across the polygon. */ if( result != AST__BAD ) { astOffset( frm, start, end, 0.5*result, cen ); /* The usual reason for not finding a width is if the polygon vertices are supplied in clockwise order, effectively negating the polygon, and resulting in the "inside" of the polygon being the infinite region outside a polygonal hole. In this case, the end point of the line perpendicular to the initial edge can be returned as a representative "inside" point. */ } else { cen[ 0 ] = end[ 0 ]; cen[ 1 ] = end[ 1 ]; } /* Return the width. */ return result; } static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){ /* * Name: * RegBaseBox * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "polygon.h" * void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * Polygon member function (over-rides the astRegBaseBox protected * method inherited from the Region class). * Description: * This function returns the upper and lower axis bounds of a Region in * the base Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *frm; /* Pointer to encapsulated Frame */ AstPointSet *pset; /* Pointer to PointSet defining the Region */ AstPolygon *this; /* Pointer to Polygon structure */ AstRegion *reg; /* Base Frame equivalent of supplied Polygon */ double **ptr; /* Pointer to PointSet data */ double *x; /* Pointer to next X axis value */ double *y; /* Pointer to next Y axis value */ double dist; /* Offset along an axis */ double x0; /* The first X axis value */ double y0; /* The first Y axis value */ int ip; /* Point index */ int np; /* No. of points in PointSet */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the Polygon structure. */ this = (AstPolygon *) this_region; /* If the base Frame bounding box has already been found, return the values stored in the Polygon structure. */ if( this->lbnd[ 0 ] != AST__BAD ) { lbnd[ 0 ] = this->lbnd[ 0 ]; lbnd[ 1 ] = this->lbnd[ 1 ]; ubnd[ 0 ] = this->ubnd[ 0 ]; ubnd[ 1 ] = this->ubnd[ 1 ]; /* If the base Frame bounding box has not yet been found, find it now and store it in the Polygon structure. */ } else { /* Get the axis values for the PointSet which defines the location and extent of the region in the base Frame of the encapsulated FrameSet. */ pset = this_region->points; ptr = astGetPoints( pset ); np = astGetNpoint( pset ); /* Get a pointer to the base Frame in the frameset encapsulated by the parent Region structure. */ frm = astGetFrame( this_region->frameset, AST__BASE ); /* Find the upper and lower bounds of the box enclosing all the vertices. The box is expressed in terms of axis offsets from the first vertex, in order to avoid problems with boxes that cross RA=0 or RA=12h */ lbnd[ 0 ] = 0.0; lbnd[ 1 ] = 0.0; ubnd[ 0 ] = 0.0; ubnd[ 1 ] = 0.0; x = ptr[ 0 ]; y = ptr[ 1 ]; x0 = *x; y0 = *y; for( ip = 0; ip < np; ip++, x++, y++ ) { dist = astAxDistance( frm, 1, x0, *x ); if( dist < lbnd[ 0 ] ) { lbnd[ 0 ] = dist; } else if( dist > ubnd[ 0 ] ) { ubnd[ 0 ] = dist; } dist = astAxDistance( frm, 2, y0, *y ); if( dist < lbnd[ 1 ] ) { lbnd[ 1 ] = dist; } else if( dist > ubnd[ 1 ] ) { ubnd[ 1 ] = dist; } } /* Convert the box bounds to absolute values, rather than values relative to the first vertex. */ lbnd[ 0 ] += x0; lbnd[ 1 ] += y0; ubnd[ 0 ] += x0; ubnd[ 1 ] += y0; /* The astNormBox requires a Mapping which can be used to test points in this base Frame. Create a copy of the Polygon and then set its FrameSet so that the current Frame in the copy is the same as the base Frame in the original. */ reg = astCopy( this ); astSetRegFS( reg, frm ); astSetNegated( reg, 0 ); /* Normalise this box. */ astNormBox( frm, lbnd, ubnd, reg ); /* Free resources */ reg = astAnnul( reg ); frm = astAnnul( frm ); /* Store it in the olygon structure for future use. */ this->lbnd[ 0 ] = lbnd[ 0 ]; this->lbnd[ 1 ] = lbnd[ 1 ]; this->ubnd[ 0 ] = ubnd[ 0 ]; this->ubnd[ 1 ] = ubnd[ 1 ]; } } static AstPointSet *RegBaseMesh( AstRegion *this_region, int *status ){ /* * Name: * RegBaseMesh * Purpose: * Return a PointSet containing a mesh of points on the boundary of a * Region in its base Frame. * Type: * Private function. * Synopsis: * #include "polygon.h" * AstPointSet *astRegBaseMesh( AstRegion *this, int *status ) * Class Membership: * Polygon member function (over-rides the astRegBaseMesh protected * method inherited from the Region class). * Description: * This function returns a PointSet containing a mesh of points on the * boundary of the Region. The points refer to the base Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the PointSet. Annul the pointer using astAnnul when it * is no longer needed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstFrame *frm; /* Base Frame in encapsulated FrameSet */ AstPointSet *result; /* Returned pointer */ AstPolygon *this; /* The Polygon structure */ double **rptr; /* Pointers to returned mesh data */ double **vptr; /* Pointers to vertex data */ double *lens; /* Pointer to work space holding edge lengths */ double d; /* Length of this edge */ double delta; /* Angular separation of points */ double end[ 2 ]; /* End position */ double mp; /* No. of mesh points per unit distance */ double p[ 2 ]; /* Position in 2D Frame */ double start[ 2 ]; /* Start position */ double total; /* Total length of polygon */ int ip; /* Point index */ int iv; /* Vertex index */ int n; /* No. of points on this edge */ int next; /* Index of next point in returned PointSet */ int np; /* No. of points in returned PointSet */ int nv; /* No. of polygon vertices */ /* Initialise */ result= NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the Region structure contains a pointer to a PointSet holding a previously created mesh, return it. */ if( this_region->basemesh ) { result = astClone( this_region->basemesh ); /* Otherwise, create a new mesh. */ } else { /* Get a pointer to the Polygon structure. */ this = (AstPolygon *) this_region; /* Get a pointer to the base Frame in the encapsulated FrameSet. */ frm = astGetFrame( this_region->frameset, AST__BASE ); /* Get the number of vertices and pointers to the vertex axis values. */ nv = astGetNpoint( this_region->points ); vptr = astGetPoints( this_region->points ); /* Allocate memory to hold the geodesic length of each edge. */ lens = astMalloc( sizeof( double )*(size_t) nv ); if( astOK ) { /* Find the total geodesic distance around the boundary. */ total = 0.0; start[ 0 ] = vptr[ 0 ][ 0 ]; start[ 1 ] = vptr[ 1 ][ 0 ]; for( iv = 1; iv < nv; iv++ ) { end[ 0 ] = vptr[ 0 ][ iv ]; end[ 1 ] = vptr[ 1 ][ iv ]; d = astDistance( frm, start, end ); if( d != AST__BAD ) total += fabs( d ); lens[ iv ] = d; start[ 0 ] = end[ 0 ]; start[ 1 ] = end[ 1 ]; } end[ 0 ] = vptr[ 0 ][ 0 ]; end[ 1 ] = vptr[ 1 ][ 0 ]; d = astDistance( frm, start, end ); if( d != AST__BAD ) total += fabs( d ); lens[ 0 ] = d; /* Find the number of mesh points per unit geodesic distance. */ if( total > 0.0 ){ mp = astGetMeshSize( this )/total; /* Find the total number of mesh points required. */ np = 0; for( iv = 0; iv < nv; iv++ ) { if( lens[ iv ] != AST__BAD ) np += 1 + (int)( lens[ iv ]*mp ); } /* Create a suitable PointSet to hold the returned positions. */ result = astPointSet( np, 2, "", status ); rptr = astGetPoints( result ); if( astOK ) { /* Initialise the index of the next point to be added to the returned PointSet. */ next = 0; /* Loop round each good edge of the polygon. The edge ends at vertex "iv". */ start[ 0 ] = vptr[ 0 ][ 0 ]; start[ 1 ] = vptr[ 1 ][ 0 ]; for( iv = 1; iv < nv; iv++ ) { end[ 0 ] = vptr[ 0 ][ iv ]; end[ 1 ] = vptr[ 1 ][ iv ]; if( lens[ iv ] != AST__BAD ) { /* Add the position of the starting vertex to the returned mesh. */ rptr[ 0 ][ next ] = start[ 0 ]; rptr[ 1 ][ next ] = start[ 1 ]; next++; /* Find the number of points on this edge, and the geodesic distance between them. */ n = 1 + (int) ( lens[ iv ]*mp ); /* If more than one point, find the distance between points. */ if( n > 1 ) { delta = lens[ iv ]/n; /* Loop round the extra points. */ for( ip = 1; ip < n; ip++ ) { /* Find the position of the next mesh point. */ astOffset( frm, start, end, delta*ip, p ); /* Add it to the mesh. */ rptr[ 0 ][ next ] = p[ 0 ]; rptr[ 1 ][ next ] = p[ 1 ]; next++; } } } /* The end of this edge becomes the start of the next. */ start[ 0 ] = end[ 0 ]; start[ 1 ] = end[ 1 ]; } /* Now do the edge which ends at the first vertex. */ end[ 0 ] = vptr[ 0 ][ 0 ]; end[ 1 ] = vptr[ 1 ][ 0 ]; if( lens[ 0 ] != AST__BAD ) { rptr[ 0 ][ next ] = start[ 0 ]; rptr[ 1 ][ next ] = start[ 1 ]; next++; n = 1 + (int)( lens[ 0 ]*mp ); if( n > 1 ) { delta = lens[ 0 ]/n; for( ip = 1; ip < n; ip++ ) { astOffset( frm, start, end, delta*ip, p ); rptr[ 0 ][ next ] = p[ 0 ]; rptr[ 1 ][ next ] = p[ 1 ]; next++; } } } /* Check the PointSet size was correct. */ if( next != np && astOK ) { astError( AST__INTER, "astRegBaseMesh(%s): Error in the " "allocated PointSet size (%d) - should have " "been %d (internal AST programming error).", status, astGetClass( this ), np, next ); } /* Save the returned pointer in the Region structure so that it does not need to be created again next time this function is called. */ if( astOK ) this_region->basemesh = astClone( result ); } } else if( astOK ) { astError( AST__BADIN, "astRegBaseMesh(%s): The boundary of " "the supplied %s has an undefined length.", status, astGetClass( this ), astGetClass( this ) ); } } /* Free resources. */ frm = astAnnul( frm ); lens = astFree( lens ); } /* Annul the result if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc, int **mask, int *status ){ /* * Name: * RegPins * Purpose: * Check if a set of points fall on the boundary of a given Polygon. * Type: * Private function. * Synopsis: * #include "polygon.h" * int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, * int **mask, int *status ) * Class Membership: * Polygon member function (over-rides the astRegPins protected * method inherited from the Region class). * Description: * This function returns a flag indicating if the supplied set of * points all fall on the boundary of the given Polygon. * * Some tolerance is allowed, as specified by the uncertainty Region * stored in the supplied Polygon "this", and the supplied uncertainty * Region "unc" which describes the uncertainty of the supplied points. * Parameters: * this * Pointer to the Polygon. * pset * Pointer to the PointSet. The points are assumed to refer to the * base Frame of the FrameSet encapsulated by "this". * unc * Pointer to a Region representing the uncertainties in the points * given by "pset". The Region is assumed to represent the base Frame * of the FrameSet encapsulated by "this". Zero uncertainity is assumed * if NULL is supplied. * mask * Pointer to location at which to return a pointer to a newly * allocated dynamic array of ints. The number of elements in this * array is equal to the value of the Npoint attribute of "pset". * Each element in the returned array is set to 1 if the * corresponding position in "pset" is on the boundary of the Region * and is set to zero otherwise. A NULL value may be supplied * in which case no array is created. If created, the array should * be freed using astFree when no longer needed. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the points all fall on the boundary of the given * Region, to within the tolerance specified. Zero otherwise. */ /* Local variables: */ AstFrame *frm; /* Base Frame in supplied Polygon */ AstPointSet *pset1; /* Pointer to copy of supplied PointSet */ AstPointSet *pset2; /* Pointer to PointSet holding resolved components */ AstPolygon *this; /* Pointer to the Polygon structure. */ AstRegion *tunc; /* Uncertainity Region from "this" */ double **ptr1; /* Pointer to axis values in "pset1" */ double **ptr2; /* Pointer to axis values in "pset2" */ double **vptr; /* Pointer to axis values at vertices */ double *safe; /* An interior point in "this" */ double edge_len; /* Length of current edge */ double end[2]; /* Position of end of current edge */ double l1; /* Length of bounding box diagonal */ double l2; /* Length of bounding box diagonal */ double lbnd_tunc[2]; /* Lower bounds of "this" uncertainty Region */ double lbnd_unc[2]; /* Lower bounds of supplied uncertainty Region */ double par; /* Parallel component */ double parmax; /* Max acceptable parallel component */ double prp; /* Perpendicular component */ double start[2]; /* Position of start of current edge */ double ubnd_tunc[2]; /* Upper bounds of "this" uncertainty Region */ double ubnd_unc[2]; /* Upper bounds of supplied uncertainty Region */ double wid; /* Width of acceptable margin around polygon */ int *m; /* Pointer to next mask value */ int i; /* Edge index */ int ip; /* Point index */ int np; /* No. of supplied points */ int nv; /* No. of vertices */ int result; /* Returned flag */ /* Initialise */ result = 0; if( mask ) *mask = NULL; /* Check the inherited status. */ if( !astOK ) return result; /* Get a pointer to the Polygon structure. */ this = (AstPolygon *) this_region; /* Check the supplied PointSet has 2 axis values per point. */ if( astGetNcoord( pset ) != 2 && astOK ) { astError( AST__INTER, "astRegPins(%s): Illegal number of axis " "values per point (%d) in the supplied PointSet - should be " "2 (internal AST programming error).", status, astGetClass( this ), astGetNcoord( pset ) ); } /* Get the number of axes in the uncertainty Region and check it is also 2. */ if( unc && astGetNaxes( unc ) != 2 && astOK ) { astError( AST__INTER, "astRegPins(%s): Illegal number of axes (%d) " "in the supplied uncertainty Region - should be 2 " "(internal AST programming error).", status, astGetClass( this ), astGetNaxes( unc ) ); } /* Get pointers to the axis values at the polygon vertices. */ vptr = astGetPoints( this_region->points ); /* Get the number of vertices. */ nv = astGetNpoint( this_region->points ); /* Take a copy of the supplied PointSet and get pointers to its axis values,and its size */ pset1 = astCopy( pset ); ptr1 = astGetPoints( pset1 ); np = astGetNpoint( pset1 ); /* Create a PointSet to hold the resolved components and get pointers to its axis data. */ pset2 = astPointSet( np, 2, "", status ); ptr2 = astGetPoints( pset2 ); /* Create a mask array if required. */ if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np ); /* Get the centre of the region in the base Frame. We use this as a "safe" interior point within the region. */ safe = astRegCentre( this, NULL, NULL, 0, AST__BASE ); /* We now find the maximum distance on each axis that a point can be from the boundary of the Polygon for it still to be considered to be on the boundary. First get the Region which defines the uncertainty within the Polygon being checked (in its base Frame), re-centre it on the interior point found above (to avoid problems if the uncertainty region straddles a discontinuity), and get its bounding box. The current Frame of the uncertainty Region is the same as the base Frame of the Polygon. */ tunc = astGetUncFrm( this, AST__BASE ); if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT ); astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc ); /* Find the geodesic length within the base Frame of "this" of the diagonal of the bounding box. */ frm = astGetFrame( this_region->frameset, AST__BASE ); l1 = astDistance( frm, lbnd_tunc, ubnd_tunc ); /* Also get the Region which defines the uncertainty of the supplied points and get its bounding box. First re-centre the uncertainty at the interior position to avoid problems from uncertainties that straddle a discontinuity. */ if( unc ) { if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT ); astGetRegionBounds( unc, lbnd_unc, ubnd_unc ); /* Find the geodesic length of the diagonal of this bounding box. */ l2 = astDistance( frm, lbnd_unc, ubnd_unc ); /* Assume zero uncertainty if no "unc" Region was supplied. */ } else { l2 = 0.0; } /* The required border width is half of the total diagonal of the two bounding boxes. */ if( astOK ) { wid = 0.5*( l1 + l2 ); /* Loop round each edge of the polygon. Edge "i" starts at vertex "i-1" and ends at vertex "i". Edge zero starts at vertex "nv-1" and ends at vertex zero. */ start[ 0 ] = vptr[ 0 ][ nv - 1 ]; start[ 1 ] = vptr[ 1 ][ nv - 1 ]; for( i = 0; i < nv; i++ ) { end[ 0 ] = vptr[ 0 ][ i ]; end[ 1 ] = vptr[ 1 ][ i ]; /* Find the length of this edge. */ edge_len = astDistance( frm, start, end ); /* Resolve all the supplied mesh points into components parallel and perpendicular to this edge. */ (void) astResolvePoints( frm, start, end, pset1, pset2 ); /* A point is effectively on this edge if the parallel component is greater than (-wid) and less than (edge_len+wid) AND the perpendicular component has an absolute value less than wid. Identify such positions and set them bad in pset1. */ parmax = edge_len + wid; for( ip = 0; ip < np; ip++ ) { par = ptr2[ 0 ][ ip ]; prp = ptr2[ 1 ][ ip ]; if( par != AST__BAD && prp != AST__BAD ) { if( par > -wid && par < parmax && prp > -wid && prp < wid ) { ptr1[ 0 ][ ip ] = AST__BAD; ptr1[ 1 ][ ip ] = AST__BAD; } } } /* The end of the current edge becomes the start of the next. */ start[ 0 ] = end[ 0 ]; start[ 1 ] = end[ 1 ]; } /* See if any good points are left in pset1. If so, it means that those points were not on any edge of hte Polygon. We use two alogorithms here depending on whether we are creating a mask array, since we can abort the check upon finding the first good point if we are not producing a mask. */ result = 1; if( mask ) { m = *mask; for( ip = 0; ip < np; ip++, m++ ) { if( ptr1[ 0 ][ ip ] != AST__BAD && ptr1[ 1 ][ ip ] != AST__BAD ) { *m = 0; result = 0; } else { *m = 1; } } } else { for( ip = 0; ip < np; ip++, m++ ) { if( ptr1[ 0 ][ ip ] != AST__BAD && ptr1[ 1 ][ ip ] != AST__BAD ) { result = 0; break; } } } } /* Free resources. */ tunc = astAnnul( tunc ); frm = astAnnul( frm ); safe = astFree( safe ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* If an error has occurred, return zero. */ if( !astOK ) { result = 0; if( mask ) *mask = astAnnul( *mask ); } /* Return the result. */ return result; } static int RegTrace( AstRegion *this_region, int n, double *dist, double **ptr, int *status ){ /* *+ * Name: * RegTrace * Purpose: * Return requested positions on the boundary of a 2D Region. * Type: * Private function. * Synopsis: * #include "polygon.h" * int astTraceRegion( AstRegion *this, int n, double *dist, double **ptr ); * Class Membership: * Polygon member function (overrides the astTraceRegion method * inherited from the parent Region class). * Description: * This function returns positions on the boundary of the supplied * Region, if possible. The required positions are indicated by a * supplied list of scalar parameter values in the range zero to one. * Zero corresponds to some arbitrary starting point on the boundary, * and one corresponds to the end (which for a closed region will be * the same place as the start). * Parameters: * this * Pointer to the Region. * n * The number of positions to return. If this is zero, the function * returns without action (but the returned function value still * indicates if the method is supported or not). * dist * Pointer to an array of "n" scalar parameter values in the range * 0 to 1.0. * ptr * A pointer to an array of pointers. The number of elements in * this array should equal tthe number of axes in the Frame spanned * by the Region. Each element of the array should be a pointer to * an array of "n" doubles, in which to return the "n" values for * the corresponding axis. The contents of the arrays are unchanged * if the supplied Region belongs to a class that does not * implement this method. * Returned Value: * Non-zero if the astTraceRegion method is implemented by the class * of Region supplied, and zero if not. *- */ /* Local Variables; */ AstFrame *frm; AstMapping *map; AstPointSet *bpset; AstPointSet *cpset; AstPolygon *this; double **bptr; double d; double p[ 2 ]; int i; int j0; int j; int ncur; int nv; int monotonic; /* Check inherited status, and the number of points to return, returning a non-zero value to indicate that this class supports the astRegTrace method. */ if( ! astOK || n == 0 ) return 1; /* Get a pointer to the Polygon structure. */ this = (AstPolygon *) this_region; /* Ensure cached information is available. */ Cache( this, status ); /* Get a pointer to the base Frame in the encapsulated FrameSet. */ frm = astGetFrame( this_region->frameset, AST__BASE ); /* We first determine the required positions in the base Frame of the Region, and then transform them into the current Frame. Get the base->current Mapping, and the number of current Frame axes. */ map = astGetMapping( this_region->frameset, AST__BASE, AST__CURRENT ); /* If it's a UnitMap we do not need to do the transformation, so put the base Frame positions directly into the supplied arrays. */ if( astIsAUnitMap( map ) ) { bpset = NULL; bptr = ptr; ncur = 2; /* Otherwise, create a PointSet to hold the base Frame positions (known to be 2D since this is an polygon). */ } else { bpset = astPointSet( n, 2, " ", status ); bptr = astGetPoints( bpset ); ncur = astGetNout( map ); } /* Check the pointers can be used safely. */ if( astOK ) { /* Get the number of vertices. */ nv = astGetNpoint( this_region->points ); /* If we have a reasonable number of pointsand there are a reasonable number of vertices, we can be quicker if we know if the parameteric distances are monotonic increasing. Find out now. */ if( n > 5 && nv > 5 ) { monotonic = 1; for( i = 1; i < n; i++ ) { if( dist[ i ] < dist[ i - 1 ] ) { monotonic = 0; break; } } } else { monotonic = 0; } /* Loop round each point. */ j0 = 1; for( i = 0; i < n; i++ ) { /* Get the required round the polygon, starting from vertex zero. */ d = dist[ i ]*this->totlen; /* Loop round each vertex until we find one which is beyond the required point. If the supplied distances are monotonic increasing, we can start the checks at the same vertex that was used for the previous since we know there will never be a backward step. */ for( j = j0; j < nv; j++ ) { if( this->startsat[ j ] > d ) break; } /* If the distances are monotonic increasing, record the vertex that we have reached so far. */ if( monotonic ) j0 = j; /* Find the distance to travel beyond the previous vertex. */ d -= this->startsat[ j - 1 ]; /* Find the position, that is the required distance from the previous vertex towards the next vertex. */ astLineOffset( frm, this->edges[ j - 1 ], d, 0.0, p ); /* Store the resulting axis values. */ bptr[ 0 ][ i ] = p[ 0 ]; bptr[ 1 ][ i ] = p[ 1 ]; } } /* If required, transform the base frame positions into the current Frame, storing them in the supplied array. Then free resources. */ if( bpset ) { cpset = astPointSet( n, ncur, " ", status ); astSetPoints( cpset, ptr ); (void) astTransform( map, bpset, 1, cpset ); cpset = astAnnul( cpset ); bpset = astAnnul( bpset ); } /* Free remaining resources. */ map = astAnnul( map ); frm = astAnnul( frm ); /* Return a non-zero value to indicate that this class supports the astRegTrace method. */ return 1; } static Segment *RemoveFromChain( Segment *head, Segment *seg, int *status ){ /* * Name: * RemoveFromChain * Purpose: * Remove a Segment from the link list maintained by astDownsize. * Type: * Private function. * Synopsis: * #include "polygon.h" * Segment *RemoveFromChain( Segment *head, Segment *seg, int *status ) * Class Membership: * Polygon member function * Description: * The supplied Segment is removed form the list, and the gap is * closed up. * Parameters: * head * The Segment structure at the head of the list. * seg * The Segment to be removed from the list. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the link head (which will have changed if "seg" was the * original head). */ /* Check the global error status. */ if ( !astOK ) return head; /* If the Segment was the original head, make the next segment the new head. */ if( head == seg ) head = seg->next; /* Close up the links between the Segments on either side of the segment being removed. */ if( seg->prev ) seg->prev->next = seg->next; if( seg->next ) seg->next->prev = seg->prev; /* Nullify the links in the segment being removed. */ seg->next = NULL; seg->prev = NULL; /* Return the new head. */ return head; } static void ResetCache( AstRegion *this, int *status ){ /* * Name: * ResetCache * Purpose: * Clear cached information within the supplied Region. * Type: * Private function. * Synopsis: * #include "polygon.h" * void ResetCache( AstRegion *this, int *status ) * Class Membership: * Region member function (overrides the astResetCache method * inherited from the parent Region class). * Description: * This function clears cached information from the supplied Region * structure. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. */ if( this ) { ( (AstPolygon *) this )->stale = 1; ( (AstPolygon *) this )->lbnd[ 0 ] = AST__BAD; (*parent_resetcache)( this, status ); } } static void SetPointSet( AstPolygon *this, AstPointSet *pset, int *status ){ /* * Name: * SetPointSet * Purpose: * Store a new set of vertices in an existing Polygon. * Type: * Private function. * Synopsis: * #include "polygon.h" * void SetPointSet( AstPolygon *this, AstPointSet *pset, int *status ) * Class Membership: * Polygon member function * Description: * The PointSet in the supplied Polygon is annulled, are stored in the supplied * Polygon, replacing the existing data pointers. * Parameters: * this * Pointer to the Polygon to be changed. * pset * The PointSet containing the enw vertex information. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if ( !astOK ) return; /* Annul the pointer to the PointSet already in the supplied Polygon. */ (void) astAnnul( ((AstRegion *) this)->points ); /* Store a clone of the supplie dnew PointSet pointer. */ ((AstRegion *) this)->points = astClone( pset ); /* Indicate the cached information in the polygon will need to be re-calculated when needed. */ astResetCache( this ); } static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) { /* * Name: * SetRegFS * Purpose: * Stores a new FrameSet in a Region * Type: * Private function. * Synopsis: * #include "polygon.h" * void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) * Class Membership: * Polygon method (over-rides the astSetRegFS method inherited from * the Region class). * Description: * This function creates a new FrameSet and stores it in the supplied * Region. The new FrameSet contains two copies of the supplied * Frame, connected by a UnitMap. * Parameters: * this * Pointer to the Region. * frm * The Frame to use. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the parent method to store the FrameSet in the parent Region structure. */ (* parent_setregfs)( this_region, frm, status ); /* Indicate cached information eeds re-calculating. */ astResetCache( this_region ); } static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { /* * Name: * Simplify * Purpose: * Simplify the Mapping represented by a Region. * Type: * Private function. * Synopsis: * #include "polygon.h" * AstMapping *Simplify( AstMapping *this, int *status ) * Class Membership: * Polygon method (over-rides the astSimplify method inherited * from the Region class). * Description: * This function invokes the parent Region Simplify method, and then * performs any further region-specific simplification. * * If the Mapping from base to current Frame is not a UnitMap, this * will include attempting to fit a new Region to the boundary defined * in the current Frame. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the simplified Region. A cloned pointer to the * supplied Region will be returned if no simplication could be * performed. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *frm; /* Current Frame */ AstMapping *map; /* Base -> current Mapping */ AstMapping *result; /* Result pointer to return */ AstPointSet *mesh; /* Mesh of current Frame positions */ AstPointSet *ps2; /* Polygon PointSet in current Frame */ AstPolygon *newpol; /* New Polygon */ AstRegion *new; /* Pointer to simplified Region */ AstRegion *this; /* Pointer to supplied Region structure */ AstRegion *unc; /* Pointer to uncertainty Region */ double **ptr2; /* Pointer axis values in "ps2" */ double *mem; /* Pointer to array holding new vertex coords */ double *p; /* Pointer to next vertex coords */ double *q; /* Pointer to next vertex coords */ int iv; /* Vertex index */ int nv; /* Number of vertices in polygon */ int ok; /* Are the new polygon vertices good? */ int simpler; /* Has some simplication taken place? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the supplied Region structure. */ this = (AstRegion *) this_mapping; /* Invoke the parent Simplify method inherited from the Region class. This will simplify the encapsulated FrameSet and uncertainty Region. */ new = (AstRegion *) (*parent_simplify)( this_mapping, status ); /* Note if any simplification took place. This is assumed to be the case if the pointer returned by the above call is different to the supplied pointer. */ simpler = ( new != this ); /* We attempt to simplify the Polygon by re-defining it within its current Frame. Transforming the Polygon from its base to its current Frame may result in the region no longer being an polygon. We test this by transforming a set of bounds on the Polygon boundary. This can only be done if the current Frame is 2-dimensional. Also, there is only any point in doing it if the Mapping from base to current Frame in the Polygon is not a UnitMap. */ map = astGetMapping( new->frameset, AST__BASE, AST__CURRENT ); if( !astIsAUnitMap( map ) && astGetNout( map ) == 2 ) { /* Get a pointer to the Frame represented by the Polgon. */ frm = astGetFrame( new->frameset, AST__CURRENT ); /* Get a mesh of points covering the Polygon in this Frame. */ mesh = astRegMesh( new ); /* Get the Region describing the positional uncertainty in this Frame. */ unc = astGetUncFrm( new, AST__CURRENT ); /* Get the positions of the vertices within this Frame. */ ps2 = astRegTransform( this, this->points, 1, NULL, NULL ); ptr2 = astGetPoints( ps2 ); /* Get the number of vertices. */ nv = astGetNpoint( ps2 ); /* Re-organise the vertex axis values into the form required by the Polygon constructor function. */ mem = astMalloc( sizeof( double)*(size_t)( 2*nv ) ); if( astOK ) { ok = 1; p = mem; q = ptr2[ 0 ]; for( iv = 0; iv < nv; iv++ ) { if( ( *(p++) = *(q++) ) == AST__BAD ) ok = 0; } q = ptr2[ 1 ]; for( iv = 0; iv < nv; iv++ ) *(p++) = *(q++); /* Create a new Polygon using these transformed vertices. */ newpol = ok ? astPolygon( frm, nv, nv, mem, unc, "", status ) : NULL; /* See if all points within the mesh created from the original Polygon fall on the boundary of the new Polygon, to within the uncertainty of the Region. */ if( newpol && astRegPins( newpol, mesh, NULL, NULL ) ) { /* If so, use the new Polygon in place of the original Region. */ (void) astAnnul( new ); new = astClone( newpol ); simpler =1; } /* Free resources. */ if( newpol ) newpol = astAnnul( newpol ); } frm = astAnnul( frm ); mesh = astAnnul( mesh ); unc = astAnnul( unc ); ps2 = astAnnul( ps2 ); mem = astFree( mem ); } map = astAnnul( map ); /* If any simplification could be performed, copy Region attributes from the supplied Region to the returned Region, and return a pointer to it. If the supplied Region had no uncertainty, ensure the returned Region has no uncertainty. Otherwise, return a clone of the supplied pointer. */ if( simpler ){ astRegOverlay( new, this, 1 ); result = (AstMapping *) new; } else { new = astAnnul( new ); result = astClone( this ); } /* If an error occurred, annul the returned pointer. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static void SmoothPoly( AstPointSet *pset, int boxsize, double strength, int *status ) { /* * Name: * SmoothPoly * Purpose: * Smoooth a polygon assuming plane geometry. * Type: * Private function. * Synopsis: * #include "polygon.h" * void SmoothPoly( AstPointSet *pset, int boxsize, double strength, * int *status ) * Class Membership: * Polygon member function * Description: * This function smooths a polygon, without changing the number of * vertices. It assumes plane geometry, so should not be used to * smooth polygons defined within a SkyFrame or CmpFrame. * * Each vertex is replaced by a new vertex determined as follows: the * mean X and Y axis value of the vertices in a section of the polygon * centred on the vertex being replaced are found (the length of the * section is given by parameter "boxsize"). The new vertex position * is then the weighted mean of this mean (X,Y) position and the old * vertex position. The weight for the mean (X,Y) position is given * by parameter "strength", and the weight for the old vertex * position is (1.0 - strength) * Parameters: * pset * A PointSet holding the polygon vertices. * boxsize * Half width of the box filter, given as a number of vertices. * strength * The weight to use for the mean (X,Y) position when finding each * new vertex position. Should be in the range 0.0 to 1.0. A value * of zero results in no change being made to the polygon. A value * of 1.0 results in the returned polygon being fully smoothed. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double **ptr; double *newx; double *newy; double *nx; double *ny; double *oldx; double *oldy; double *ox; double *oy; double *px; double *py; double *qx; double *qy; double a; double b; double sx; double sy; int half_width; int i; int nv; int top; /* Check the global error status. */ if ( !astOK ) return; /* Get the number of vertices. */ nv = astGetNpoint( pset ); /* Get pointers to arrays holding the supplied vertex positions. */ ptr = astGetPoints( pset ); oldx = ptr[ 0 ]; oldy = ptr[ 1 ]; /* Allocate arrays to hold the returned vertex positions. */ newx = astMalloc( nv*sizeof( double ) ); newy = astMalloc( nv*sizeof( double ) ); /* Check these pointers can be used safely. */ if( astOK ) { /* Get weighting factors for the fully smoothed and unsmoothed positions. */ a = strength; b = 1.0 - a; /* Ensure the box size is sufficiently small for there to be room for two boxes along the polygon. */ half_width = nv/4 - 1; if( boxsize < half_width ) half_width = boxsize; if( half_width < 1 ) half_width = 1; /* Modify the weight for the fully smoothed position to include the normalisation factor needed to account for the box width. */ a /= 2*half_width + 1; /* Find the sum of the x and y coordinates within a box centred on the first vertex. This includes vertices from the end of the polygon. */ px = oldx + 1; qx = oldx + nv; sx = (oldx)[ 0 ]; py = oldy + 1; qy = oldy + nv; sy = (oldy)[ 0 ]; for( i = 0; i < half_width; i++ ) { sx += *(px++) + *(--qx); sy += *(py++) + *(--qy); } /* Replacing vertices within the first half box will include vertices at both ends of the polygon. Set up the pointers accordingly, and then find replacements for each vertex in the first half box.*/ ox = oldx; oy = oldy; nx = newx; ny = newy; for( i = 0; i < half_width; i++ ) { /* Form the new vertex (x,y) values as the weighted mean of the mean (x,y) values in the box, and the old (x,y) values. */ *(nx++) = a*sx + b*( *(ox++) ); *(ny++) = a*sy + b*( *(oy++) ); /* Add in the next vertex X and Y axis values to the running sums, and remove the position that has now passed out of the box. */ sx += *(px++) - *(qx++); sy += *(py++) - *(qy++); } /* Adjust the pointer for the rest of the polygon, up to one half box away from the end. In this section, the smoothing box does not touch either end of the polygon. */ top = nv - half_width - 1; qx = oldx; qy = oldy; for( ; i < top; i++ ){ /* Form the new vertex (x,y) values as the weighted mean of the mean (x,y) values in the box, and the old (x,y) values. */ *(nx++) = a*sx + b*( *(ox++) ); *(ny++) = a*sy + b*( *(oy++) ); /* Add in the next vertex X and Y axis values to the running sums, and remove the position that has now passed out of the box. */ sx += *(px++) - *(qx++); sy += *(py++) - *(qy++); } /* Now do the last half box (which includes vertices from the start of the polygon). */ top = nv; px = oldx; py = oldy; for( ; i < top; i++ ){ *(nx++) = a*sx + b*( *(ox++) ); *(ny++) = a*sy + b*( *(oy++) ); sx += *(px++) - *(qx++); sy += *(py++) - *(qy++); } /* Replace the data points in the PointSet. */ ptr[ 0 ] = newx; ptr[ 1 ] = newy; oldx = astFree( oldx ); oldy = astFree( oldy ); } } /* * Name: * TraceEdge * Purpose: * Find a point that is inside the required outline. * Type: * Private function. * Synopsis: * #include "polygon.h" * void TraceEdge( value, const array[], * const int lbnd[ 2 ], const int ubnd[ 2 ], * int iv0, int ix0, int iy0, int starpix, * int full, int *status ); * Class Membership: * Polygon member function * Description: * This function forms a polygon enclosing the region of the data * array specified by and "value". If this polygon contains * the point "(inx,iny)", then a PointSet is returned holding the * pixel coordinates of the Polygon vertices. If the polygon * does not contain "(inx,iny)", a NULL pointer is returned. * * Each vertex in the polygon corresponds to a corner of a pixel in * the data array. * Parameters: * value * The data value defining valid pixels. * array * The data array. * lbnd * The lower pixel index bounds of the array. * ubnd * The upper pixel index bounds of the array. * iv0 * The vector index of a pixel inside the region such that the * pixel to the right is NOT inside the region. This defines the * start of the polygon. * ix0 * The X pixel index of the pixel specified by "iv0". * inx * The X pixel index of a point which must be inside the polygon * for the polygon to be acceptable. * iny * The Y pixel index of a point which must be inside the polygon * for the polygon to be acceptable. * starpix * If non-zero, the usual Starlink definition of pixel coordinate * is used (integral values at pixel corners). Otherwise, the * system used by other AST functions such as astResample is used * (integral values at pixel centres). * full * If non-zero, the full polygon is stored. If zero, vertices in the * middle of straight sections of the Polygon are omitted. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a PointSet holding the vertices of the polygon, or * NULL if the polygon did not contain "(inx,iny)". * Notes: * - must be one of LT, LE, EQ, GE, GT, NE. */ /* Define a macro to implement the function for a specific data type and operation. */ #define MAKE_TRACEEDGE(X,Xtype,Oper,OperI) \ static AstPointSet *TraceEdge##Oper##X( Xtype value, const Xtype array[], \ const int lbnd[ 2 ], const int ubnd[ 2 ], \ int iv0, int ix0, int iy0, \ int starpix, int full, \ int *status ){ \ \ /* Local Variables: */ \ AstPointSet *result; /* Pointer to text describing oper */ \ const Xtype *pa; /* Pointer to current valid pixel value */ \ const Xtype *pb; /* Pointer to neigbouring valid pixel value */ \ const Xtype *pc; /* Pointer to neigbouring valid pixel value */ \ double *ptr[ 2 ]; /* PointSet data pointers */ \ double *xvert; /* Pointer to array holding vertex X axis values */ \ double *yvert; /* Pointer to array holding vertex Y axis values */ \ double xx; /* Pixel X coord at corner */ \ double yy; /* Pixel Y coord at corner */ \ int at; /* The pixel corner to draw to */ \ int done; /* Have we arrived back at the start of the polygon? */ \ int ii; /* Index of new vertex */ \ int ix; /* X pixel index of current valid pixel */ \ int iy; /* Y pixel index of current valid pixel */ \ int nright; /* Overall number of right hand turns along polygon */ \ int nvert; /* Number of vertices */ \ int nx; /* Pixels per row */ \ \ /* Initialise */ \ result = NULL; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ \ /* Initialise pointers to arrays holding the X and Y pixel coordinates at \ the vertices of the polygon. */ \ xvert = NULL; \ yvert = NULL; \ nvert = 0; \ \ /* Find number of pixels in one row of the array. */ \ nx = ( ubnd[ 0 ] - lbnd[ 0 ] + 1 ); \ \ /* The four corners of a pixel are numbered as follows: 0=bottom left, \ 1=top left, 2=top right, 3=bottom right. The following algorithm moves \ along pixel edges, from corner to corner, using the above numbering \ scheme to identify the corners. We start the polygon by moving from the \ bottom right to the top right corner of pixel "(ix0,iy0)". */ \ ix = ix0; \ iy = iy0; \ at = 2; \ \ /* Store a pointer to the first good pixel value. */ \ pa = array + ( ix - lbnd[ 0 ] ) + nx*( iy - lbnd[ 1 ] ) ; \ \ /* We count the number of times the polygon turns to the right compared \ to the left. Initialise it to zero. */ \ nright = 0; \ \ /* Loop round tracing out the polygon until we arrive back at the \ beginning. The Polygon class requires that the inside of the polygon \ is to the left as we move round the polygon in an anti-clockwise \ direction. So at each corner, we attempt to move to the next \ anti-clockwise good pixel corner. */ \ done = 0; \ while( !done ) { \ \ /* If we have arrived at the bottom left corner of the good pixel, we must \ have come from the top left corner since all movements around a pixel \ must be anti-clockwise. */ \ if( at == 0 ) { \ \ /* Note the pixel coordinates at the bottom left corner of the current \ pixel. */ \ if( starpix ) { \ xx = ix - 1.0; \ yy = iy - 1.0; \ } else { \ xx = ix - 0.5; \ yy = iy - 0.5; \ } \ \ /* Get a pointer to lower left pixel value */ \ pb = pa - nx - 1; \ \ /* Get a pointer to lower mid pixel value. */ \ pc = pb + 1; \ \ /* If the lower left pixel is within the array and meets the validity \ requirements, move to the left along its top edge. */ \ if( iy > lbnd[ 1 ] && ix > lbnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \ nright++; \ pa = pb; \ at = 1; \ ix--; \ iy--; \ \ /* Otherwise, if lower mid pixel is good, move down its left edge. */ \ } else if( iy > lbnd[ 1 ] && ISVALID(*pc,OperI,value) ) { \ pa = pc; \ at = 0; \ iy--; \ \ /* Otherwise, move to the right along the bottom edge of the current pixel. */ \ } else { \ nright--; \ at = 3; \ } \ \ /* If the polygon bends at this point, or if we will be smoothing the \ polygon, append the pixel coordinates at this pixel corner to the \ polygon. */ \ if( full || pa != pc ) ADD( xx, yy ); \ \ /* If we have arrived at the top left corner of the good pixel, we must \ have come from the top right corner. */ \ } else if( at == 1 ) { \ \ /* Note the pixel coordinates at the top left corner of the current \ pixel. */ \ if( starpix ) { \ xx = ix - 1.0; \ yy = iy; \ } else { \ xx = ix - 0.5; \ yy = iy + 0.5; \ } \ \ /* Get a pointer to upper left pixel value */ \ pb = pa + nx - 1; \ \ /* Get a pointer to mid left pixel value. */ \ pc = pa - 1; \ \ /* If upper left pixel is good, move up its left edge. */ \ if( iy < ubnd[ 1 ] && ix > lbnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \ nright++; \ pa = pb; \ at = 2; \ ix--; \ iy++; \ \ /* Otherwise, if left mid pixel is good, move left along its top edge. */ \ } else if( ix > lbnd[ 0 ] && ISVALID(*pc,OperI,value) ) { \ pa = pc; \ at = 1; \ ix--; \ \ /* Otherwise, move down the left edge of the current pixel. */ \ } else { \ nright--; \ at = 0; \ } \ \ /* If the polygon bends at this point, or if we will be smoothing the \ polygon, append the pixel coordinates at this pixel corner to the \ polygon. */ \ if( full || pa != pc ) ADD( xx, yy ); \ \ /* If we have arrived at the top right corner of the good pixel, we must \ have come from the bottom right corner. */ \ } else if( at == 2 ) { \ \ /* Note the pixel coordinates at the top right corner of the current \ pixel. */ \ if( starpix ) { \ xx = ix; \ yy = iy; \ } else { \ xx = ix + 0.5; \ yy = iy + 0.5; \ } \ \ /* Pointer to upper right pixel value */ \ pb = pa + nx + 1; \ \ /* Pointer to top mid pixel value. */ \ pc = pa + nx; \ \ /* If upper right pixel is good, move right along its bottom edge. */ \ if( iy < ubnd[ 1 ] && ix < ubnd[ 0 ] && ISVALID(*pb,OperI,value) ){ \ nright++; \ pa = pb; \ at = 3; \ ix++; \ iy++; \ \ /* Otherwise, if upper mid pixel is good, move up its right edge. */ \ } else if( iy < ubnd[ 1 ] && ISVALID(*pc,OperI,value) ) { \ pa = pc; \ at = 2; \ iy++; \ \ /* Otherwise, move left along the top edge of the current pixel. */ \ } else { \ nright--; \ at = 1; \ } \ \ /* If the polygon bends at this point, or if we will be smoothing the \ polygon, append the pixel coordinates at this pixel corner to the \ polygon. */ \ if( full || pa != pc ) ADD( xx, yy ); \ \ /* Arrived at bottom right corner of good pixel from lower left. */ \ } else { \ \ /* Note the pixel coordinates at the bottom right corner of the current \ pixel. */ \ if( starpix ) { \ xx = ix; \ yy = iy - 1.0; \ } else { \ xx = ix + 0.5; \ yy = iy - 0.5; \ } \ \ /* Pointer to lower right pixel value */ \ pb = pa - ( nx - 1 ); \ \ /* Pointer to mid right pixel value. */ \ pc = pa + 1; \ \ /* If lower right pixel is good, move down its left edge. */ \ if( iy > lbnd[ 1 ] && ix < ubnd[ 0 ] && ISVALID(*pb,OperI,value) ) { \ nright++; \ pa = pb; \ at = 0; \ ix++; \ iy--; \ \ /* Otherwise, if right mid pixel is good, move right along its lower edge. */ \ } else if( ix < ubnd[ 0 ] && ISVALID(*pc,OperI,value) ) { \ pa = pc; \ at = 3; \ ix++; \ \ /* Otherwise, move up the left edge of the current pixel. */ \ } else { \ nright--; \ at = 2; \ } \ \ /* If the polygon bends at this point, or if we will be smoothing the \ polygon, append the pixel coordinates at this pixel corner to the \ polygon. */ \ if( full || pa != pc ) ADD( xx, yy ); \ } \ \ /* If we have arrived back at the start, break out of the loop. */ \ if( ix == ix0 && iy == iy0 && at == 2 ) done = 1; \ } \ \ /* If we have circled round to the right, the polygon will not enclosed \ the specified position, so free resources and return a NULL pointer. */ \ if( nright > 0 ) { \ xvert = astFree( xvert ); \ yvert = astFree( yvert ); \ \ /* If we have circled round to the left, the polygon will enclose \ the specified position, so create and return a PointSet. */ \ } else { \ result = astPointSet( nvert, 2, " ", status ); \ ptr[ 0 ] = xvert; \ ptr[ 1 ] = yvert; \ astSetPoints( result, ptr ); \ } \ \ /* Annul the returned PointSet if anythign went wrong. */ \ if( !astOK && result ) result = astAnnul( result ); \ \ /* Return the PointSet pointer. */ \ return result; \ } /* Define a macro for testing if a pixel value satisfies the requirements specified by and . Compiler optimisation should remove all the "if" testing from this expression. */ #define ISVALID(V,OperI,Value) ( \ ( OperI == AST__LT ) ? ( (V) < Value ) : ( \ ( OperI == AST__LE ) ? ( (V) <= Value ) : ( \ ( OperI == AST__EQ ) ? ( (V) == Value ) : ( \ ( OperI == AST__GE ) ? ( (V) >= Value ) : ( \ ( OperI == AST__NE ) ? ( (V) != Value ) : ( \ (V) > Value \ ) \ ) \ ) \ ) \ ) \ ) /* Define a macro to add a vertex position to dynamically allocated arrays of X and Y positions. */ #define ADD(X,Y) {\ ii = nvert++; \ xvert = (double *) astGrow( xvert, nvert, sizeof( double ) ); \ yvert = (double *) astGrow( yvert, nvert, sizeof( double ) ); \ if( astOK ) { \ xvert[ ii ] = (X); \ yvert[ ii ] = (Y); \ } \ } /* Define a macro that uses the above macro to to create implementations of TraceEdge for all operations. */ #define MAKEALL_TRACEEDGE(X,Xtype) \ MAKE_TRACEEDGE(X,Xtype,LT,AST__LT) \ MAKE_TRACEEDGE(X,Xtype,LE,AST__LE) \ MAKE_TRACEEDGE(X,Xtype,EQ,AST__EQ) \ MAKE_TRACEEDGE(X,Xtype,NE,AST__NE) \ MAKE_TRACEEDGE(X,Xtype,GE,AST__GE) \ MAKE_TRACEEDGE(X,Xtype,GT,AST__GT) /* Expand the above macro to generate a function for each required data type and operation. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ MAKEALL_TRACEEDGE(LD,long double) #endif MAKEALL_TRACEEDGE(D,double) MAKEALL_TRACEEDGE(L,long int) MAKEALL_TRACEEDGE(UL,unsigned long int) MAKEALL_TRACEEDGE(I,int) MAKEALL_TRACEEDGE(UI,unsigned int) MAKEALL_TRACEEDGE(S,short int) MAKEALL_TRACEEDGE(US,unsigned short int) MAKEALL_TRACEEDGE(B,signed char) MAKEALL_TRACEEDGE(UB,unsigned char) MAKEALL_TRACEEDGE(F,float) /* Undefine the macros. */ #undef MAKE_TRACEEDGE #undef MAKEALL_TRACEEDGE #undef ISVALID static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a Polygon to transform a set of points. * Type: * Private function. * Synopsis: * #include "polygon.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * Polygon member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a Polygon and a set of points encapsulated in a * PointSet and transforms the points by setting axis values to * AST__BAD for all points which are outside the region. Points inside * the region are copied unchanged from input to output. * Parameters: * this * Pointer to the Polygon. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - The forward and inverse transformations are identical for a * Region. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of axes in the Frame represented by the Polygon. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstFrame *frm; /* Pointer to base Frame in FrameSet */ AstLineDef *a; /* Line from inside point to test point */ AstLineDef *b; /* Polygon edge */ AstPointSet *in_base; /* PointSet holding base Frame input positions*/ AstPointSet *result; /* Pointer to output PointSet */ AstPolygon *this; /* Pointer to Polygon */ double **ptr_in; /* Pointer to input base Frame coordinate data */ double **ptr_out; /* Pointer to output current Frame coordinate data */ double *px; /* Pointer to array of first axis values */ double *py; /* Pointer to array of second axis values */ double p[ 2 ]; /* Current test position */ int closed; /* Is the boundary part of the Region? */ int i; /* Edge index */ int icoord; /* Coordinate index */ int in_region; /* Is the point inside the Region? */ int ncoord_out; /* No. of current Frame axes */ int ncross; /* Number of crossings */ int neg; /* Has the Region been negated? */ int npoint; /* No. of input points */ int nv; /* No. of vertices */ int point; /* Loop counter for input points */ int pos; /* Is test position in, on, or outside boundary? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the Polygon structure. */ this = (AstPolygon *) this_mapping; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Region class. This function validates all arguments and generates an output PointSet if necessary, containing a copy of the input PointSet. */ result = (*parent_transform)( this_mapping, in, forward, out, status ); /* Get the number of points to be transformed. */ npoint = astGetNpoint( result ); /* Get a pointer to the output axis values. */ ptr_out = astGetPoints( result ); /* Find the number of axes in the current Frame. This need not be 2 (the number of axes in the *base* Frame must be 2 however). */ ncoord_out = astGetNcoord( result ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* First use the encapsulated FrameSet to transform the supplied positions from the current Frame in the encapsulated FrameSet (the Frame represented by the Region), to the base Frame (the Frame in which the Region is defined). This call also returns a pointer to the base Frame of the encapsulated FrameSet. Note, the returned pointer may be a clone of the "in" pointer, and so we must be carefull not to modify the contents of the returned PointSet. */ in_base = astRegTransform( this, in, 0, NULL, &frm ); ptr_in = astGetPoints( in_base ); /* Get the number of vertices in the polygon. */ nv = astGetNpoint( ((AstRegion *) this)->points ); /* See if the boundary is part of the Region. */ closed = astGetClosed( this ); /* See if the Region has been negated. */ neg = astGetNegated( this ); /* Perform coordinate arithmetic. */ /* ------------------------------ */ if ( astOK ) { px = ptr_in[ 0 ]; py = ptr_in[ 1 ]; /* Loop round each supplied point in the base Frame of the polygon. */ for ( point = 0; point < npoint; point++, px++, py++ ) { /* If the input point is bad, indicate that bad output values should be returned. */ if( *px == AST__BAD || *py == AST__BAD ) { in_region = 0; /* Otherwise, we first determine if the point is inside, outside, or on, the Polygon boundary. Initialially it is unknown. */ } else { /* Ensure cached information is available.*/ Cache( this, status ); /* Create a definition of the line from a point which is inside the polygon to the supplied point. This is a structure which includes cached intermediate information which can be used to speed up subsequent calculations. */ p[ 0 ] = *px; p[ 1 ] = *py; a = astLineDef( frm, this->in, p ); /* We now determine the number of times this line crosses the polygon boundary. Initialise the number of crossings to zero. */ ncross = 0; pos = UNKNOWN; /* Loop rouind all edges of the polygon. */ for( i = 0; i < nv; i++ ) { b = this->edges[ i ]; /* If this point is on the current edge, then we need do no more checks since we know it is either inside or outside the polygon (depending on whether the polygon is closed or not). */ if( astLineContains( frm, b, 0, p ) ) { pos = ON; break; /* Otherwise, see if the two lines cross within their extent. If so, increment the number of crossings. */ } else if( astLineCrossing( frm, b, a, NULL ) ) { ncross++; } } /* Free resources */ a = astFree( a ); /* If the position is not on the boundary, it is inside the boundary if the number of crossings is even, and outside otherwise. */ if( pos == UNKNOWN ) pos = ( ncross % 2 == 0 )? IN : OUT; /* Whether the point is in the Region depends on whether the point is inside the polygon boundary, whether the Polygon has been negated, and whether the polygon is closed. */ if( neg ) { if( pos == IN ) { in_region = 0; } else if( pos == OUT ) { in_region = 1; } else if( closed ) { in_region = 1; } else { in_region = 0; } } else { if( pos == IN ) { in_region = 1; } else if( pos == OUT ) { in_region = 0; } else if( closed ) { in_region = 1; } else { in_region = 0; } } } /* If the point is not inside the Region, store bad output values. */ if( !in_region ) { for ( icoord = 0; icoord < ncoord_out; icoord++ ) { ptr_out[ icoord ][ point ] = AST__BAD; } } } } /* Free resources */ in_base = astAnnul( in_base ); frm = astAnnul( frm ); /* Annul the result if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Polygon objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Polygon objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstPolygon *out; /* Pointer to output Polygon */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the output Polygon. */ out = (AstPolygon *) objout; /* For safety, first clear any references to the input memory from the output Polygon. */ out->edges = NULL; out->startsat = NULL; /* Indicate cached information needs nre-calculating. */ astResetCache( (AstPolygon *) out ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Polygon objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Polygon objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstPointSet *ps; /* Pointer to PointSet inside Region */ AstPolygon *this; /* Pointer to Polygon */ int i; /* Index of vertex */ int istat; /* Original AST error status */ int nv; /* Number of vertices */ int rep; /* Original error reporting state */ /* Obtain a pointer to the Polygon structure. */ this = (AstPolygon *) obj; /* Annul all resources. */ ps = ((AstRegion *) this)->points; if( this->edges && ps ) { /* Ensure we get a value for "nv" even if an error has occurred. */ istat = astStatus; astClearStatus; rep = astReporting( 0 ); nv = astGetNpoint( ps ); astSetStatus( istat ); astReporting( rep ); /* Free the structures holding the edge information. */ for( i = 0; i < nv; i++ ) { this->edges[ i ] = astFree( this->edges[ i ] ); } this->edges = astFree( this->edges ); this->startsat = astFree( this->startsat ); } } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Polygon objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Polygon class to an output Channel. * Parameters: * this * Pointer to the Polygon whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if ( !astOK ) return; /* Write out values representing the instance variables for the Polygon class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* A flag indicating the convention used for determining the interior of the polygon. A zero value indicates that the old AST system is in use (inside to the left when moving anti-clockwise round the vertices as viewed from the outside of the celestial sphere). A non-zero value indicates the STC system is in use (inside to the left when moving anti-clockwise round the vertices as viewed from the inside of the celestial sphere). AST currently uses the STC system. */ astWriteInt( channel, "Order", 1, 0, 1, "Polygon uses STC vertex order convention" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAPolygon and astCheckPolygon functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Polygon,Region) astMAKE_CHECK(Polygon) AstPolygon *astPolygon_( void *frame_void, int npnt, int dim, const double *points, AstRegion *unc, const char *options, int *status, ...) { /* *++ * Name: c astPolygon f AST_POLYGON * Purpose: * Create a Polygon. * Type: * Public function. * Synopsis: c #include "polygon.h" c AstPolygon *astPolygon( AstFrame *frame, int npnt, int dim, c const double *points, AstRegion *unc, c const char *options, ... ) f RESULT = AST_POLYGON( FRAME, NPNT, DIM, POINTS, UNC, OPTIONS, STATUS ) * Class Membership: * Polygon constructor. * Description: * This function creates a new Polygon object and optionally initialises * its attributes. * * The Polygon class implements a polygonal area, defined by a * collection of vertices, within a 2-dimensional Frame. The vertices * are connected together by geodesic curves within the encapsulated Frame. * For instance, if the encapsulated Frame is a simple Frame then the * geodesics will be straight lines, but if the Frame is a SkyFrame then * the geodesics will be great circles. Note, the vertices must be * supplied in an order such that the inside of the polygon is to the * left of the boundary as the vertices are traversed. Supplying them * in the reverse order will effectively negate the polygon. * * Within a SkyFrame, neighbouring vertices are always joined using the * shortest path. Thus if an edge of 180 degrees or more in length is * required, it should be split into section each of which is less * than 180 degrees. The closed path joining all the vertices in order * will divide the celestial sphere into two disjoint regions. The * inside of the polygon is the region which is circled in an * anti-clockwise manner (when viewed from the inside of the celestial * sphere) when moving through the list of vertices in the order in * which they were supplied when the Polygon was created (i.e. the * inside is to the left of the boundary when moving through the * vertices in the order supplied). * Parameters: c frame f FRAME = INTEGER (Given) * A pointer to the Frame in which the region is defined. It must * have exactly 2 axes. A deep copy is taken of the supplied Frame. * This means that any subsequent changes made to the Frame using the * supplied pointer will have no effect the Region. c npnt f NPNT = INTEGER (Given) * The number of points in the Region. c dim f DIM = INTEGER (Given) c The number of elements along the second dimension of the "points" f The number of elements along the first dimension of the POINTS * array (which contains the point coordinates). This value is * required so that the coordinate values can be correctly * located if they do not entirely fill this array. The value c given should not be less than "npnt". f given should not be less than NPNT. c points f POINTS( DIM, 2 ) = DOUBLE PRECISION (Given) c The address of the first element of a 2-dimensional array of c shape "[2][dim]" giving the physical coordinates of the vertices. c These should be stored such that the value of coordinate c number "coord" for point number "pnt" is found in element c "in[coord][pnt]". f A 2-dimensional array giving the physical coordinates of the f vertices. These should be stored such that the value of coordinate f number COORD for point number PNT is found in element IN(PNT,COORD). c unc f UNC = INTEGER (Given) * An optional pointer to an existing Region which specifies the * uncertainties associated with the boundary of the Box being created. * The uncertainty in any point on the boundary of the Box is found by * shifting the supplied "uncertainty" Region so that it is centred at * the boundary point being considered. The area covered by the * shifted uncertainty Region then represents the uncertainty in the * boundary position. The uncertainty is assumed to be the same for * all points. * * If supplied, the uncertainty Region must be of a class for which * all instances are centro-symetric (e.g. Box, Circle, Ellipse, etc.) * or be a Prism containing centro-symetric component Regions. A deep * copy of the supplied Region will be taken, so subsequent changes to * the uncertainty Region using the supplied pointer will have no * effect on the created Box. Alternatively, f a null Object pointer (AST__NULL) c a NULL Object pointer * may be supplied, in which case a default uncertainty is used * equivalent to a box 1.0E-6 of the size of the Box being created. * * The uncertainty Region has two uses: 1) when the c astOverlap f AST_OVERLAP * function compares two Regions for equality the uncertainty * Region is used to determine the tolerance on the comparison, and 2) * when a Region is mapped into a different coordinate system and * subsequently simplified (using c astSimplify), f AST_SIMPLIFY), * the uncertainties are used to determine if the transformed boundary * can be accurately represented by a specific shape of Region. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new Polygon. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new Polygon. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astPolygon() f AST_POLYGON = INTEGER * A pointer to the new Polygon. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstPolygon *new; /* Pointer to new Polygon */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate a pointer to the supplied Frame structure. */ frame = astCheckFrame( frame_void ); /* Initialise the Polygon, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPolygon( NULL, sizeof( AstPolygon ), !class_init, &class_vtab, "Polygon", frame, npnt, dim, points, unc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Polygon's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new Polygon. */ return new; } AstPolygon *astPolygonId_( void *frame_void, int npnt, int dim, const double *points, void *unc_void, const char *options, ... ) { /* * Name: * astPolygonId_ * Purpose: * Create a Polygon. * Type: * Private function. * Synopsis: * #include "polygon.h" * AstPolygon *astPolygonId_( void *frame_void, int npnt, * int dim, const double *points, void *unc_void, * const char *options, ... ) * Class Membership: * Polygon constructor. * Description: * This function implements the external (public) interface to the * astPolygon constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astPolygon_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astPolygon_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astPolygon_. * Returned Value: * The ID value associated with the new Polygon. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstPolygon *new; /* Pointer to new Polygon */ AstRegion *unc; /* Pointer to Region structure */ va_list args; /* Variable argument list */ int *status; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain a Frame pointer from the supplied ID and validate the pointer to ensure it identifies a valid Frame. */ frame = astVerifyFrame( astMakePointer( frame_void ) ); /* Obtain a Region pointer from the supplied "unc" ID and validate the pointer to ensure it identifies a valid Region . */ unc = unc_void ? astCheckRegion( astMakePointer( unc_void ) ) : NULL; /* Initialise the Polygon, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPolygon( NULL, sizeof( AstPolygon ), !class_init, &class_vtab, "Polygon", frame, npnt, dim, points, unc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Polygon's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new Polygon. */ return astMakeId( new ); } AstPolygon *astInitPolygon_( void *mem, size_t size, int init, AstPolygonVtab *vtab, const char *name, AstFrame *frame, int npnt, int dim, const double *points, AstRegion *unc, int *status ) { /* *+ * Name: * astInitPolygon * Purpose: * Initialise a Polygon. * Type: * Protected function. * Synopsis: * #include "polygon.h" * AstPolygon *astInitPolygon( void *mem, size_t size, int init, AstPolygonVtab *vtab, * const char *name, AstFrame *frame, int npnt, * int dim, const double *points, AstRegion *unc ) * Class Membership: * Polygon initialiser. * Description: * This function is provided for use by class implementations to initialise * a new Polygon object. It allocates memory (if necessary) to accommodate * the Polygon plus any additional data associated with the derived class. * It then initialises a Polygon structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a Polygon at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Polygon is to be initialised. * This must be of sufficient size to accommodate the Polygon data * (sizeof(Polygon)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the Polygon (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the Polygon * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the Polygon's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new Polygon. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * frame * A pointer to the Frame in which the region is defined. * npnt * The number of points in the Region. * dim * The number of elements along the second dimension of the "points" * array (which contains the point coordinates). This value is * required so that the coordinate values can be correctly * located if they do not entirely fill this array. The value * given should not be less than "npnt". * points * The address of the first element of a 2-dimensional array of * shape "[2][dim]" giving the physical coordinates of the * points. These should be stored such that the value of coordinate * number "coord" for point number "pnt" is found in element * "in[coord][pnt]". * unc * A pointer to a Region which specifies the uncertainty in the * supplied positions (all points in the new Polygon being * initialised are assumed to have the same uncertainty). A NULL * pointer can be supplied, in which case default uncertainties equal * to 1.0E-6 of the dimensions of the new Polygon's bounding box are * used. If an uncertainty Region is supplied, it must be either a Box, * a Circle or an Ellipse, and its encapsulated Frame must be related * to the Frame supplied for parameter "frame" (i.e. astConvert * should be able to find a Mapping between them). Two positions * the "frame" Frame are considered to be co-incident if their * uncertainty Regions overlap. The centre of the supplied * uncertainty Region is immaterial since it will be re-centred on the * point being tested before use. A deep copy is taken of the supplied * Region. * Returned Value: * A pointer to the new Polygon. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstPolygon *new; /* Pointer to new Polygon */ AstPointSet *pset; /* Pointer to PointSet holding points */ const double *q; /* Pointer to next supplied axis value */ double **ptr; /* Pointer to data in pset */ double *p; /* Pointer to next PointSet axis value */ int i; /* Axis index */ int j; /* Point index */ int nin; /* No. of axes */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitPolygonVtab( vtab, name ); /* Initialise. */ new = NULL; /* Check the number of axis values per position is correct. */ nin = astGetNaxes( frame ); if( nin != 2 ) { astError( AST__BADIN, "astInitPolygon(%s): The supplied %s has %d " "axes - polygons must have exactly 2 axes.", status, name, astGetClass( frame ), nin ); /* If so create a PointSet and store the supplied points in it. Check none are bad. */ } else { pset = astPointSet( npnt, 2, "", status ); ptr = astGetPoints( pset ); for( i = 0; i < 2 && astOK; i++ ) { p = ptr[ i ]; q = points + i*dim; for( j = 0; j < npnt; j++ ) { if( (*(p++) = *(q++)) == AST__BAD ) { astError( AST__BADIN, "astInitPolygon(%s): One or more " "bad axis values supplied for the vertex " "number %d.", status, name, j + 1 ); break; } } } /* Initialise a Region structure (the parent class) as the first component within the Polygon structure, allocating memory if necessary. */ new = (AstPolygon *) astInitRegion( mem, size, 0, (AstRegionVtab *) vtab, name, frame, pset, unc ); if ( astOK ) { /* Initialise the Polygon data. */ /* ------------------------------ */ new->lbnd[ 0 ] = AST__BAD; new->ubnd[ 0 ] = AST__BAD; new->lbnd[ 1 ] = AST__BAD; new->ubnd[ 1 ] = AST__BAD; new->edges = NULL; new->startsat = NULL; new->totlen = 0.0; new->acw = 1; new->stale = 1; /* Ensure the vertices are stored such that the unnegated Polygon represents the inside of the polygon. */ EnsureInside( new, status ); /* If an error occurred, clean up by deleting the new Polygon. */ if ( !astOK ) new = astDelete( new ); } /* Free resources. */ pset = astAnnul( pset ); } /* Return a pointer to the new Polygon. */ return new; } AstPolygon *astLoadPolygon_( void *mem, size_t size, AstPolygonVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadPolygon * Purpose: * Load a Polygon. * Type: * Protected function. * Synopsis: * #include "polygon.h" * AstPolygon *astLoadPolygon( void *mem, size_t size, AstPolygonVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * Polygon loader. * Description: * This function is provided to load a new Polygon using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Polygon structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a Polygon at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the Polygon is to be * loaded. This must be of sufficient size to accommodate the * Polygon data (sizeof(Polygon)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Polygon (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Polygon structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstPolygon) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Polygon. If this is NULL, a pointer * to the (static) virtual function table for the Polygon class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Polygon" is used instead. * Returned Value: * A pointer to the new Polygon. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPolygon *new; /* Pointer to the new Polygon */ int order; /* Is the new (STC) order convention used? */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Polygon. In this case the Polygon belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstPolygon ); vtab = &class_vtab; name = "Polygon"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitPolygonVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Polygon. */ new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Polygon" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* A flag indicating what order the vertices are stored in. See the Dump function. */ order = astReadInt( channel, "order", 0 ); /* Initialise other class properties. */ new->lbnd[ 0 ] = AST__BAD; new->ubnd[ 0 ] = AST__BAD; new->lbnd[ 1 ] = AST__BAD; new->ubnd[ 1 ] = AST__BAD; new->edges = NULL; new->startsat = NULL; new->totlen = 0.0; new->acw = 1; new->stale = 1; /* If the order in which the vertices were written used the old AST convention, negate the Polygon so that it is consistent with the current conevtion (based on STC). */ if( ! order ) astNegate( new ); /* Ensure the vertices are stored such that the unnegated Polygon represents the inside of the polygon. */ EnsureInside( new, status ); /* If an error occurred, clean up by deleting the new Polygon. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Polygon pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ AstPolygon *astDownsize_( AstPolygon *this, double maxerr, int maxvert, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Polygon,Downsize))( this, maxerr, maxvert, status ); } ./ast-7.3.3/fprism.c0000644000175000017500000000606712262533650012617 0ustar olesoles/* *+ * Name: * fprism.c * Purpose: * Define a FORTRAN 77 interface to the AST Prism class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Prism class. * Routines Defined: * AST_ISAPRISM * AST_PRISM * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 10-JAN-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "prism.h" /* C interface to the Prism class */ F77_LOGICAL_FUNCTION(ast_isaprism)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAPRISM", NULL, 0 ); astWatchSTATUS( RESULT = astIsAPrism( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_prism)( INTEGER(REG1), INTEGER(REG2), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(REG1) GENPTR_INTEGER(REG2) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_PRISM", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astPrism( astI2P( *REG1 ), astI2P( *REG2 ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/fmatrixmap.c0000644000175000017500000000660412262533650013464 0ustar olesoles/* *+ * Name: * fmatrixmap.c * Purpose: * Define a FORTRAN 77 interface to the AST MatrixMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the MatrixMap class. * Routines Defined: * AST_ISAMATRIXMAP * AST_MATRIXMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 14-NOV-1996 (DSB): * Original version. * 3-JUN-1997 (DSB): * AST_MTRROT and AST_MTRMULT removed. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "matrixmap.h" /* C interface to the MatrixMap class */ F77_LOGICAL_FUNCTION(ast_isamatrixmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAMATRIXMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAMatrixMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_matrixmap)( INTEGER(NIN), INTEGER(NOUT), INTEGER(FORM), DOUBLE_ARRAY(MATRIX), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NIN) GENPTR_INTEGER(NOUT) GENPTR_INTEGER(FORM) GENPTR_DOUBLE_ARRAY(MATRIX) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_MATRIXMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astMatrixMap( *NIN, *NOUT, *FORM, MATRIX, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/ast_link_adam0000644000175000017500000004045212262533707013663 0ustar olesoles # N.B. the previous line should be blank. #++ # Name: # ast_link_adam # Purpose: # Link an ADAM program with the AST library. # Type of Module: # Shell script. # Description: # This command should only be used when building Starlink ADAM programs # which use the AST library, in order to generate the correct arguments # to allow the ADAM ``alink'' command to link the program. The arguments # generated are written to standard output but may be substituted into # the ``alink'' command line in the standard UNIX way using backward # quotes (see below). # # By default, it is assumed that you are building an ADAM program which # does not produce graphical output. However, switches are provided for # linking other types of program. This command should not be used when # building stand-alone (non-ADAM) programs. Use the ``ast_link'' command # instead. # Invocation: #c alink program.o -L/star/lib `ast_link_adam [switches]` #f alink program.f -L/star/lib `ast_link_adam [switches]` # Switches: # The following switches may optionally be given to this command to # modify its behaviour: # # - ``-csla'': Ignored. Provided for backward compatibility only. # # - ``-fsla'': Ignored. Provided for backward compatibility only. # # - ``-grf'': Requests that no arguments be generated to specify which # 2D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new graphics system yourself and wish to provide your own arguments for # linking with it. This switch differs from the other ``grf'' switches in # that it assumes that your graphics module implements the complete # interface required by the current version of AST. If future versions of # AST introduce new functions to the graphics interface, this switch will # cause ``unresolved symbol'' errors to occur during linking, warning you # that you need to implement new functions in your graphics module. To # avoid such errors, you can use one of the other, version-specific, # switches in place of the ``-grf'' switch, but these will cause run-time # errors to be reported if any AST function is invoked which requires # facilities not in the implemented interface. # # - ``-grf_v2.0'': This switch is equivalent to the ``-mygrf'' switch. # It indicates that you want to link with your own graphics module which # implements the 2D graphics interface required by V2.0 of AST. # # - ``-grf_v3.2'': Indicates that you want to link with your own graphics # module which implements the 2D graphics interface required by V3.2 of AST. # # - ``-grf_v5.6'': Indicates that you want to link with your own graphics # module which implements the 2D graphics interface required by V5.6 of AST. # # - ``-myerr'': Requests that no arguments be generated to specify how # error messages produced by the AST library should be delivered. You # should use this option only if you have implemented an interface to a # new error delivery system yourself and wish to provide your own # arguments for linking with it. By default, error messages are delivered # in the standard ADAM way via the EMS Error Message Service (Starlink # System Note SSN/4). # # - ``-mygrf'': This switch has been superceeded by the ``-grf'' switch, # but is retained in order to allow applications to be linked with a # graphics module which implements the interface used by AST V2.0. It is # equivalent to the ``-grf_v2.0'' switch. # # - ``-pgp'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via the # standard (or ``native'') version of the PGPLOT graphics # package. By default, no graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # # - ``-grf3d'': Requests that no arguments be generated to specify which # 3D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new 3D graphics system yourself and wish to provide your own arguments # for linking with it. # # - ``-pgp3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no 3D graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via # the standard (or ``native'') version of the PGPLOT graphics # package. By default, no 3D graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # SLALIB: # The AST distribution includes a cut down subset of the C version of # the SLALIB library written by Pat Wallace. This subset contains only # the functions needed by the AST library. It is built as part of the # process of building AST and is distributed under GPL (and is thus # compatible with the AST license). Previous version of this script # allowed AST applications to be linked against external SLALIB # libraries (either Fortran or C) rather than the internal version. # The current version of this script does not provide this option, # and always uses the internal SLALIB library. However, for backward # compatibility, this script still allows the "-fsla" and "-csla" flags # (previously used for selecting which version of SLALIB to use) to be # specified, but they will be ignored. # Examples: #c alink display.o -L/star/lib `ast_link_adam -pgplot` #c Links an ADAM program ``display'' which uses the standard #c version of PGPLOT for graphical output. #c alink plotit.o -L. -L/star/lib `ast_link_adam -grf` -lgrf #c Links an ADAM program ``plotit'', written in C. The ``-grf'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by the current version of AST. #c Here, this interface is supplied by means of the ``-lgrf'' library #c reference. #c alink plotit.o -L. -L/star/lib `ast_link_adam -grf_v2.0` -lgrf #c Links an ADAM program ``plotit'', written in C. The ``-grf_v2.0'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by version 2.0 of AST. Here, #c this interface is supplied by means of the ``-lgrf'' library #c reference. #f alink display.f -L/star/lib `ast_link_adam -pgplot` #f Compiles and links an ADAM Fortran program called ``display'' which #f uses the standard version of PGPLOT for graphical output. #f alink plotit.f -L. -L/star/lib `ast_link_adam -grf` -lgrf #f Compiles and links an ADAM Fortran program ``plotit''. The ``-grf'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by the current version of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. #f alink plotit.f -L. -L/star/lib `ast_link_adam -grf_v2.0` -lgrf #f Compiles and links an ADAM Fortran program ``plotit''. The ``-grf_v2.0'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by version 2.0 of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. # Copyright: # Copyright (C) 1997-2006 Council for the Central Laboratory of the Research Councils # Authors: # RFWS: R.F. Warren-Smith (STARLINK) # {enter_new_authors_here} # History: # 11-NOV-1996 (RFWS): # Original version. # 18-NOV-1997 (RFWS): # Adapted prologue for document extraction. # 28-SEP-1998 (RFWS): # Distinguish between -pgp and -pgplot options. # 23-JAN-2004 (DSB): # Added switches to support older grf implementations. # 21-APR-2005 (DSB): # Added "-fsla" option. # 16-JUN-2006 (DSB): # Ignore "-fsla" and "-clsa" options, and always use PAL. # 22-AUG-2007 (DSB): # Added "-grf3d", "-pgplot3d" and "-pgp3d" flags. # 4-MAR-2011 (DSB): # Added v5.6 grf options. # {enter_changes_here} # Bugs: # {note_any_bugs_here} #-- # This function searches the directory path specified in PATH, looking for # an executable file which is not a directory. If found, it echos the full # file name to standard output. Otherwise, it outputs nothing. find() { IFS=':'; for d in $PATH; do f="${d:=.}/${1}" test -x "${f}" -a ! -d "${f}" && echo "${f}" && break done; } # Initialise linking options. err='' grf='' grf3d='' sla='' # Interpret command line switches. # -------------------------------- while :; do case "${1}" in # -csla - Previously used to request C version of SLALIB. Now ignored. -csla) # sla='c' shift;; # -fsla - Previously used to request Fortran version of SLALIB. Now ignored. -fsla) # sla='f' shift;; # -myerr - Requests no error reporting. -myerr) err='my' shift;; # -grf - Requests no 2D graphics. -grf) grf='current' shift;; # -mygrf - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -mygrf) grf='v2.0' shift;; # -grf_v2.0 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -grf_v2.0) grf='v2.0' shift;; # -grf_v3.2 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V3.2. -grf_v3.2) grf='v3.2' shift;; # -grf_v5.6 - Requests no 2D graphics, except for null implementations of # functions added to the grf interface after AST V5.6. -grf_v5.6) grf='v5.6' shift;; # -pgp - Requests 2D graphical output through Starlink PGPLOT. -pgp) grf='pgp' shift;; # -pgplot - Requests 2D graphical output through native PGPLOT. -pgplot) grf='pgplot' shift;; # -grf3d - Requests no 3D graphics. -grf3d) grf3d='current' shift;; # -pgp3d - Requests 3D graphical output through Starlink PGPLOT. -pgp3d) grf3d='pgp' shift;; # -pgplot3d - Requests 3D graphical output through native PGPLOT. -pgplot3d) grf3d='pgplot' shift;; # Once all switches have been read, continue with the rest of the script. '') break;; # Catch unrecognised switches and report an error. *) echo >&2 "ast_link_adam: unknown argument \""${1}"\" given" exit 1;; esac done # Link with the main AST library. # ------------------------------- # Start forming the list of arguments with the main AST library itself. args='-last' # Generate arguments for linking PAL. # ----------------------------------- case "0" in # If we configured --with-external_pal include a link option to pick up # an external PAL library. 1) args="${args} -lpal";; # Otherwise, use the internal PAL & SOFA libraries. *) args="${args} -last_pal";; esac # Generate arguments for linking the 2D graphics system. # ------------------------------------------------------ case "${grf}" in # If using Starlink PGPLOT, link with the AST PGPLOT interface and # the Fortran library via the PGP link script. pgp) args="${args} -last_pgplot `pgp_link_adam`";; # If using native PGPLOT, link with the AST PGPLOT interface and # the Fortran library via the PGPLOT link script. pgplot) args="${args} -last_pgplot `pgplot_link_adam`";; # If using own graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # If using own graphics which conform to the requirements of version 5.6 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 5.6. v5.6) :;; # If using own graphics which conform to the requirements of version 3.2 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 3.2. v3.2) args="${args} -last_grf_5.6";; # If using own graphics which conform to the requirements of version 2.0 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 2.0. v2.0) args="${args} -last_grf_3.2 -last_grf_5.6";; # Default graphics (none) requires linking with all the default (null) AST # "grf" modules. *) args="${args} -last_grf_2.0 -last_grf_3.2 -last_grf_5.6";; esac # Generate arguments for linking the 3D graphics system. # ------------------------------------------------------ case "${grf3d}" in # If using Starlink PGPLOT, link with the AST 3D PGPLOT interface and # the Fortran library via the PGP link script (if found). pgp) args="${args} -last_pgplot3d `\`find pgp_link\``" f77='y';; # If using native PGPLOT, link with the AST 3D PGPLOT interface and the # Fortran library via the PGPLOT link script (if found). pgplot) args="${args} -last_pgplot3d `\`find pgplot_link\``" f77='y';; # If using own 3D graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # Default graphics (none) requires linking with all the default (null) AST # "grf3d" modules. *) args="${args} -last_grf3d";; esac # Make a second pass through the AST library. # ------------------------------------------- # This library is a link to the main AST library and results in a second # pass to resolve any backward references generated by the other modules # used above. A different library name must be used to avoid the two passes # being merged into one (either below, or by other link scripts). args="${args} -last_pass2" # Generate arguments for linking the error reporting system. # ---------------------------------------------------------- case "${err}" in # If using own error reporting, do not produce any arguments. my) :;; # Default error reporting requires linking with the AST EMS interface and # the EMS library via the link script. *) args="${args} -last_ems `ems_link_adam`";; esac # Link with the maths library. # ---------------------------- args="${args} -lm" # Link with the starmem library, if available. # -------------------------------------------- args="${args} `\`find starmem_link\``" # Pass the resulting argument list through an awk script which eliminates # all except the last reference to each library. echo "${args}" \ | awk 'BEGIN{RS=" ";FS="\n"} {if($1)f[i++]=$1} END{for(;i--;)if(!w[f[i]]++)l=f[i]" "l;print l}' # End of script. ./ast-7.3.3/err_drama.c0000644000175000017500000000715612262533650013253 0ustar olesoles/* * Name: * err_ems.c * Purpose: * Implement the "err" module for the DRAMA ERS error system. * Description: * This file implements an alternative "err" module for the AST * library. It is used to deliver error messages through the * DRAMA ERS error message system rather than by the default mechanism. * Copyright: * Copyright (C) 2008 Science and Technology Facilities Council. * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (UCLan) * TIMJ: Tim Jenness (JAC, Hawaii) * RFWS: R.F. Warren-Smith (STARLINK) * {enter_new_authors_here} * History: * 6-NOV-1996 (DSB): * Original version. * 16-SEP-2008 (TIMJ): * Use modern EMS interface * 13-NOV-2008 (TIMJ): * Modify for DRAMA * {enter_changes_here} */ #if HAVE_CONFIG_H #include #endif /* Module Macros. */ /* ============== */ /* Define the astCLASS macro (even although this is not a class implementation). This indicates to header files that they should make "protected" symbols available. */ #define astCLASS /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "err.h" /* Interface to this module */ /* Need to define these for DRAMA. Otherwise we have to include drama.h in the distribution as well */ #if HAVE_STDARG_H # define DSTDARG_OK #endif #define ERS_STANDALONE #include "Ers.h" /* Interface to the Ers system */ /* Function implementations. */ /* ========================= */ void astPutErr_( int status, const char *message ) { /* *+ * Name: * astPutErr * Purpose: * Deliver an error message. * Type: * Protected function. * Synopsis: * #include "err.h" * void astPutErr( int status, const char *message ) * Description: * This function delivers an error message and (optionally) an * accompanying status value to the user. It may be re-implemented * in order to deliver error messages in different ways, according * to the environment in which the AST library is being used. * Parameters: * status * The error status value. * message * A pointer to a null-terminated character string containing * the error message to be delivered. This should not contain * newline characters. * Notes: * - This function is documented as "protected" but, in fact, is * publicly accessible so that it may be re-implemented as * required. *- */ /* Local Variables: */ StatusType local_status; /* Local status value */ /* Make a copy of the status value supplied. Then invoke ems_rep_c to report the error message through EMS and to associate the error status with it. Ignore any returned status value. */ local_status = status; ErsRep( 0, &local_status, "%s", message ); } ./ast-7.3.3/ast_err.h0000644000175000017500000003647112262533710012762 0ustar olesoles/* * C error define file for facility AST (1521) * Generated by the MESSGEN utility */ #ifndef AST_ERROR_DEFINED #define AST_ERROR_DEFINED /* attribute getting error */ enum { AST__ATGER = 233933154 }; /* messid=300 */ /* attribute setting error */ enum { AST__ATSER = 233933162 }; /* messid=301 */ /* attribute value invalid */ enum { AST__ATTIN = 233933170 }; /* messid=302 */ /* axis index invalid */ enum { AST__AXIIN = 233933178 }; /* messid=303 */ /* bad attribute name */ enum { AST__BADAT = 233933186 }; /* messid=304 */ /* zero-sized box given */ enum { AST__BADBX = 233933194 }; /* messid=305 */ /* bad input data */ enum { AST__BADIN = 233933202 }; /* messid=306 */ /* bad number of input coordinates */ enum { AST__BADNI = 233933210 }; /* messid=307 */ /* bad number of output coordinates */ enum { AST__BADNO = 233933218 }; /* messid=308 */ /* PolyMap contains illegal power value */ enum { AST__BADPW = 233933226 }; /* messid=309 */ /* ShiftMap contains no shift information */ enum { AST__BADSM = 233933234 }; /* messid=310 */ /* WinMap contains no bounds information */ enum { AST__BADWM = 233933242 }; /* messid=311 */ /* bad break index */ enum { AST__BDBRK = 233933250 }; /* messid=312 */ /* bad field specifier */ enum { AST__BDFMT = 233933258 }; /* messid=313 */ /* invalid FITS keyword value found */ enum { AST__BDFTS = 233933266 }; /* messid=314 */ /* inappropriate Object supplied */ enum { AST__BDOBJ = 233933274 }; /* messid=315 */ /* wrong number of clipping axes */ enum { AST__CLPAX = 233933282 }; /* messid=316 */ /* range of coordinates invalid */ enum { AST__CORNG = 233933290 }; /* messid=317 */ /* too many breaks in a curve */ enum { AST__CVBRK = 233933298 }; /* messid=318 */ /* array dimensions invalid */ enum { AST__DIMIN = 233933306 }; /* messid=319 */ /* date/time error */ enum { AST__DTERR = 233933314 }; /* messid=320 */ /* invalid use of astEnd */ enum { AST__ENDIN = 233933322 }; /* messid=321 */ /* end of input Channel encountered */ enum { AST__EOCHN = 233933330 }; /* messid=322 */ /* attempt to export Object pointer from level zero */ enum { AST__EXPIN = 233933338 }; /* messid=323 */ /* corrupted FitsChan supplied */ enum { AST__FCRPT = 233933346 }; /* messid=324 */ /* error while formatting coordinate value */ enum { AST__FMTER = 233933354 }; /* messid=325 */ /* Frame index invalid */ enum { AST__FRMIN = 233933362 }; /* messid=326 */ /* FrameSet invalid */ enum { AST__FRSIN = 233933370 }; /* messid=327 */ /* cannot convert FITS data value type */ enum { AST__FTCNV = 233933378 }; /* messid=328 */ /* low level graphics error */ enum { AST__GRFER = 233933386 }; /* messid=329 */ /* invalid Handle */ enum { AST__INHAN = 233933394 }; /* messid=330 */ /* incompatible numbers of coordinates */ enum { AST__INNCO = 233933402 }; /* messid=331 */ /* internal programming error */ enum { AST__INTER = 233933410 }; /* messid=332 */ /* incompatible transformation directions */ enum { AST__INTRD = 233933418 }; /* messid=333 */ /* circular dependency between KeyMaps */ enum { AST__KYCIR = 233933426 }; /* messid=334 */ /* class loader error */ enum { AST__LDERR = 233933434 }; /* messid=335 */ /* invalid lookup table increment */ enum { AST__LUTII = 233933442 }; /* messid=336 */ /* invalid number of lookup table elements */ enum { AST__LUTIN = 233933450 }; /* messid=337 */ /* requested memory size invalid */ enum { AST__MEMIN = 233933458 }; /* messid=338 */ /* not a 2d or 3d MatrixMap */ enum { AST__MTR23 = 233933466 }; /* messid=339 */ /* null rotation axis supplied */ enum { AST__MTRAX = 233933474 }; /* messid=340 */ /* bad matrix shapes for multiplication */ enum { AST__MTRML = 233933482 }; /* messid=341 */ /* null matrix supplied */ enum { AST__MTRMT = 233933490 }; /* messid=342 */ /* number of axes invalid */ enum { AST__NAXIN = 233933498 }; /* messid=343 */ /* number of characters invalid */ enum { AST__NCHIN = 233933506 }; /* messid=344 */ /* number of coordinates invalid */ enum { AST__NCOIN = 233933514 }; /* messid=345 */ /* number of coordinates per point invalid */ enum { AST__NCPIN = 233933522 }; /* messid=346 */ /* number of array elements invalid */ enum { AST__NELIN = 233933530 }; /* messid=347 */ /* number of output coordinates too small */ enum { AST__NOCTS = 233933538 }; /* messid=348 */ /* transformation not defined */ enum { AST__NODEF = 233933546 }; /* messid=349 */ /* required FITS keywords missing */ enum { AST__NOFTS = 233933554 }; /* messid=350 */ /* unable to allocate memory */ enum { AST__NOMEM = 233933562 }; /* messid=351 */ /* number of output points too small */ enum { AST__NOPTS = 233933570 }; /* messid=352 */ /* attribute is read-only */ enum { AST__NOWRT = 233933578 }; /* messid=353 */ /* number of points invalid */ enum { AST__NPTIN = 233933586 }; /* messid=354 */ /* Object invalid */ enum { AST__OBJIN = 233933594 }; /* messid=355 */ /* invalid Plot option */ enum { AST__OPT = 233933602 }; /* messid=356 */ /* points data structure invalid */ enum { AST__PDSIN = 233933610 }; /* messid=357 */ /* no numerical labels can be produced */ enum { AST__PLFMT = 233933618 }; /* messid=358 */ /* permutation invalid */ enum { AST__PRMIN = 233933626 }; /* messid=359 */ /* pointer invalid */ enum { AST__PTRIN = 233933634 }; /* messid=360 */ /* range of points invalid */ enum { AST__PTRNG = 233933642 }; /* messid=361 */ /* read error */ enum { AST__RDERR = 233933650 }; /* messid=362 */ /* invalid or corrupted Region structure supplied */ enum { AST__REGIN = 233933658 }; /* messid=363 */ /* invalid attempt to remove last Frame */ enum { AST__REMIN = 233933666 }; /* messid=364 */ /* sky coordinate system invalid */ enum { AST__SCSIN = 233933674 }; /* messid=365 */ /* axis selection invalid */ enum { AST__SELIN = 233933682 }; /* messid=366 */ /* bad SLALIB transformation type */ enum { AST__SLAIN = 233933690 }; /* messid=367 */ /* coordinate transformation not defined */ enum { AST__TRNND = 233933698 }; /* messid=368 */ /* unmatched quotes */ enum { AST__UNMQT = 233933706 }; /* messid=369 */ /* valid area too small */ enum { AST__VSMAL = 233933714 }; /* messid=370 */ /* non-existent longitude or latitude axis */ enum { AST__WCSAX = 233933722 }; /* messid=371 */ /* too few mapping coordinates */ enum { AST__WCSNC = 233933730 }; /* messid=372 */ /* invalid projection parameters */ enum { AST__WCSPA = 233933738 }; /* messid=373 */ /* unknown projection type */ enum { AST__WCSTY = 233933746 }; /* messid=374 */ /* too many Objects in use at once */ enum { AST__XSOBJ = 233933754 }; /* messid=375 */ /* zoom factor invalid */ enum { AST__ZOOMI = 233933762 }; /* messid=376 */ /* bad coordinate index */ enum { AST__BADCI = 233933770 }; /* messid=377 */ /* FrameSet integrity lost */ enum { AST__ILOST = 233933778 }; /* messid=378 */ /* error in IntraMap transformation function */ enum { AST__ITFER = 233933786 }; /* messid=379 */ /* IntraMap transformation function name invalid */ enum { AST__ITFNI = 233933794 }; /* messid=380 */ /* Mapping bounding box not found */ enum { AST__MBBNF = 233933802 }; /* messid=381 */ /* multiple registration of IntraMap transformation function */ enum { AST__MRITF = 233933810 }; /* messid=382 */ /* Object class unknown */ enum { AST__OCLUK = 233933818 }; /* messid=383 */ /* error while unformatting a coordinate value */ enum { AST__UNFER = 233933826 }; /* messid=384 */ /* unregistered IntraMap transformation function */ enum { AST__URITF = 233933834 }; /* messid=385 */ /* grid bounds invalid */ enum { AST__GBDIN = 233933842 }; /* messid=386 */ /* number of grid dimensions invalid */ enum { AST__NGDIN = 233933850 }; /* messid=387 */ /* positional accuracy tolerance invalid */ enum { AST__PATIN = 233933858 }; /* messid=388 */ /* sub-pixel interpolation scheme invalid */ enum { AST__SISIN = 233933866 }; /* messid=389 */ /* scale size in pixels invalid */ enum { AST__SSPIN = 233933874 }; /* messid=390 */ /* error in user-supplied sub-pixel interpolation function */ enum { AST__UINER = 233933882 }; /* messid=391 */ /* error in user-supplied 1-d sub-pixel interpolation kernel */ enum { AST__UK1ER = 233933890 }; /* messid=392 */ /* invalid comma in expression */ enum { AST__COMIN = 233933898 }; /* messid=393 */ /* invalid constant in expression */ enum { AST__CONIN = 233933906 }; /* messid=394 */ /* duplicate variable name */ enum { AST__DUVAR = 233933914 }; /* messid=395 */ /* invalid number of transformation functions */ enum { AST__INNTF = 233933922 }; /* messid=396 */ /* missing or invalid operand in expression */ enum { AST__MIOPA = 233933930 }; /* messid=397 */ /* missing or invalid operator in expression */ enum { AST__MIOPR = 233933938 }; /* messid=398 */ /* missing variable name */ enum { AST__MISVN = 233933946 }; /* messid=399 */ /* missing left parenthesis in expression */ enum { AST__MLPAR = 233933954 }; /* messid=400 */ /* missing right parenthesis in expression */ enum { AST__MRPAR = 233933962 }; /* messid=401 */ /* missing right hand side in function */ enum { AST__NORHS = 233933970 }; /* messid=402 */ /* undefined variable or function in expression */ enum { AST__UDVOF = 233933978 }; /* messid=403 */ /* variable name invalid */ enum { AST__VARIN = 233933986 }; /* messid=404 */ /* wrong number of function arguments in expression */ enum { AST__WRNFA = 233933994 }; /* messid=405 */ /* invalid units specification */ enum { AST__BADUN = 233934002 }; /* messid=406 */ /* no rest frequency is defined */ enum { AST__NORSF = 233934010 }; /* messid=407 */ /* no standard of rest is defined */ enum { AST__NOSOR = 233934018 }; /* messid=408 */ /* invalid SpecMap */ enum { AST__SPCIN = 233934026 }; /* messid=409 */ /* invalid XML name or prefix */ enum { AST__XMLNM = 233934034 }; /* messid=410 */ /* invalid XML comment text */ enum { AST__XMLCM = 233934042 }; /* messid=411 */ /* invalid XML processing instruction target text */ enum { AST__XMLPT = 233934050 }; /* messid=412 */ /* invalid XML content item index */ enum { AST__XMLIT = 233934058 }; /* messid=413 */ /* supplied XML document is not well formed */ enum { AST__XMLWF = 233934066 }; /* messid=414 */ /* Range of log axis scale includes zero */ enum { AST__ZERAX = 233934074 }; /* messid=415 */ /* Invalid parameters for offset sky coordinate system */ enum { AST__BADOC = 233934082 }; /* messid=416 */ /* error getting a named value from a KeyMap */ enum { AST__MPGER = 233934090 }; /* messid=417 */ /* invalid integer index supplied for a KeyMap entry */ enum { AST__MPIND = 233934098 }; /* messid=418 */ /* region cannot be re-centred */ enum { AST__REGCN = 233934106 }; /* messid=419 */ /* attribute has no usable value */ enum { AST__NOVAL = 233934114 }; /* messid=420 */ /* incompatible time scales */ enum { AST__INCTS = 233934122 }; /* messid=421 */ /* invalid TimeMap */ enum { AST__TIMIN = 233934130 }; /* messid=422 */ /* cannot use supplied AstroCoords info */ enum { AST__STCKEY = 233934138 }; /* messid=423 */ /* invalid AstroCoords index */ enum { AST__STCIND = 233934146 }; /* messid=424 */ /* cannot conserve flux whilst resampling an array of data */ enum { AST__CNFLX = 233934154 }; /* messid=425 */ /* Unknown AST tuning parameter name supplied */ enum { AST__TUNAM = 233934162 }; /* messid=426 */ /* Bad value supplied for a public function parameter */ enum { AST__BDPAR = 233934170 }; /* messid=427 */ /* Supplied FrameSet does not contain any independent axes */ enum { AST__3DFSET = 233934178 }; /* messid=428 */ /* Attempt to delete original Plot3D base Frame */ enum { AST__PXFRRM = 233934186 }; /* messid=429 */ /* Illegal syntax for string substitution template */ enum { AST__BADSUB = 233934194 }; /* messid=430 */ /* Incompatible flags for re-sampling or re-binning */ enum { AST__BADFLG = 233934202 }; /* messid=431 */ /* Error locking or unlocking an AST Object */ enum { AST__LCKERR = 233934210 }; /* messid=432 */ /* FITS keyword had undefined value */ enum { AST__FUNDEF = 233934218 }; /* messid=433 */ /* invalid integer index supplied for a KeyMap vector element */ enum { AST__MPVIN = 233934226 }; /* messid=434 */ /* operation specifier invalid */ enum { AST__OPRIN = 233934234 }; /* messid=435 */ /* no inside point found */ enum { AST__NONIN = 233934242 }; /* messid=436 */ /* requested key not found in KeyMap */ enum { AST__MPKER = 233934250 }; /* messid=437 */ /* error putting a named value into a KeyMap */ enum { AST__MPPER = 233934258 }; /* messid=438 */ /* Attempt made to add an entry to a locked KeyMap */ enum { AST__BADKEY = 233934266 }; /* messid=439 */ /* Bad data type */ enum { AST__BADTYP = 233934274 }; /* messid=440 */ /* Column already exists with different properties */ enum { AST__OLDCOL = 233934282 }; /* messid=441 */ /* Bad null value for a FITS table column */ enum { AST__BADNULL = 233934290 }; /* messid=442 */ /* Key string is too long */ enum { AST__BIGKEY = 233934298 }; /* messid=443 */ /* No such column exists in the table */ enum { AST__BADCOL = 233934306 }; /* messid=444 */ /* Table is too large */ enum { AST__BIGTAB = 233934314 }; /* messid=445 */ /* Invalid array size */ enum { AST__BADSIZ = 233934322 }; /* messid=446 */ /* Error reading WCS from FITS binary table */ enum { AST__BADTAB = 233934330 }; /* messid=447 */ /* Cannot access FITS binary table */ enum { AST__NOTAB = 233934338 }; /* messid=448 */ /* Error in levmar Levenberg-Marquardt code */ enum { AST__LEVMAR = 233934346 }; /* messid=449 */ /* Fit failed */ enum { AST__NOFIT = 233934354 }; /* messid=450 */ /* A transformation generated one or more NaN values */ enum { AST__ISNAN = 233934362 }; /* messid=451 */ /* write error */ enum { AST__WRERR = 233934370 }; /* messid=452 */ /* Bad variant Mapping name */ enum { AST__BDVNM = 233934378 }; /* messid=453 */ /* Attempt to add a variant Mapping to a mirror Frame */ enum { AST__MIRRO = 233934386 }; /* messid=454 */ #endif /* AST_ERROR_DEFINED */ ./ast-7.3.3/fxmlchan.c0000644000175000017500000001001212262533650013100 0ustar olesoles/* *+ * Name: * fxmlchan.c * Purpose: * Define a FORTRAN 77 interface to the AST XmlChan class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the XmlChan class. * Routines Defined: * AST_XMLCHAN * AST_ISAXMLCHAN * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 21-OCT-2003 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "channel.h" /* Provides wrapper functions */ #include "xmlchan.h" /* C interface to the XmlChan class */ #include /* Prototypes for external functions. */ /* ================================== */ /* This is the null function defined by the FORTRAN interface in fobject.c. */ F77_SUBROUTINE(ast_null)( void ); /* FORTRAN interface functions. */ /* ============================ */ /* These functions implement the remainder of the FORTRAN interface. */ F77_INTEGER_FUNCTION(ast_xmlchan)( void (* SOURCE)(), void (* SINK)(), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; const char *(* source)( void ); int i; void (* sink)( const char * ); astAt( "AST_XMLCHAN", NULL, 0 ); astWatchSTATUS( /* Set the source and sink function pointers to NULL if a pointer to the null routine AST_NULL has been supplied. */ source = (const char *(*)( void )) SOURCE; if ( source == (const char *(*)( void )) F77_EXTERNAL_NAME(ast_null) ) { source = NULL; } sink = (void (*)( const char * )) SINK; if ( sink == (void (*)( const char * )) F77_EXTERNAL_NAME(ast_null) ) { sink = NULL; } options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astXmlChanFor( source, astSourceWrap, sink, astSinkWrap, "%s", options ) ); astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isaxmlchan)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAXMLCHAN", NULL, 0 ); astWatchSTATUS( RESULT = astIsAXmlChan( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } ./ast-7.3.3/ffitschan.c0000644000175000017500000007603012262533650013261 0ustar olesoles/* *+ * Name: * ffitschan.c * Purpose: * Define a FORTRAN 77 interface to the AST FitsChan class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the FitsChan class. * Routines Defined: * AST_DELFITS * AST_PURGEWCS * AST_FINDFITS * AST_FITSCHAN * AST_ISAFITSCHAN * AST_PUTCARDS * AST_PUTFITS * AST_RETAINFITS * AST_SETFITS * AST_GETFITS * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 11-DEC-1996 (DSB): * Original version. * 21-FEB-1997 (DSB): * Added source and sink functions to AST_FITSCHAN. * 20-MAR-1997 (DSB): * Functions for accessing named keywords removed. Others renamed. * 28-APR-1997 (DSB): * FindFits and GetFits merged. * 10-SEP-2004 (TIMJ): * Only copy the fits header to fortran string if it was found * by astFindFits. * 17-NOV-2004 (DSB): * Added AST_SETFITS * 7-OCT-2005 (DSB): * Added AST_GETFITS */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "ast_err.h" /* AST error codes */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "object.h" /* C interface to the base Object class */ #include "fitschan.h" /* C interface to the FitsChan class */ #include #include /* Prototypes for private functions. */ /* ================================= */ static char *SourceWrap( const char *(*)( void ), int * ); static void SinkWrap( void (*)( const char * ), const char *, int * ); static void TabSourceWrap( void (*)( void ), AstFitsChan *, const char *, int, int, int * ); /* Prototypes for external functions. */ /* ================================== */ /* This is the null function defined by the FORTRAN interface in fobject.c. */ F77_SUBROUTINE(ast_null)( void ); /* Source and sink function interfaces. */ /* ==================================== */ /* These functions are concerned with allowing FORTRAN implementations of FitsChan source and sink functions to be passed to the FitsChan class and invoked when necessary by C code in the main class implementation. All FORTRAN-specific aspects of this interface are encapsulated here. */ static void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) { /* * Name: * SinkWrap * Purpose: * Wrapper function to invoke a FORTRAN FitsChan sink function. * Type: * Private function. * Synopsis: * static void SinkWrap( void (* sink)( const char * ), const char *line, * int *status ) * Description: * This function invokes the sink function whose pointer is * supplied in order to write an output line to an external data * store. * Parameters: * sink * Pointer to a sink function. This should result from a cast * applied to a pointer to a function (with two FORTRAN * arguments: a character string of length 80 to receive a FITS * card and an integer error status), that returns void. This * is the form of FitsChan sink function employed by the FORTRAN * language interface to the AST library. * status * Pointer to inherited status value. */ /* Local Variables: */ DECLARE_CHARACTER(CARD,80); DECLARE_INTEGER(STATUS); char *d; const char *c; int i,lim; /* Check the global error status. */ if ( !astOK ) return; /* Copy the supplied null terminated string to a fixed length, blank padded string which can be passed to the Fortran routine. */ c = line; d = CARD; lim = (int) strlen( line ); if( lim > 80 ) lim = 80; for( i = 0; i < lim; i++ ){ *(d++) = (*c++); } for( ; i < 80; i++ ){ *(d++) = ' '; } /* Cast the sink function pointer to a pointer to the FORTRAN subroutine and then invoke it. Transfer the AST error status to and from the subroutine's error status argument. */ STATUS = astStatus; ( ( void (*)() ) sink )( CHARACTER_ARG(CARD), INTEGER_ARG(&STATUS) TRAIL_ARG(CARD) ); astSetStatus( STATUS ); } static char *SourceWrap( const char *(* source)( void ), int *status ) { /* * Name: * SourceWrap * Purpose: * Wrapper function to invoke a FORTRAN FitsChan source function. * Type: * Private function. * Synopsis: * static char *SourceWrap( const char *(* source)( void ), int *status ) * Description: * This function invokes the source function whose pointer is * supplied in order to read the next input line from an external * data store. It then returns a pointer to a dynamic string * containing a copy of the text that was read. * Parameters: * source * Pointer to a source function. This should result from a cast * applied to a pointer to a function (with two FORTRAN * arguments: a character string of length 80 to return a FITS * card and an integer error status), that returns a Fortran * integer. This is the form of FitsChan source function * employed by the FORTRAN language interface to the AST * library. * status * Pointer to inherited status. * Returned Value: * A pointer to a dynamically allocated, null terminated string * containing a copy of the text that was read. This string must be * freed by the caller (using astFree) when no longer required. * * A NULL pointer will be returned if there is no more input text * to read. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ DECLARE_CHARACTER(CARD,81); /* Fixed length Fortran string */ DECLARE_INTEGER(STATUS); /* Fortran error status value */ char *result; /* Result pointer to return */ int retval; /* Value returned by source subroutine */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Cast the source function pointer to a pointer to the FORTRAN function and then invoke it. Transfer the AST error status to and from the subroutine's error status argument. */ STATUS = astStatus; retval = ( *(F77_INTEGER_TYPE (*)()) source )( CHARACTER_ARG(CARD), INTEGER_ARG(&STATUS) TRAIL_ARG(CARD) ); astSetStatus( STATUS ); /* If a card was returned, make a dynamic copy of it. */ if ( astOK && retval ) result = astString( CARD, 80 ); /* Return the result. */ return result; } static void TabSourceWrap( void (*tabsource)( void ), AstFitsChan *this, const char *extname, int extver, int extlevel, int *status ){ /* * Name: * TabSourceWrap * Purpose: * Wrapper function to invoke the F77 table source function. * Type: * Private function. * Synopsis: * void TabSourceWrap( void (*tabsource)( void ), * AstFitsChan *this, const char *extname, * int extver, int extlevel, int *status ){ * Class Membership: * Channel member function. * Description: * This function invokes the table source function whose pointer is * supplied in order to read a named FITS binary table from an external * FITS file. * Parameters: * tabsource * Pointer to the C tab source function. * this * Pointer to the FitsChan. It's reference count will be decremented * by this function. * extname * Pointer to the string holding the name of the FITS extension * from which a table is to be read. * extver * FITS "EXTVER" value for required extension. * extlevel * FITS "EXTLEVEL" value for required extension. * status * Pointer to the inherited status variable. */ /* Local Variables: */ DECLARE_CHARACTER(EXTNAME,80); DECLARE_INTEGER(THIS_ID); DECLARE_INTEGER(LSTAT); DECLARE_INTEGER(EXTVER); DECLARE_INTEGER(EXTLEVEL); AstObject *this_id; char *d; const char *c; int i; int lim; /* Check the global error status. */ if ( !astOK ) return; /* Get an external identifier for the FitsChan. Note, this does not increment the Object's reference count. Cannot use astClone as we are in a "public" environment and so astClone would require an object identifier, not a true C pointer. So the calling function should clone the pointer before calling this function to avoid the reference count dropping to zero when the associated identifier is annulled at the end of this function. */ this_id = astMakeId( this ); THIS_ID = astP2I( this_id ); /* Export the extver and extlevel values */ EXTVER = extver; EXTLEVEL = extlevel; /* Copy the supplied null terminated string to a fixed length, blank padded string which can be passed to the Fortran routine. */ c = extname; d = EXTNAME; lim = (int) strlen( extname ); if( lim > 80 ) lim = 80; for( i = 0; i < lim; i++ ){ *(d++) = (*c++); } for( ; i < 80; i++ ){ *(d++) = ' '; } /* Invoke the table source function (casting it to the F77 API first) to read the table, and store it in the FitsChan. */ if( astOK ) { LSTAT = 0; ( ( void (*)() ) tabsource )( INTEGER_ARG(&THIS_ID), CHARACTER_ARG(EXTNAME), INTEGER_ARG(&EXTVER), INTEGER_ARG(&EXTLEVEL), INTEGER_ARG(&LSTAT) TRAIL_ARG(EXTNAME) ); } /* Report an error if the source function failed. */ if( LSTAT ) { if( astOK ) { astError( AST__NOTAB, "astRead(%s): The table source function failed to read " "a binary table from extension %s in an external FITS file.", status, astGetC( this_id, "Class" ), extname ); } else { astError( astStatus, "astRead(%s): The table source function failed to read " "a binary table from extension %s in an external FITS file.", status, astGetC( this_id, "Class" ), extname ); } } /* Free the external identifier for the FitsChan. Note, this decrements the Object reference count. See comments above. */ (void) astAnnulId( this_id ); } /* FORTRAN interface functions. */ /* ============================ */ /* These functions implement the remainder of the FORTRAN interface. */ F77_INTEGER_FUNCTION(ast_fitschan)( F77_INTEGER_TYPE (* SOURCE)(), void (* SINK)(), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; const char *(* source)( void ); int i; void (* sink)( const char * ); astAt( "AST_FITSCHAN", NULL, 0 ); astWatchSTATUS( /* Set the source and sink function pointers to NULL if a pointer to the null routine AST_NULL has been supplied. */ source = (const char *(*)( void )) SOURCE; if ( source == (const char *(*)( void )) F77_EXTERNAL_NAME(ast_null) ) { source = NULL; } sink = (void (*)( const char * )) SINK; if ( sink == (void (*)( const char * )) F77_EXTERNAL_NAME(ast_null) ) { sink = NULL; } options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astFitsChanFor( source, SourceWrap, sink, SinkWrap, "%s", options ) ); astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isafitschan)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAFITSCHAN", NULL, 0 ); astWatchSTATUS( RESULT = astIsAFitsChan( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_putcards)( INTEGER(THIS), CHARACTER(CARDS), INTEGER(STATUS) TRAIL(CARDS) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(CARDS) char *cards; astAt( "AST_PUTCARDS", NULL, 0 ); astWatchSTATUS( cards = astString( CARDS, CARDS_length ); astPutCards( astI2P( *THIS ), cards ); (void) astFree( (void *) cards ); ) } F77_SUBROUTINE(ast_putfits)( INTEGER(THIS), CHARACTER(CARD), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(CARD) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(CARD) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *card; astAt( "AST_PUTFITS", NULL, 0 ); astWatchSTATUS( card = astString( CARD, CARD_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astPutFits( astI2P( *THIS ), card, overwrite ); (void) astFree( (void *) card ); ) } F77_SUBROUTINE(ast_delfits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_DELFITS", NULL, 0 ); astWatchSTATUS( astDelFits( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_purgewcs)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_PURGEWCS", NULL, 0 ); astWatchSTATUS( astPurgeWCS( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_retainfits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_RETAINFITS", NULL, 0 ); astWatchSTATUS( astRetainFits( astI2P( *THIS ) ); ) } F77_LOGICAL_FUNCTION(ast_findfits)( INTEGER(THIS), CHARACTER(NAME), CHARACTER(CARD), LOGICAL(INC), INTEGER(STATUS) TRAIL(NAME) TRAIL(CARD) ){ GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_CHARACTER(CARD) GENPTR_LOGICAL(INC) F77_LOGICAL_TYPE(RESULT); int i, len; char *name; char card[ 81 ]; int inc; astAt( "AST_FINDFITS", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); inc = F77_ISTRUE( *INC ); RESULT = astFindFits( astI2P( *THIS ), name, card, inc ) ? F77_TRUE : F77_FALSE; i = 0; if ( astOK && F77_ISTRUE(RESULT) ) { len = (int) strlen( card ); for( i = 0; i < CARD_length && i < len; i++ ) CARD[i] = card[i]; } for( ; i < CARD_length; i++ ) CARD[i] = ' '; (void) astFree( (void *) name ); ) return RESULT; } F77_SUBROUTINE(ast_setfitsf)( INTEGER(THIS), CHARACTER(NAME), DOUBLE(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_DOUBLE(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment; astAt( "AST_SETFITSF", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsF( astI2P( *THIS ), name, *VALUE, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitsu)( INTEGER(THIS), CHARACTER(NAME), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment; astAt( "AST_SETFITSU", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsU( astI2P( *THIS ), name, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitscm)( INTEGER(THIS), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *comment; astAt( "AST_SETFITSCM", NULL, 0 ); astWatchSTATUS( comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsCM( astI2P( *THIS ), comment, overwrite ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitsi)( INTEGER(THIS), CHARACTER(NAME), INTEGER(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_INTEGER(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment; astAt( "AST_SETFITSI", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsI( astI2P( *THIS ), name, *VALUE, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitscf)( INTEGER(THIS), CHARACTER(NAME), DOUBLE_ARRAY(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_DOUBLE_ARRAY(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment; astAt( "AST_SETFITSCF", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsCF( astI2P( *THIS ), name, VALUE, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitsci)( INTEGER(THIS), CHARACTER(NAME), INTEGER_ARRAY(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_INTEGER_ARRAY(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment; astAt( "AST_SETFITSCI", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsCI( astI2P( *THIS ), name, VALUE, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitsl)( INTEGER(THIS), CHARACTER(NAME), LOGICAL(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_LOGICAL(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite, value; char *name, *comment; astAt( "AST_SETFITSL", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); value = F77_ISTRUE( *VALUE ); astSetFitsL( astI2P( *THIS ), name, value, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitss)( INTEGER(THIS), CHARACTER(NAME), CHARACTER(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(VALUE) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_CHARACTER(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment, *value; astAt( "AST_SETFITSS", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); value = astString( VALUE, VALUE_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsS( astI2P( *THIS ), name, value, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) value ); (void) astFree( (void *) comment ); ) } F77_SUBROUTINE(ast_setfitscn)( INTEGER(THIS), CHARACTER(NAME), CHARACTER(VALUE), CHARACTER(COMMENT), LOGICAL(OVERWRITE), INTEGER(STATUS) TRAIL(NAME) TRAIL(VALUE) TRAIL(COMMENT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_CHARACTER(VALUE) GENPTR_CHARACTER(COMMENT) GENPTR_LOGICAL(OVERWRITE) int overwrite; char *name, *comment, *value; astAt( "AST_SETFITSS", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); value = astString( VALUE, VALUE_length ); comment = astString( COMMENT, COMMENT_length ); overwrite = F77_ISTRUE( *OVERWRITE ); astSetFitsCN( astI2P( *THIS ), name, value, comment, overwrite ); (void) astFree( (void *) name ); (void) astFree( (void *) value ); (void) astFree( (void *) comment ); ) } #define MAKE_AST_GETFITS(f,F,Ftype,X,Xtype) \ F77_LOGICAL_FUNCTION(ast_getfits##f)( INTEGER(THIS), \ CHARACTER(NAME), \ Ftype(VALUE), \ INTEGER(STATUS) \ TRAIL(NAME) ){ \ GENPTR_INTEGER(THIS) \ GENPTR_CHARACTER(NAME) \ GENPTR_##Ftype(VALUE) \ GENPTR_INTEGER(STATUS) \ F77_LOGICAL_TYPE(RESULT); \ \ char *name; \ Xtype *value; \ \ value = (Xtype *) VALUE; \ \ astAt( "AST_GETFITS"#F, NULL, 0 ); \ astWatchSTATUS( \ name = astString( NAME, NAME_length ); \ if( name && !strcmp( name, "." ) ) name = astFree( name ); \ RESULT = astGetFits##X( astI2P( *THIS ), name, value ) ? \ F77_TRUE : F77_FALSE; \ (void) astFree( (void *) name ); \ ) \ return RESULT; \ } MAKE_AST_GETFITS(f,F,DOUBLE,F,double) MAKE_AST_GETFITS(i,I,INTEGER,I,int) MAKE_AST_GETFITS(l,L,LOGICAL,L,int) #undef MAKE_AST_GETFITS F77_LOGICAL_FUNCTION(ast_testfits)( INTEGER(THIS), CHARACTER(NAME), LOGICAL(THERE), INTEGER(STATUS) TRAIL(NAME) ){ GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) GENPTR_LOGICAL(THERE) GENPTR_INTEGER(STATUS) F77_LOGICAL_TYPE(RESULT); char *name; int there; astAt( "AST_TESTFITS", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); RESULT = astTestFits( astI2P( *THIS ), name, &there ) ? F77_TRUE : F77_FALSE; (void) astFree( (void *) name ); ) *THERE = there ? F77_TRUE : F77_FALSE; return RESULT; } #define MAKE_AST_GETFITS(f,F,Ftype,X,Xtype) \ F77_LOGICAL_FUNCTION(ast_getfits##f)( INTEGER(THIS), \ CHARACTER(NAME), \ Ftype##_ARRAY(VALUE), \ INTEGER(STATUS) \ TRAIL(NAME) ){ \ GENPTR_INTEGER(THIS) \ GENPTR_CHARACTER(NAME) \ GENPTR_##Ftype##_ARRAY(VALUE) \ GENPTR_INTEGER(STATUS) \ F77_LOGICAL_TYPE(RESULT); \ \ char *name; \ Xtype value[2]; \ \ astAt( "AST_GETFITS"#F, NULL, 0 ); \ astWatchSTATUS( \ name = astString( NAME, NAME_length ); \ if( name && !strcmp( name, "." ) ) name = astFree( name ); \ RESULT = astGetFits##X( astI2P( *THIS ), name, value ) ? \ F77_TRUE : F77_FALSE; \ VALUE[ 0 ] = (F77_DOUBLE_TYPE) value[ 0 ]; \ VALUE[ 1 ] = (F77_DOUBLE_TYPE) value[ 1 ]; \ (void) astFree( (void *) name ); \ ) \ return RESULT; \ } MAKE_AST_GETFITS(cf,CF,DOUBLE,CF,double) MAKE_AST_GETFITS(ci,CI,INTEGER,CI,int) #undef MAKE_AST_GETFITS #define MAKE_AST_GETFITS(f,F,X) \ F77_LOGICAL_FUNCTION(ast_getfits##f)( INTEGER(THIS), \ CHARACTER(NAME), \ CHARACTER(VALUE), \ INTEGER(STATUS) \ TRAIL(NAME) \ TRAIL(VALUE) ){ \ GENPTR_INTEGER(THIS) \ GENPTR_CHARACTER(NAME) \ GENPTR_CHARACTER(VALUE) \ GENPTR_INTEGER(STATUS) \ F77_LOGICAL_TYPE(RESULT); \ \ char *name; \ int i, len; \ char *value; \ \ astAt( "AST_GETFITS"#F, NULL, 0 ); \ astWatchSTATUS( \ name = astString( NAME, NAME_length ); \ if( name && !strcmp( name, "." ) ) name = astFree( name ); \ RESULT = astGetFits##X( astI2P( *THIS ), name, &value ) ? \ F77_TRUE : F77_FALSE; \ if ( astOK && F77_ISTRUE(RESULT) ) { \ len = (int) strlen( value ); \ for( i = 0; i < VALUE_length && i < len; i++ ) VALUE[i] = value[i]; \ } else { \ i = 0; \ } \ for( ; i < VALUE_length; i++ ) VALUE[i] = ' '; \ (void) astFree( (void *) name ); \ ) \ return RESULT; \ } MAKE_AST_GETFITS(s,S,S) MAKE_AST_GETFITS(cn,CN,CN) #undef MAKE_AST_GETFITS F77_SUBROUTINE(ast_readfits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_READFITS", NULL, 0 ); astWatchSTATUS( astReadFits( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_writefits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_WRITEFITS", NULL, 0 ); astWatchSTATUS( astWriteFits( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_emptyfits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_EMPTYFITS", NULL, 0 ); astWatchSTATUS( astEmptyFits( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_showfits)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_SHOWFITS", NULL, 0 ); astWatchSTATUS( astShowFits( astI2P( *THIS ) ); ) } F77_INTEGER_FUNCTION(ast_gettables)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_INTEGER_TYPE(RESULT); astAt( "AST_GETTABLES", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astGetTables( astI2P( *THIS ) ) ); ) return RESULT; } F77_SUBROUTINE(ast_removetables)( INTEGER(THIS), CHARACTER(KEY), INTEGER(STATUS) TRAIL(KEY) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(KEY) char *key; astAt( "AST_REMOVETABLES", NULL, 0 ); astWatchSTATUS( key = astString( KEY, KEY_length ); astRemoveTables( astI2P( *THIS ), key ); (void) astFree( (void *) key ); ) } F77_SUBROUTINE(ast_puttable)( INTEGER(THIS), INTEGER(TABLE), CHARACTER(EXTNAM), INTEGER(STATUS) TRAIL(EXTNAM) ){ GENPTR_INTEGER(THIS) GENPTR_INTEGER(TABLES) GENPTR_CHARACTER(EXTNAM) char *extnam; astAt( "AST_PUTTABLE", NULL, 0 ); astWatchSTATUS( extnam = astString( EXTNAM, EXTNAM_length ); astPutTable( astI2P( *THIS ), astI2P( *TABLE ), extnam ); extnam = astFree( extnam ); ) } F77_SUBROUTINE(ast_puttables)( INTEGER(THIS), INTEGER(TABLES), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_INTEGER(TABLES) astAt( "AST_PUTTABLES", NULL, 0 ); astWatchSTATUS( astPutTables( astI2P( *THIS ), astI2P( *TABLES ) ); ) } F77_SUBROUTINE(ast_tablesource)( INTEGER(THIS), void (* SOURCE)(), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) void (* source)( void ); astAt( "AST_TABLESOURCE", NULL, 0 ); astWatchSTATUS( source = (void (*)( void )) SOURCE; if ( source == (void (*)( void )) F77_EXTERNAL_NAME(ast_null) ) { source = NULL; } astSetTableSource( astI2P( *THIS ), source, TabSourceWrap ); ) } ./ast-7.3.3/fzoommap.c0000644000175000017500000000612012262533650013135 0ustar olesoles/* *+ * Name: * fzoommap.c * Purpose: * Define a FORTRAN 77 interface to the AST ZoomMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the ZoomMap class. * Routines Defined: * AST_ISAZOOMMAP * AST_ZOOMMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 18-JUL-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "zoommap.h" /* C interface to the ZoomMap class */ F77_LOGICAL_FUNCTION(ast_isazoommap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAZOOMMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAZoomMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_zoommap)( INTEGER(NAXES), DOUBLE(ZOOM), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NAXES) GENPTR_DOUBLE(ZOOM) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_ZOOMMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astZoomMap( *NAXES, *ZOOM, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/fmathmap.c0000644000175000017500000000750212262533650013107 0ustar olesoles/* *+ * Name: * fmathmap.c * Purpose: * Define a FORTRAN 77 interface to the AST MathMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the MathMap class. * Routines Defined: * AST_ISAMATHMAP * AST_MATHMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 3-SEP-1999 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "mathmap.h" /* C interface to the MathMap class */ F77_LOGICAL_FUNCTION(ast_isamathmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAMATHMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAMathMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_mathmap)( INTEGER(NIN), INTEGER(NOUT), INTEGER(NFWD), CHARACTER_ARRAY(FWD), INTEGER(NINV), CHARACTER_ARRAY(INV), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(FWD) TRAIL(INV) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NIN) GENPTR_INTEGER(NOUT) GENPTR_INTEGER(NFWD) GENPTR_CHARACTER_ARRAY(FWD) GENPTR_INTEGER(NINV) GENPTR_CHARACTER_ARRAY(INV) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char **fwd; char **inv; char *options; int i; astAt( "AST_MATHMAP", NULL, 0 ); astWatchSTATUS( fwd = astStringArray( FWD, *NFWD, FWD_length ); inv = astStringArray( INV, *NINV, INV_length ); options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astMathMap( *NIN, *NOUT, *NFWD, (const char **) fwd, *NINV, (const char **) inv, "%s", options ) ); astFree( options ); astFree( inv ); astFree( fwd ); ) return RESULT; } ./ast-7.3.3/fcmpframe.c0000644000175000017500000000624412262533650013254 0ustar olesoles/* *+ * Name: * fcmpframe.c * Purpose: * Define a FORTRAN 77 interface to the AST CmpFrame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the CmpFrame class. * Routines Defined: * AST_CMPFRAME * AST_ISACMPFRAME * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 30-SEP-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "cmpframe.h" /* C interface to the CmpFrame class */ F77_LOGICAL_FUNCTION(ast_isacmpframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISACMPFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsACmpFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_cmpframe)( INTEGER(FRAME1), INTEGER(FRAME2), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME1) GENPTR_INTEGER(FRAME2) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_CMPFRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astCmpFrame( astI2P( *FRAME1 ), astI2P( *FRAME2 ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/intramap.h0000644000175000017500000002750712262533650013141 0ustar olesoles#if !defined( INTRAMAP_INCLUDED ) /* Include this file only once */ #define INTRAMAP_INCLUDED /* *+ * Name: * intramap.h * Type: * C include file. * Purpose: * Define the interface to the IntraMap class. * Invocation: * #include "intramap.h" * Description: * This include file defines the interface to the IntraMap class * and provides the type definitions, function prototypes and * macros, etc. needed to use this class. * * The IntraMap class implements Mappings which transform * coordinates using a privately-defined transformation function * (e.g. written in C). * Inheritance: * The IntraMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * IntraFlag * IntraMap identification string. * Methods Over-Ridden: * Public: * None. * * Protected: * astMapMerge * Simplify a sequence of Mappings containing an IntraMap. * astTransform * Transform a set of points using an IntraMap. * New Methods Defined: * Public: * None. * * Protected: * astClearIntraFlag * Clear the IntraFlag attribute for an IntraMap. * astGetIntraFlag * Get the value of the IntraFlag attribute for an IntraMap. * astSetIntraFlag * Set the value of the IntraFlag attribute for an IntraMap. * astTestIntraFlag * Test whether a value has been set for the IntraFlag attribute of * an IntraMap. * Other Class Functions: * Public: * astIntraMap * Create an IntraMap. * astIntraReg * Register a transformation function for use by an IntraMap. * astIsAIntraMap * Test class membership. * * Protected: * astCheckIntraMap * Validate class membership. * astInitIntraMap * Initialise an IntraMap. * astLoadIntraMap * Load an IntraMap. * Macros: * None. * Type Definitions: * Public: * AstIntraMap * IntraMap object type. * * Protected: * AstIntraMapVtab * IntraMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 24-MAR-1998 (RFWS): * Original version. * 16-SEP-1999 (RFWS): * Added the IntraFlag attribute and added a Mapping pointer as a new * first argument to transformation functions. * 8-JAN-2003 (DSB): * Added protected astInitIntraMapVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macro Definitions. */ /* ================== */ #define AST__NOFWD (1U) /* No forward transformation defined */ #define AST__NOINV (2U) /* No inverse transformation defined */ #define AST__SIMPFI (4U) /* Forward-inverse may be simplified */ #define AST__SIMPIF (8U) /* Inverse-forward may be simplified */ #define AST__ANY (-66) /* Allow any number of input/output coords */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* IntraMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstIntraMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ char *intraflag; /* Pointer to identification string */ int ifun; /* Transformation function index */ } AstIntraMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstIntraMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ const char *(* GetIntraFlag)( AstIntraMap *, int * ); int (* TestIntraFlag)( AstIntraMap *, int * ); void (* ClearIntraFlag)( AstIntraMap *, int * ); void (* SetIntraFlag)( AstIntraMap *, const char *, int * ); } AstIntraMapVtab; /* Structure to hold data for transformation functions. */ typedef struct AstIntraMapTranData { void (* tran)( AstMapping *, int, int, const double *[], int, int, double *[] ); /* Pointer to transformation function */ void (* tran_wrap)( void (*)( AstMapping *, int, int, const double *[], int, int, double *[] ), AstMapping *, int, int, const double *[], int, int, double *[], int * ); /* Pointer to wrapper function */ char *author; /* Author's name */ char *contact; /* Contact details (e.g. e-mail address) */ char *name; /* Function name (assigned by caller) */ char *purpose; /* Comment string describing purpose */ int nin; /* Number of input coordinates per point */ int nout; /* Number of output coordinates per point */ unsigned int flags; /* Flags to describe function behaviour */ } AstIntraMapTranData; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstIntraMapGlobals { AstIntraMapVtab Class_Vtab; int Class_Init; } AstIntraMapGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(IntraMap) /* Check class membership */ astPROTO_ISA(IntraMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstIntraMap *astIntraMap_( const char *, int, int, const char *, int *, ...); #else AstIntraMap *astIntraMapId_( const char *, int, int, const char *, ... )__attribute__((format(printf,4,5))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstIntraMap *astInitIntraMap_( void *, size_t, int, AstIntraMapVtab *, const char *, const char *, int, int, int * ); /* Vtab initialiser. */ void astInitIntraMapVtab_( AstIntraMapVtab *, const char *, int * ); /* Loader. */ AstIntraMap *astLoadIntraMap_( void *, size_t, AstIntraMapVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitIntraMapGlobals_( AstIntraMapGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astIntraReg_( const char *, int, int, void (*)( AstMapping *, int, int, const double *[], int, int, double *[] ), unsigned int, const char *, const char *, const char *, int * ); #if defined(astCLASS) /* Protected */ const char *astGetIntraFlag_( AstIntraMap *, int * ); int astTestIntraFlag_( AstIntraMap *, int * ); void astClearIntraFlag_( AstIntraMap *, int * ); void astSetIntraFlag_( AstIntraMap *, const char *, int * ); #else /* Public only */ void astIntraRegFor_( const char *, int, int, void (*)( AstMapping *, int, int, const double *[], int, int, double *[] ), void (*)( void (*)( AstMapping *, int, int, const double *[], int, int, double *[]), AstMapping *, int, int, const double *[], int, int, double *[], int * ), unsigned int, const char *, const char *, const char *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckIntraMap(this) astINVOKE_CHECK(IntraMap,this,0) #define astVerifyIntraMap(this) astINVOKE_CHECK(IntraMap,this,1) /* Test class membership. */ #define astIsAIntraMap(this) astINVOKE_ISA(IntraMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astIntraMap astINVOKE(F,astIntraMap_) #else #define astIntraMap astINVOKE(F,astIntraMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitIntraMap(mem,size,init,vtab,name,fname,nin,nout) \ astINVOKE(O,astInitIntraMap_(mem,size,init,vtab,name,fname,nin,nout,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitIntraMapVtab(vtab,name) astINVOKE(V,astInitIntraMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadIntraMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadIntraMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckIntraMap to validate IntraMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astIntraReg(name,nin,nout,tran,flags,purpose,author,contact) \ astIntraReg_(name,nin,nout,tran,flags,purpose,author,contact,STATUS_PTR) #if defined(astCLASS) /* Protected */ #define astClearIntraFlag(this) \ astINVOKE(V,astClearIntraFlag_(astCheckIntraMap(this),STATUS_PTR)) #define astGetIntraFlag(this) \ astINVOKE(V,astGetIntraFlag_(astCheckIntraMap(this),STATUS_PTR)) #define astSetIntraFlag(this,value) \ astINVOKE(V,astSetIntraFlag_(astCheckIntraMap(this),value,STATUS_PTR)) #define astTestIntraFlag(this) \ astINVOKE(V,astTestIntraFlag_(astCheckIntraMap(this),STATUS_PTR)) #else /* Public only */ #define astIntraRegFor(name,nin,nout,tran,tran_wrap,flags,purpose,author,contact) \ astIntraRegFor_(name,nin,nout,tran,tran_wrap,flags,purpose,author,contact,STATUS_PTR) #endif #endif ./ast-7.3.3/GRF_PAR0000644000175000017500000000603312262533650012207 0ustar olesoles*+ * Name: * GRF_PAR * Purpose: * Define the constants needed to implement Fortran GRF routines. * Language: * Fortran 77 * Type of Module: * Include file. * Description: * This file contains definitions which are required by Fortran 77 * programs which implement their own grf routines (routines for * drawing graphics primitive used by the AST Plot class). * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 13-JUN-2001 (DSB): * Original version. *- * Values identifying different graphics attributes. INTEGER GRF__STYLE PARAMETER ( GRF__STYLE = 0 ) INTEGER GRF__WIDTH PARAMETER ( GRF__WIDTH = 1 ) INTEGER GRF__SIZE PARAMETER ( GRF__SIZE = 2 ) INTEGER GRF__FONT PARAMETER ( GRF__FONT = 3 ) INTEGER GRF__COLOUR PARAMETER ( GRF__COLOUR = 4 ) * Values identifying different graphics primatives. INTEGER GRF__TEXT PARAMETER ( GRF__TEXT = 0 ) INTEGER GRF__LINE PARAMETER ( GRF__LINE = 1 ) INTEGER GRF__MARK PARAMETER ( GRF__MARK = 2 ) * The number of different graphics attributes. INTEGER GRF__NATTR PARAMETER ( GRF__NATTR = 5 ) * Values identifying capabilities. INTEGER GRF__ESC PARAMETER ( GRF__ESC = 0 ) INTEGER GRF__MJUST PARAMETER ( GRF__MJUST = 1 ) INTEGER GRF__SCALES PARAMETER ( GRF__SCALES = 2 ) * Values identifying types of graphics escape sequence INTEGER GRF__ESPER PARAMETER ( GRF__ESPER = 1 ) INTEGER GRF__ESSUP PARAMETER ( GRF__ESSUP = 2 ) INTEGER GRF__ESSUB PARAMETER ( GRF__ESSUB = 3 ) INTEGER GRF__ESGAP PARAMETER ( GRF__ESGAP = 4 ) INTEGER GRF__ESBAC PARAMETER ( GRF__ESBAC = 5 ) INTEGER GRF__ESSIZ PARAMETER ( GRF__ESSIZ = 6 ) INTEGER GRF__ESWID PARAMETER ( GRF__ESWID = 7 ) INTEGER GRF__ESFON PARAMETER ( GRF__ESFON = 8 ) INTEGER GRF__ESCOL PARAMETER ( GRF__ESCOL = 9 ) INTEGER GRF__ESSTY PARAMETER ( GRF__ESSTY = 10 ) INTEGER GRF__ESPOP PARAMETER ( GRF__ESPOP = 11 ) INTEGER GRF__ESPSH PARAMETER ( GRF__ESPSH = 12 ) ./ast-7.3.3/cmpregion.h0000644000175000017500000001771612262533650013312 0ustar olesoles#if !defined( CMPREGION_INCLUDED ) /* Include this file only once */ #define CMPREGION_INCLUDED /* *+ * Name: * cmpregion.h * Type: * C include file. * Purpose: * Define the interface to the CmpRegion class. * Invocation: * #include "cmpregion.h" * Description: * This include file defines the interface to the CmpRegion class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The CmpRegion class implement a Region which represents a simple interval * on each axis of the encapsulated Frame * Inheritance: * The CmpRegion class inherits from the Region class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 11-OCT-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "region.h" /* Coordinate regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros. */ /* ------- */ /* Boolean operators */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif #define AST__AND 1 #define AST__OR 2 #define AST__XOR 3 /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* CmpRegion structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstCmpRegion { /* Attributes inherited from the parent class. */ AstRegion region; /* Parent class structure */ /* Attributes specific to objects in this class. */ AstRegion *region1; /* First component Region */ AstRegion *region2; /* Second component Region */ int oper; /* Boolean operator */ double *rvals[ 2 ]; /* Used boundary length at each break */ double *offs[ 2 ]; /* Jump at each break */ int nbreak[ 2 ]; /* Number of breaks */ double d0[ 2 ]; /* Total used boundary length */ double dtot[ 2 ]; /* Total boundary length */ AstRegion *xor1; /* First XORed Region */ AstRegion *xor2; /* Second XORed Region */ int bounded; /* Is this CmpRegion bounded? */ } AstCmpRegion; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstCmpRegionVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstRegionVtab region_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ int (* CmpRegionList)( AstCmpRegion *, int *, AstRegion ***, int * ); } AstCmpRegionVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstCmpRegionGlobals { AstCmpRegionVtab Class_Vtab; int Class_Init; } AstCmpRegionGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitCmpRegionGlobals_( AstCmpRegionGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(CmpRegion) /* Check class membership */ astPROTO_ISA(CmpRegion) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstCmpRegion *astCmpRegion_( void *, void *, int, const char *, int *, ...); #else AstCmpRegion *astCmpRegionId_( void *, void *, int, const char *, ... )__attribute__((format(printf,4,5))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstCmpRegion *astInitCmpRegion_( void *, size_t, int, AstCmpRegionVtab *, const char *, AstRegion *, AstRegion *, int, int * ); /* Vtab initialiser. */ void astInitCmpRegionVtab_( AstCmpRegionVtab *, const char *, int * ); /* Loader. */ AstCmpRegion *astLoadCmpRegion_( void *, size_t, AstCmpRegionVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ int astCmpRegionList_( AstCmpRegion *, int *, AstRegion ***, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckCmpRegion(this) astINVOKE_CHECK(CmpRegion,this,0) #define astVerifyCmpRegion(this) astINVOKE_CHECK(CmpRegion,this,1) /* Test class membership. */ #define astIsACmpRegion(this) astINVOKE_ISA(CmpRegion,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astCmpRegion astINVOKE(F,astCmpRegion_) #else #define astCmpRegion astINVOKE(F,astCmpRegionId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitCmpRegion(mem,size,init,vtab,name,reg1,reg2,oper) \ astINVOKE(O,astInitCmpRegion_(mem,size,init,vtab,name,reg1,reg2,oper,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitCmpRegionVtab(vtab,name) astINVOKE(V,astInitCmpRegionVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadCmpRegion(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadCmpRegion_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckCmpRegion to validate CmpRegion pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astCmpRegionList(this,nreg,reg_list) \ astINVOKE(V,astCmpRegionList_(this,nreg,reg_list,STATUS_PTR)) #endif #endif ./ast-7.3.3/ftranmap.c0000644000175000017500000000617312262533650013125 0ustar olesoles/* *+ * Name: * ftranmap.c * Purpose: * Define a FORTRAN 77 interface to the AST TranMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the TranMap class. * Routines Defined: * AST_ISATRANMAP * AST_TRANMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S.Berry (Starlink) * History: * 10-FEB-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "tranmap.h" /* C interface to the TranMap class */ F77_LOGICAL_FUNCTION(ast_isatranmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astWatchSTATUS( astAt( "AST_ISATRANMAP", NULL, 0 ); RESULT = astIsATranMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_tranmap)( INTEGER(MAP1), INTEGER(MAP2), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(MAP1) GENPTR_INTEGER(MAP2) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_TRANMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astTranMap( astI2P( *MAP1 ), astI2P( *MAP2 ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/permmap.h0000644000175000017500000002454612262533650012767 0ustar olesoles#if !defined( PERMMAP_INCLUDED ) /* Include this file only once */ #define PERMMAP_INCLUDED /* *+ * Name: * permmap.h * Type: * C include file. * Purpose: * Define the interface to the PermMap class. * Invocation: * #include "permmap.h" * Description: * This include file defines the interface to the PermMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The PermMap class implements Mappings that perform permutation * of the order of coordinate values, possibly also accompanied by * changes in the number of coordinates (between input and output). * * In addition to permuting the coordinate order, coordinates may * also be assigned constant values which are unrelated to other * coordinate values. This facility is useful when the number of * coordinates is being increased, as it allows fixed values to be * assigned to the new coordinates. * Inheritance: * The PermMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * None. * * Protected: * astTransform * Transform a set of points. * New Methods Defined: * Public: * None. * * Protected: * astGetConstants * Obtain a copy of the constants array * astGetInPerm * Obtain a copy of the input permutation array * astGetOutPerm * Obtain a copy of the output permutation array * Other Class Functions: * Public: * astIsAPermMap * Test class membership. * astPermMap * Create a PermMap. * * Protected: * astCheckPermMap * Validate class membership. * astInitPermMap * Initialise a PermMap. * astInitPermMapVtab * Initialise the virtual function table for the PermMap class. * astLoadPermMap * Load a PermMap. * Macros: * None. * Type Definitions: * Public: * AstPermMap * PermMap object type. * * Protected: * AstPermMapVtab * PermMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 29-FEB-1996 (RFWS): * Original version. * 26-SEP-1996 (RFWS): * Added external interface and I/O facilities. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitPermMapVtab * method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* PermMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstPermMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ int *inperm; /* Pointer to input permutation array */ int *outperm; /* Pointer to output permutation array */ double *constant; /* Pointer to array of constant values */ int permsplit; /* Method to use within MapSplit */ } AstPermMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstPermMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ double *(* GetConstants)( AstPermMap *, int * ); int *(* GetInPerm)( AstPermMap *, int * ); int *(* GetOutPerm)( AstPermMap *, int * ); void (* SetPermSplit)( AstPermMap *, int, int * ); void (* ClearPermSplit)( AstPermMap *, int * ); int (* TestPermSplit)( AstPermMap *, int * ); int (* GetPermSplit)( AstPermMap *, int * ); } AstPermMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstPermMapGlobals { AstPermMapVtab Class_Vtab; int Class_Init; } AstPermMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitPermMapGlobals_( AstPermMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(PermMap) /* Check class membership */ astPROTO_ISA(PermMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstPermMap *astPermMap_( int, const int [], int, const int [], const double [], const char *, int *, ...); #else AstPermMap *astPermMapId_( int, const int [], int, const int [], const double [], const char *, ... )__attribute__((format(printf,6,7))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstPermMap *astInitPermMap_( void *, size_t, int, AstPermMapVtab *, const char *, int, const int [], int, const int [], const double [], int * ); /* Vtab initialiser. */ void astInitPermMapVtab_( AstPermMapVtab *, const char *, int * ); /* Loader. */ AstPermMap *astLoadPermMap_( void *, size_t, AstPermMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ double *astGetConstants_( AstPermMap *, int * ); int *astGetInPerm_( AstPermMap *, int * ); int *astGetOutPerm_( AstPermMap *, int * ); void astSetPermSplit_( AstPermMap *, int, int * ); void astClearPermSplit_( AstPermMap *, int * ); int astTestPermSplit_( AstPermMap *, int * ); int astGetPermSplit_( AstPermMap *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckPermMap(this) astINVOKE_CHECK(PermMap,this,0) #define astVerifyPermMap(this) astINVOKE_CHECK(PermMap,this,1) /* Test class membership. */ #define astIsAPermMap(this) astINVOKE_ISA(PermMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astPermMap astINVOKE(F,astPermMap_) #else #define astPermMap astINVOKE(F,astPermMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitPermMap(mem,size,init,vtab,name,nin,inperm,nout,outperm,constant) \ astINVOKE(O,astInitPermMap_(mem,size,init,vtab,name,nin,inperm,nout,outperm,constant,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitPermMapVtab(vtab,name) astINVOKE(V,astInitPermMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadPermMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadPermMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckPermMap to validate PermMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astGetConstants(this) astINVOKE(V,astGetConstants_(astCheckPermMap(this),STATUS_PTR)) #define astGetInPerm(this) astINVOKE(V,astGetInPerm_(astCheckPermMap(this),STATUS_PTR)) #define astGetOutPerm(this) astINVOKE(V,astGetOutPerm_(astCheckPermMap(this),STATUS_PTR)) #define astSetPermSplit(this,permsplit) astINVOKE(V,astSetPermSplit_(astCheckPermMap(this),permsplit,STATUS_PTR)) #define astClearPermSplit(this) astINVOKE(V,astClearPermSplit_(astCheckPermMap(this),STATUS_PTR)) #define astTestPermSplit(this) astINVOKE(V,astTestPermSplit_(astCheckPermMap(this),STATUS_PTR)) #define astGetPermSplit(this) astINVOKE(V,astGetPermSplit_(astCheckPermMap(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/fplot.c0000644000175000017500000005331612262533650012442 0ustar olesoles/* *+ * Name: * fplot.c * Purpose: * Define a FORTRAN 77 interface to the AST Plot class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Plot class. * Routines Defined: * AST_BORDER * AST_BOUNDINGBOX * AST_CLIP * AST_CURVE * AST_GENCURVE * AST_GRID * AST_GRIDLINE * AST_ISAPLOT * AST_MARK * AST_PLOT * AST_POLYCURVE * AST_TEXT * AST_GRFSET * AST_GRFPUSH * AST_GRFPOP * AST_STRIPESCAPES * AST_GETGRFCONTEXT * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 23-OCT-1996 (DSB): * Original version. * 14-NOV-1996 (DSB): * Method names shortened. CrvBreak removed. * 21-NOV-1996 (DSB): * Method names changed, CLIP argument NBND removed. * 18-DEC-1996 (DSB): * Argument UP changed to single precision and NCOORD removed * in AST_TEXT. * 11-AUG-1998 (DSB): * Added AST_POLYCURVE. * 9-JAN-2001 (DSB): * Change argument "in" for astMark and astPolyCurve from type * "const double (*)[]" to "const double *". * 13-JUN-2001 (DSB): * Modified to add support for astGenCurve, astGrfSet, astGrfPop, * astGrfPush and EXTERNAL grf functions. * 14-AUG-2002 (DSB): * Added AST_BOUNDINGBOX. * 8-JAN-2003 (DSB): * Include "string.h". * 10-JUL-2006 (DSB): * Add AST_STRIPESCAPES * 21-JUN-2007 (DSB): * - Avoid use of protected astGetGrfContext function. * - Change data type of GrfContext from integer to AST Object pointer. * 29-JUN-2007 (DSB): * Added astGetGrfCOntext and removed astSetGrfContext. * 30-AUG-2007 (DSB): * Use astGrfConID to get the identifier for the graphics context * KeyMap. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 #define MXSTRLEN 80 /* String length at which truncation starts within pgqtxt and pgptxt. */ /* Header files. */ /* ============= */ #include "string.h" #include "ast_err.h" /* AST error codes */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "plot.h" /* C interface to the Plot class */ #include "grf.h" /* Low-level graphics interface */ /* Prototypes for external functions. */ /* ================================== */ /* This is the null function defined by the FORTRAN interface in fobject.c. */ F77_SUBROUTINE(ast_null)( void ); static int FGAttrWrapper( AstPlot *, int, double, double *, int ); static int FGBBufWrapper( AstPlot * ); static int FGEBufWrapper( AstPlot * ); static int FGFlushWrapper( AstPlot * ); static int FGLineWrapper( AstPlot *, int, const float *, const float * ); static int FGMarkWrapper( AstPlot *, int, const float *, const float *, int ); static int FGTextWrapper( AstPlot *, const char *, float, float, const char *, float, float ); static int FGTxExtWrapper( AstPlot *, const char *, float, float, const char *, float, float, float *, float * ); static int FGCapWrapper( AstPlot *, int, int ); static int FGQchWrapper( AstPlot *, float *, float * ); static int FGScalesWrapper( AstPlot *, float *, float * ); F77_LOGICAL_FUNCTION(ast_isaplot)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAPLOT", NULL, 0 ); astWatchSTATUS( RESULT = astIsAPlot( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_plot)( INTEGER(FRAME), REAL_ARRAY(GRAPHBOX), DOUBLE_ARRAY(BASEBOX), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_REAL_ARRAY(GRAPHBOX) GENPTR_DOUBLE_ARRAY(BASEBOX) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_PLOT", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astPlot( astI2P( *FRAME ), GRAPHBOX, BASEBOX, "%s", options ) ); astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_border)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_BORDER", NULL, 0 ); astWatchSTATUS( RESULT = astBorder( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_boundingbox)( INTEGER(THIS), REAL_ARRAY(LBND), REAL_ARRAY(UBND), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_REAL_ARRAY(LBND) GENPTR_REAL_ARRAY(UBND) astAt( "AST_BOUNDINGBOX", NULL, 0 ); astWatchSTATUS( astBoundingBox( astI2P( *THIS ), LBND, UBND ); ) } F77_SUBROUTINE(ast_clip)( INTEGER(THIS), INTEGER(IFRAME), DOUBLE_ARRAY(LBND), DOUBLE_ARRAY(UBND), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) GENPTR_DOUBLE_ARRAY(LBND) GENPTR_DOUBLE_ARRAY(UBND) astAt( "AST_CLIP", NULL, 0 ); astWatchSTATUS( astClip( astI2P( *THIS ), *IFRAME, LBND, UBND ); ) } F77_SUBROUTINE(ast_gridline)( INTEGER(THIS), INTEGER(AXIS), DOUBLE_ARRAY(START), DOUBLE(LENGTH), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_INTEGER(AXIS) GENPTR_DOUBLE_ARRAY(START) GENPTR_DOUBLE(LENGTH) astAt( "AST_GRIDLINE", NULL, 0 ); astWatchSTATUS( astGridLine( astI2P( *THIS ), *AXIS, START, *LENGTH ); ) } F77_SUBROUTINE(ast_curve)( INTEGER(THIS), DOUBLE_ARRAY(START), DOUBLE_ARRAY(FINISH), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(START) GENPTR_DOUBLE_ARRAY(FINISH) astAt( "AST_CURVE", NULL, 0 ); astWatchSTATUS( astCurve( astI2P( *THIS ), START, FINISH ); ) } F77_SUBROUTINE(ast_grid)( INTEGER(THIS), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) astAt( "AST_GRID", NULL, 0 ); astWatchSTATUS( astGrid( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_mark)( INTEGER(THIS), INTEGER(NMARK), INTEGER(NCOORD), INTEGER(INDIM), DOUBLE_ARRAY(IN), INTEGER(TYPE), INTEGER(STATUS) ){ GENPTR_INTEGER(THIS) GENPTR_INTEGER(NMARK) GENPTR_INTEGER(NCOORD) GENPTR_INTEGER(INDIM) GENPTR_DOUBLE_ARRAY(IN) GENPTR_INTEGER(TYPE) astAt( "AST_MARK", NULL, 0 ); astWatchSTATUS( astMark( astI2P( *THIS ), *NMARK, *NCOORD, *INDIM, (const double *)IN, *TYPE ); ) } F77_SUBROUTINE(ast_polycurve)( INTEGER(THIS), INTEGER(NPOINT), INTEGER(NCOORD), INTEGER(INDIM), DOUBLE_ARRAY(IN), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(NPOINT) GENPTR_INTEGER(NCOORD) GENPTR_INTEGER(INDIM) GENPTR_DOUBLE_ARRAY(IN) astAt( "AST_POLYCURVE", NULL, 0 ); astWatchSTATUS( astPolyCurve( astI2P( *THIS ), *NPOINT, *NCOORD, *INDIM, (const double *)IN ); ) } F77_SUBROUTINE(ast_gencurve)( INTEGER(THIS), INTEGER(MAP), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(MAP) astAt( "AST_GENCURVE", NULL, 0 ); astWatchSTATUS( astGenCurve( astI2P( *THIS ), astI2P( *MAP ) ); ) } F77_SUBROUTINE(ast_text)( INTEGER(THIS), CHARACTER(TEXT), DOUBLE_ARRAY(POS), REAL_ARRAY(UP), CHARACTER(JUST), INTEGER(STATUS) TRAIL(TEXT) TRAIL(JUST) ){ GENPTR_INTEGER(THIS) GENPTR_CHARACTER(TEXT) GENPTR_DOUBLE_ARRAY(POS) GENPTR_REAL_ARRAY(UP) GENPTR_CHARACTER(JUST) char *text, *just; astAt( "AST_TEXT", NULL, 0 ); astWatchSTATUS( text = astString( TEXT, TEXT_length ); just = astString( JUST, JUST_length ); astText( astI2P( *THIS ), text, POS, UP, just ); (void) astFree( (void *) text ); (void) astFree( (void *) just ); ) } F77_SUBROUTINE(ast_grfpush)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_GRFPUSH", NULL, 0 ); astWatchSTATUS( astGrfPush( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_grfpop)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_GRFPOP", NULL, 0 ); astWatchSTATUS( astGrfPop( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_bbuf)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_BBUF", NULL, 0 ); astWatchSTATUS( astBBuf( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_ebuf)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) astAt( "AST_EBUF", NULL, 0 ); astWatchSTATUS( astEBuf( astI2P( *THIS ) ); ) } F77_SUBROUTINE(ast_grfset)( INTEGER(THIS), CHARACTER(NAME), AstGrfFun FUN, INTEGER(STATUS) TRAIL(NAME) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(NAME) char *name; AstGrfFun fun; const char *class; /* Object class */ const char *method; /* Current method */ int ifun; /* Index into grf function list */ AstGrfWrap wrapper; /* Wrapper function for C Grf routine*/ method = "AST_GRFSET"; class = "Plot"; astAt( method, NULL, 0 ); astWatchSTATUS( /* Set the function pointer to NULL if a pointer to the null routine AST_NULL has been supplied. */ fun = FUN; if ( fun == (AstGrfFun) F77_EXTERNAL_NAME(ast_null) ) { fun = NULL; } name = astString( NAME, NAME_length ); astGrfSet( astI2P( *THIS ), name, fun ); ifun = astGrfFunID( name, method, class ); if( ifun == AST__GATTR ) { wrapper = (AstGrfWrap) FGAttrWrapper; } else if( ifun == AST__GBBUF ) { wrapper = (AstGrfWrap) FGBBufWrapper; } else if( ifun == AST__GEBUF ) { wrapper = (AstGrfWrap) FGEBufWrapper; } else if( ifun == AST__GFLUSH ) { wrapper = (AstGrfWrap) FGFlushWrapper; } else if( ifun == AST__GLINE ) { wrapper = (AstGrfWrap) FGLineWrapper; } else if( ifun == AST__GMARK ) { wrapper = (AstGrfWrap) FGMarkWrapper; } else if( ifun == AST__GTEXT ) { wrapper = (AstGrfWrap) FGTextWrapper; } else if( ifun == AST__GCAP ) { wrapper = (AstGrfWrap) FGCapWrapper; } else if( ifun == AST__GTXEXT ) { wrapper = (AstGrfWrap) FGTxExtWrapper; } else if( ifun == AST__GQCH ) { wrapper = (AstGrfWrap) FGQchWrapper; } else if( ifun == AST__GSCALES ) { wrapper = (AstGrfWrap) FGScalesWrapper; } else { wrapper = (AstGrfWrap) FGFlushWrapper; if( astOK ) astError( AST__INTER, "%s(%s): AST internal programming " "error - Grf function id %d not yet supported.", status, method, class, ifun ); } astGrfWrapper( astI2P( *THIS ), name, wrapper ); ) } static int FGAttrWrapper( AstPlot *this, int attr, double value, double *old_value, int prim ) { DECLARE_DOUBLE(OLDVAL); int ret; F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); ret = ( *(int (*)( INTEGER(grfcon), INTEGER(attr), DOUBLE(value), DOUBLE(old_value), INTEGER(prim) )) this->grffun[ AST__GATTR ])( INTEGER_ARG(&GRFCON), INTEGER_ARG(&attr), DOUBLE_ARG(&value), DOUBLE_ARG(&OLDVAL), INTEGER_ARG(&prim) ); if( old_value ) *old_value = OLDVAL; return ret; } static int FGBBufWrapper( AstPlot *this ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)(INTEGER(grfcon))) this->grffun[ AST__GBBUF ])(INTEGER_ARG(&GRFCON)); } static int FGEBufWrapper( AstPlot *this ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)(INTEGER(grfcon))) this->grffun[ AST__GEBUF ])(INTEGER_ARG(&GRFCON)); } static int FGFlushWrapper( AstPlot *this ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)(INTEGER(grfcon))) this->grffun[ AST__GFLUSH ])(INTEGER_ARG(&GRFCON)); } static int FGLineWrapper( AstPlot *this, int n, const float *x, const float *y ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)( INTEGER(grfcon), INTEGER(n), REAL_ARRAY(x), REAL_ARRAY(y) )) this->grffun[ AST__GLINE ])( INTEGER_ARG(&GRFCON), INTEGER_ARG(&n), REAL_ARRAY_ARG(x), REAL_ARRAY_ARG(y) ); } static int FGMarkWrapper( AstPlot *this, int n, const float *x, const float *y, int type ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)( INTEGER(grfcon), INTEGER(n), REAL_ARRAY(x), REAL_ARRAY(y), INTEGER(type) )) this->grffun[ AST__GMARK ])( INTEGER_ARG(&GRFCON), INTEGER_ARG(&n), REAL_ARRAY_ARG(x), REAL_ARRAY_ARG(y), INTEGER_ARG(&type) ); } static int FGTextWrapper( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy ) { DECLARE_CHARACTER(LTEXT,MXSTRLEN); DECLARE_CHARACTER(LJUST,MXSTRLEN); int ftext_length; int fjust_length; F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); ftext_length = strlen( text ); if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; astStringExport( text, LTEXT, ftext_length ); fjust_length = strlen( just ); if( fjust_length > LJUST_length ) fjust_length = LJUST_length; astStringExport( just, LJUST, fjust_length ); return ( *(int (*)( INTEGER(grfcon), CHARACTER(LTEXT), REAL(x), REAL(y), CHARACTER(LJUST), REAL(upx), REAL(upy) TRAIL(ftext) TRAIL(fjust) ) ) this->grffun[ AST__GTEXT ])( INTEGER_ARG(&GRFCON), CHARACTER_ARG(LTEXT), REAL_ARG(&x), REAL_ARG(&y), CHARACTER_ARG(LJUST), REAL_ARG(&upx), REAL_ARG(&upy) TRAIL_ARG(ftext) TRAIL_ARG(fjust) ); } static int FGCapWrapper( AstPlot *this, int cap, int value ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)( INTEGER(grfcon), INTEGER(cap), INTEGER(value) ) ) this->grffun[ AST__GCAP ])( INTEGER_ARG(&GRFCON), INTEGER_ARG(&cap), INTEGER_ARG(&value) ); } static int FGTxExtWrapper( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy, float *xb, float *yb ) { DECLARE_CHARACTER(LTEXT,MXSTRLEN); DECLARE_CHARACTER(LJUST,MXSTRLEN); int ftext_length; int fjust_length; F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); ftext_length = strlen( text ); if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; astStringExport( text, LTEXT, ftext_length ); fjust_length = strlen( just ); if( fjust_length > LJUST_length ) fjust_length = LJUST_length; astStringExport( just, LJUST, fjust_length ); return ( *(int (*)( INTEGER(grfcon), CHARACTER(LTEXT), REAL(x), REAL(y), CHARACTER(LJUST), REAL(upx), REAL(upy), REAL_ARRAY(xb), REAL_ARRAY(yb) TRAIL(ftext) TRAIL(fjust) ) ) this->grffun[ AST__GTXEXT ])( INTEGER_ARG(&GRFCON), CHARACTER_ARG(LTEXT), REAL_ARG(&x), REAL_ARG(&y), CHARACTER_ARG(LJUST), REAL_ARG(&upx), REAL_ARG(&upy), REAL_ARRAY_ARG(xb), REAL_ARRAY_ARG(yb) TRAIL_ARG(ftext) TRAIL_ARG(fjust) ); } static int FGQchWrapper( AstPlot *this, float *chv, float *chh ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)( INTEGER(grfcon), REAL(chv), REAL(chh) ) ) this->grffun[ AST__GQCH ])( INTEGER_ARG(&GRFCON), REAL_ARG(chv), REAL_ARG(chh) ); } static int FGScalesWrapper( AstPlot *this, float *alpha, float *beta ) { F77_INTEGER_TYPE(GRFCON); int *status = astGetStatusPtr; if ( !astOK ) return 0; GRFCON = astP2I( astGrfConID( this ) ); return ( *(int (*)( INTEGER(grfcon), REAL(alpha), REAL(beta) ) ) this->grffun[ AST__GSCALES ])( INTEGER_ARG(&GRFCON), REAL_ARG(alpha), REAL_ARG(beta) ); } /* NO_CHAR_FUNCTION indicates that the f77.h method of returning a character result doesn't work, so add an extra argument instead and wrap this function up in a normal FORTRAN 77 function (in the file plot.f). */ #if NO_CHAR_FUNCTION F77_SUBROUTINE(ast_stripescapes_a)( CHARACTER(RESULT), #else F77_SUBROUTINE(ast_stripescapes)( CHARACTER_RETURN_VALUE(RESULT), #endif CHARACTER(TEXT), INTEGER(STATUS) #if NO_CHAR_FUNCTION TRAIL(RESULT) #endif TRAIL(TEXT) ) { GENPTR_CHARACTER(RESULT) GENPTR_CHARACTER(TEXT) char *text; const char *result; int i; astAt( "AST_STRIPESCAPES", NULL, 0 ); astWatchSTATUS( text = astString( TEXT, TEXT_length ); result = astStripEscapes( text ); i = 0; if ( astOK ) { /* Copy result */ for ( ; result[ i ] && i < RESULT_length; i++ ) { RESULT[ i ] = result[ i ]; } } while ( i < RESULT_length ) RESULT[ i++ ] = ' '; /* Pad with blanks */ astFree( text ); ) } F77_LOGICAL_FUNCTION(ast_getgrfcontext)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_INTEGER_TYPE(RESULT); astAt( "AST_GETGRFCONTEXT", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astGetGrfContext( astI2P( *THIS ) ) ); ) return RESULT; } ./ast-7.3.3/region.c0000644000175000017500000156156412262533650012613 0ustar olesoles/* *class++ * Name: * Region * Purpose: * Represents a region within a coordinate system. * Constructor Function: * None. * Description: * This class provides the basic facilities for describing a region within * a specified coordinate system. However, the Region class does not * have a constructor function of its own, as it is simply a container * class for a family of specialised sub-classes such as Circle, Box, etc, * which implement Regions with particular shapes. * * All sub-classes of Region require a Frame to be supplied when the Region * is created. This Frame describes the coordinate system in which the * Region is defined, and is referred to as the "encapsulated Frame" below. * Constructors will also typically required one or more positions to be * supplied which define the location and extent of the region. These * positions must be supplied within the encapsulated Frame. * * The Region class inherits from the Frame class, and so a Region can be * supplied where-ever a Frame is expected. In these cases, supplying a * Region is equivalent to supplying a reference to its encapsulated Frame. * Thus all the methods of the Frame class can be used on the Region class. * For instance, the c astFormat function f AST_FORMAT routine * may be used on a Region to format an axis value. * * In addition, since Frame inherits from Mapping, a Region is also a sort * of Mapping. Transforming positions by supplying a Region to one of the c astTran functions f AST_TRAN routines * is the way to determine if a given position is inside or outside the * Region. When used as a Mapping, most classes of Frame are equivalent to * a UnitMap. However, the Region class modifies this behaviour so that a * Region acts like a UnitMap only for input positions which are within the * area represented by the Region. Input positions which are outside the * area produce bad output values (i.e. the output values are equal to * AST__BAD). This behaviour is the same for both the forward and the * inverse transformation. In this sense the "inverse transformation" * is not a true inverse of the forward transformation, since applying * the forward transformation to a point outside the Region, and then * applying the inverse transformation results, in a set of AST__BAD axis * values rather than the original axis values. If required, the c astRemoveRegions f AST_REMOVEREGIONS * function can be used to remove the "masking" effect of any Regions * contained within a compound Mapping or FrameSet. It does this by * replacing each Region with a UnitMap or equivalent Frame (depending * on the context in which the Region is used). * * If the coordinate system represented by the Region is changed (by * changing the values of one or more of the attribute which the Region * inherits from its encapsulated Frame), the area represented by * the Region is mapped into the new coordinate system. For instance, let's * say a Circle (a subclass of Region) is created, a SkyFrame being * supplied to the constructor so that the Circle describes a circular * area on the sky in FK4 equatorial coordinates. Since Region inherits * from Frame, the Circle will have a System attribute and this attribute * will be set to "FK4". If the System attribute of the Region is then * changed from FK4 to FK5, the circular area represented by the Region * will automatically be mapped from the FK4 system into the FK5 system. * In general, changing the coordinate system in this way may result in the * region changing shape - for instance, a circle may change into an * ellipse if the transformation from the old to the new coordinate system * is linear but with different scales on each axis. Thus the specific * class of a Region cannot be used as a guarantee of the shape in any * particular coordinate system. If the c astSimplify function f AST_SIMPLIFY routine * is used on a Region, it will endeavour to return a new Region of * a sub-class which accurately describes the shape in the current * coordinate system of the Region (but this may not always be possible). * * It is possible to negate an existing Region so that it represents all * areas of the encapsulated Frame except for the area specified when * the Region was created. * Inheritance: * The Region class inherits from the Frame class. * Attributes: * In addition to those attributes common to all Frames, every * Region also has the following attributes: * * - Adaptive: Should the area adapt to changes in the coordinate system? * - Negated: Has the original region been negated? * - Closed: Should the boundary be considered to be inside the region? * - MeshSize: Number of points used to create a mesh covering the Region * - FillFactor: Fraction of the Region which is of interest * - Bounded: Is the Region bounded? * * Every Region also inherits any further attributes that belong * to the encapsulated Frame, regardless of that Frame's class. (For * example, the Equinox attribute, defined by the SkyFrame class, is * inherited by any Region which represents a SkyFrame.) * Functions: c In addition to those functions applicable to all Frames, the c following functions may also be applied to all Regions: f In addition to those routines applicable to all Frames, the f following routines may also be applied to all Regions: * c - astGetRegionBounds: Get the bounds of a Region f - AST_GETREGIONBOUNDS: Get the bounds of a Region c - astGetRegionFrame: Get a copy of the Frame represent by a Region f - AST_GETREGIONFRAME: Get a copy of the Frame represent by a Region f - astGetRegionFrameSet: Get a copy of the Frameset encapsulated by a Region f - AST_GETREGIONFRAMESET: Get a copy of the Frameset encapsulated by a Region c - astGetRegionMesh: Get a mesh of points covering a Region f - AST_GETREGIONMESH: Get a mesh of points covering a Region c - astGetRegionPoints: Get the positions that define a Region f - AST_GETREGIONPOINTS: Get the positions that define a Region c - astGetUnc: Obtain uncertainty information from a Region f - AST_GETUNC: Obtain uncertainty information from a Region c - astMapRegion: Transform a Region into a new coordinate system f - AST_MAPREGION: Transform a Region into a new coordinate system c - astNegate: Toggle the value of the Negated attribute f - AST_NEGATE: Toggle the value of the Negated attribute c - astOverlap: Determines the nature of the overlap between two Regions f - AST_OVERLAP: Determines the nature of the overlap between two Regions c - astMask: Mask a region of a data grid f - AST_MASK: Mask a region of a data grid c - astSetUnc: Associate a new uncertainty with a Region f - AST_SETUNC: Associate a new uncertainty with a Region c - astShowMesh: Display a mesh of points on the surface of a Region f - AST_SHOWMESH: Display a mesh of points on the surface of a Region * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (STARLINK) * History: * 3-DEC-2003 (DSB): * Original version. * 12-MAY-2005 (DSB): * Override astNormBox method. * 12-AUG-2005 (DSB): * Override ObsLat and ObsLon accessor methods. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 2-MAR-2006 (DSB): * Changed AST_LONG_DOUBLE to HAVE_LONG_DOUBLE. * 14-MAR-2006 (DSB): * Added astGetRefFS. * 28-MAY-2007 (DSB): * - Added protected function astBndMesh. * 14-JAN-2009 (DSB): * Override the astIntersect method. * 20-JAN-2009 (DSB): * Change astPickAxes so that it returns a Region rather than a * Frame if possible. This included adding method astRegBasePick. * 9-FEB-2009 (DSB): * Move PointList methods astGetEnclosure and astSetEnclosure to * Region. * 18-FEB-2009 (DSB): * Remove methods astGetEnclosure and astSetEnclosure. * 15-JUN-2009 (DSB): * Modify MapRegion to use FrameSets properly. * 18-JUN-2009 (DSB): * Override ObsAlt accessor methods. * 7-SEP-2009 (DSB): * Fix astMask to avoid reading variance values from the data array. * 8-SEP-2009 (DSB): * Fix bugs in astOverlap that could result in wrong results if * either region is unbounded. * 4-JAN-2010 (DSB): * Fix bug in GetRegionBounds (it was assumed implicitly that the base * Frame had the same number of axes as the current Frame). * 18-MAR-2011 (DSB): * Added astGetRegionMesh public method. * 22-MAR-2011 (DSB): * Improve uniformity of points produced by astRegBaseGrid method. * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. * 17-MAY-2011 (DSB): * In RegBaseGrid, accept the final try even if it is not within 5% * of the required meshsize. * 27-APR-2012 (DSB): * Store a negated copy of itself with each Region. Changing the Negated * attribute of a Region causes the cached information to be reset, and * re-calculating it can be an expensive operation. So instead of changing * "Negatated" in "this", access the negated copy of "this" using the * new protected method astGetNegation. * 7-JUN-2012 (DSB): * Added protected astRegSplit method to split a Region into disjoint * component regions. * 15-JUN-2012 (DSB): * Guard against division by zero in RegBase Grid if "ipr" is zero. * 7-NOV-2013 (DSB): * Added method astGetRegionFrameSet. *class-- * Implementation Notes: * - All sub-classes must over-ride the following abstract methods declared * in this class: astRegBaseBox, astRegBaseMesh, astRegPins, astRegCentre. * They must also extend the astTransform method. In addition they should * usually extend astSimplify. */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Region /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Value for Ident attribute of of an encapsulated FrameSet which indicates that it is a dummy FrameSet (see astRegDummy). */ #define DUMMY_FS "ASTREGION-DUMMY" /* * Name: * MAKE_CLEAR * Purpose: * Define a function to clear an attribute value for a Region. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_CLEAR(attribute) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Clear( AstFrame *this ) * * that clears the value of a specified attribute for the encapsulated * FrameSet within a Region (this). This function is intended to over-ride * the astClear method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. */ /* Define the macro. */ #define MAKE_CLEAR(attribute) \ static void Clear##attribute( AstFrame *this_frame, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Obtain a pointer to the encapsulated FrameSet and invoke its \ astClear method. The protected astClear##attribute method is not used \ because we want the current Frame of the FrameSet tp be re-mapped if \ necessary. */ \ astClear( this->frameset, #attribute ); \ } /* * Name: * MAKE_CLEAR_AXIS * Purpose: * Define a function to clear an attribute value for a Region axis. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_CLEAR_AXIS(attribute) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Clear( AstFrame *this, int axis ) * * that clears the value of a specified attribute for an axis of * the encapsulated FrameSet within a Region (this). This function is * intended to over-ride the astClear method inherited * from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. */ /* Define the macro. */ #define MAKE_CLEAR_AXIS(attribute) \ static void Clear##attribute( AstFrame *this_frame, int axis, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ char buf[100]; /* Buffer for attribute name */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Validate the axis index supplied. */ \ (void) astValidateAxis( this, axis, 1, "astClear" #attribute ); \ \ /* We use the public astSetx method rather than the protected \ astSet#attribute method so that the current Frame in the encapsulated \ FrameSet will be re-mapped if necessary. Construct the attribute name. */ \ sprintf( buf, "%s(%d)", #attribute, axis + 1 ); \ \ /* Obtain a pointer to the Region's encapsulated FrameSet and invoke its \ astClear method. The protected astClear#attribute method is notused \ since we want the current Frame of the encapsulated FrameSet to be \ remapped if required. */ \ astClear( this->frameset, buf ); \ } /* * Name: * MAKE_GET * Purpose: * Define a function to get an attribute value for a Region. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_GET(attribute,type) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static Get( AstFrame *this ) * * that gets the value of a specified attribute for the encapsulated * FrameSet of a Region (this). This function is intended to over-ride * the astGet method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. */ /* Define the macro. */ #define MAKE_GET(attribute,type) \ static type Get##attribute( AstFrame *this_frame, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ type result; /* Value to return */ \ \ /* Check the global error status. */ \ if ( !astOK ) return (type) 0; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Obtain a pointer to the encapsulated FrameSet and invoke its \ astGet method. */ \ result = astGet##attribute( this->frameset ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = (type) 0; \ \ /* Return the result. */ \ return result; \ } /* * Name: * MAKE_GET_AXIS * Purpose: * Define a function to get an attribute value for a Region axis. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_GET_AXIS(attribute,type) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static Get( AstFrame *this, int axis ) * * that gets the value of a specified attribute for an axis of the * encapsulated FrameSet within a Region (this). This function is intended * to over-ride the astGet method inherited from the Frame * class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. */ /* Define the macro. */ #define MAKE_GET_AXIS(attribute,type) \ static type Get##attribute( AstFrame *this_frame, int axis, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ type result; /* Value to return */ \ \ /* Check the global error status. */ \ if ( !astOK ) return (type) 0; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Validate the axis index supplied. */ \ (void) astValidateAxis( this, axis, 1, "astGet" #attribute ); \ \ /* Obtain a pointer to the Region's encapsulated FrameSet and invoke its \ astGet method. */ \ result = astGet##attribute( this->frameset, axis ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = (type) 0; \ \ /* Return the result. */ \ return result; \ } /* * Name: * MAKE_SET_SYSTEM * Purpose: * Define a function to set a System attribute value for a Region. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_SET_SYSTEM(attribute) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Set( AstFrame *this, AstSystemType value ) * * that sets the value of a specified attribute for the encapsulated * FrameSet of a Region (this). This function is intended to over-ride the * astSet method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. */ /* Define the macro. */ #define MAKE_SET_SYSTEM(attribute) \ static void Set##attribute( AstFrame *this_frame, AstSystemType value, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ const char *text; /* Pointer to system string */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Convert the supplied value to a string using the astSystemString method of the current Frame in the encapsulated FrameSet. */ \ text = astSystemString( this->frameset, value ); \ \ /* Set the value by invoking the public astSetC method on the encapusulated \ FrameSet. This ensures that the current Frame of the encapsulated \ FrameSet is re-mapped if necessary. */ \ astSetC( this->frameset, #attribute, text ); \ } /* * Name: * MAKE_SET * Purpose: * Define a function to set an attribute value for a Region. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_SET(attribute,type,x) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Set( AstFrame *this, value ) * * that sets the value of a specified attribute for the encapsulated * FrameSet of a Region (this). This function is intended to over-ride the * astSet method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. * x * The single character code for the astSetx function for the given C * type. */ /* Define the macro. */ #define MAKE_SET(attribute,type,x) \ static void Set##attribute( AstFrame *this_frame, type value, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Set the value by invoking the public astSetx method on the encapusulated \ FrameSet. This ensures that the current Frame of the encapsulated \ FrameSet is re-mapped if necessary. */ \ astSet##x( this->frameset, #attribute, value ); \ } /* * Name: * MAKE_SET_AXIS * Purpose: * Define a function to set an attribute value for a Region axis. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_SET_AXIS(attribute,type,x) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Set( AstFrame *this, int axis, value ) * * that sets the value of a specified attribute for an axis of the * encapsulated FrameSet within a Region (this). This function is intended * to over-ride the astSet method inherited from the Frame * class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. * x * The single character code for the astSetx function for the given C * type. */ /* Define the macro. */ #define MAKE_SET_AXIS(attribute,type,x) \ static void Set##attribute( AstFrame *this_frame, int axis, type value, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ char buf[100]; /* Buffer for attribute name */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Validate the axis index supplied. */ \ (void) astValidateAxis( this, axis, 1, "astSet" #attribute ); \ \ /* We use the public astSetx method rather than the protected \ astSet#attribute method so that the current Frame in the encapsulated \ FrameSet will be re-mapped if necessary. Construct the attribute name. */ \ sprintf( buf, "%s(%d)", #attribute, axis + 1 ); \ \ /* Obtain a pointer to the Region's encapsulated FrameSet and invoke its \ astSet method. */ \ astSet##x( this->frameset, buf, value ); \ } /* * Name: * MAKE_TEST * Purpose: * Define a function to test if an attribute value is set for a Region. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_TEST(attribute) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static int Test( AstFrame *this ) * * that returns a boolean result (0 or 1) to indicate if the value * of a specified attribute for the encapsulated FrameSet within a * Region (this) is set. This function is intended to over-ride the * astTest method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. */ /* Define the macro. */ #define MAKE_TEST(attribute) \ static int Test##attribute( AstFrame *this_frame, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to Region structure */ \ int result; /* Result to return */ \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Obtain a pointer to the Region's encapsulated FrameSet and invoke its \ astTest method. */ \ result = astTest##attribute( this->frameset ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } /* * Name: * MAKE_TEST_AXIS * Purpose: * Define a function to test if an attribute value is set for a Region * axis. * Type: * Private macro. * Synopsis: * #include "region.h" * MAKE_TEST_AXIS(attribute) * Class Membership: * Defined by the Region class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static int Test( AstFrame *this, int axis ) * * that returns a boolean result (0 or 1) to indicate if the value * of a specified attribute for an axis of the encapsulated FrameSet * within a Region (this) is set. This function is intended to over-ride * the astTest method inherited from the Frame class. * Parameters: * attribute * Name of the attribute, as it appears in the function name. */ /* Define the macro. */ #define MAKE_TEST_AXIS(attribute) \ static int Test##attribute( AstFrame *this_frame, int axis, int *status ) { \ \ /* Local Variables: */ \ AstRegion *this; /* Pointer to the Region structure */ \ int result; /* Value to return */ \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Obtain a pointer to the Region structure. */ \ this = (AstRegion *) this_frame; \ \ /* Validate the axis index supplied. */ \ (void) astValidateAxis( this, axis, 1, "astTest" #attribute ); \ \ /* Obtain a pointer to the Region's encapsulated FrameSet and invoke its \ astTest method. */ \ result = astTest##attribute( this->frameset, axis ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "mapping.h" /* Coordinate Mappings */ #include "unitmap.h" /* Unit Mappings */ #include "permmap.h" /* Coordinate permutation Mappings */ #include "cmpmap.h" /* Compound Mappings */ #include "frame.h" /* Parent Frame class */ #include "frameset.h" /* Interconnected coordinate systems */ #include "region.h" /* Interface definition for this class */ #include "circle.h" /* Circular regions */ #include "box.h" /* Box regions */ #include "cmpregion.h" /* Compound regions */ #include "ellipse.h" /* Elliptical regions */ #include "pointset.h" /* Sets of points */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static int (* parent_getusedefs)( AstObject *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Region) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(Region,Class_Init) #define class_vtab astGLOBAL(Region,Class_Vtab) #define getattrib_buff astGLOBAL(Region,GetAttrib_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstRegionVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* Prototypes for Private Member Functions. */ /* ======================================== */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ static int MaskLD( AstRegion *, AstMapping *, int, int, const int[], const int ubnd[], long double [], long double, int * ); #endif static int MaskB( AstRegion *, AstMapping *, int, int, const int[], const int[], signed char[], signed char, int * ); static int MaskD( AstRegion *, AstMapping *, int, int, const int[], const int[], double[], double, int * ); static int MaskF( AstRegion *, AstMapping *, int, int, const int[], const int[], float[], float, int * ); static int MaskI( AstRegion *, AstMapping *, int, int, const int[], const int[], int[], int, int * ); static int MaskL( AstRegion *, AstMapping *, int, int, const int[], const int[], long int[], long int, int * ); static int MaskS( AstRegion *, AstMapping *, int, int, const int[], const int[], short int[], short int, int * ); static int MaskUB( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned char[], unsigned char, int * ); static int MaskUI( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned int[], unsigned int, int * ); static int MaskUL( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned long int[], unsigned long int, int * ); static int MaskUS( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned short int[], unsigned short int, int * ); static AstAxis *GetAxis( AstFrame *, int, int * ); static AstFrame *GetRegionFrame( AstRegion *, int * ); static AstFrameSet *GetRegionFrameSet( AstRegion *, int * ); static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * ); static AstFrame *RegFrame( AstRegion *, int * ); static AstFrameSet *Conv( AstFrameSet *, AstFrameSet *, int * ); static AstFrameSet *Convert( AstFrame *, AstFrame *, const char *, int * ); static AstFrameSet *ConvertX( AstFrame *, AstFrame *, const char *, int * ); static AstFrameSet *FindFrame( AstFrame *, AstFrame *, const char *, int * ); static AstFrameSet *GetRegFS( AstRegion *, int * ); static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * ); static AstMapping *RegMapping( AstRegion *, int * ); static AstMapping *RemoveRegions( AstMapping *, int * ); static AstMapping *Simplify( AstMapping *, int * ); static AstObject *Cast( AstObject *, AstObject *, int * ); static AstPointSet *BTransform( AstRegion *, AstPointSet *, int, AstPointSet *, int * ); static AstPointSet *BndBaseMesh( AstRegion *, double *, double *, int * ); static AstPointSet *BndMesh( AstRegion *, double *, double *, int * ); static AstPointSet *GetSubMesh( int *, AstPointSet *, int * ); static AstPointSet *RegBaseGrid( AstRegion *, int * ); static AstPointSet *RegBaseMesh( AstRegion *, int * ); static AstPointSet *RegGrid( AstRegion *, int * ); static AstPointSet *RegMesh( AstRegion *, int * ); static AstPointSet *RegTransform( AstRegion *, AstPointSet *, int, AstPointSet *, AstFrame **, int * ); static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * ); static AstRegion *MapRegion( AstRegion *, AstMapping *, AstFrame *, int * ); static AstRegion *RegBasePick( AstRegion *, int, const int *, int * ); static AstRegion **RegSplit( AstRegion *, int *, int * ); static AstSystemType SystemCode( AstFrame *, const char *, int * ); static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * ); static const char *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * ); static const char *Format( AstFrame *, int, double, int * ); static const char *SystemString( AstFrame *, AstSystemType, int * ); static const int *GetPerm( AstFrame *, int * ); static double *RegCentre( AstRegion *, double *, double **, int, int, int * ); static double Angle( AstFrame *, const double[], const double[], const double[], int * ); static double AxAngle( AstFrame *, const double[], const double[], int, int * ); static double AxDistance( AstFrame *, int, double, double, int * ); static double AxOffset( AstFrame *, int, double, double, int * ); static double Distance( AstFrame *, const double[], const double[], int * ); static double Gap( AstFrame *, int, double, int *, int * ); static double Offset2( AstFrame *, const double[2], double, double, double[2], int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetNaxes( AstFrame *, int * ); static int GetObjSize( AstObject *, int * ); static int GetUseDefs( AstObject *, int * ); static int IsUnitFrame( AstFrame *, int * ); static int LineContains( AstFrame *, AstLineDef *, int, double *, int * ); static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int Overlap( AstRegion *, AstRegion *, int * ); static int OverlapX( AstRegion *, AstRegion *, int * ); static int RegDummyFS( AstRegion *, int * ); static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int RegTrace( AstRegion *, int, double *, double **, int * ); static int Unformat( AstFrame *, int, const char *, double *, int * ); static int ValidateAxis( AstFrame *, int, int, const char *, int * ); static void CheckPerm( AstFrame *, const int *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void GetRegionBounds( AstRegion *, double *, double *, int * ); static void GetRegionBounds2( AstRegion *, double *, double *, int * ); static void GetRegionMesh( AstRegion *, int, int, int, int *, double *, int * ); static void GetRegionPoints( AstRegion *, int, int, int *, double *, int * ); static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * ); static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * ); static void MatchAxes( AstFrame *, AstFrame *, int *, int * ); static void MatchAxesX( AstFrame *, AstFrame *, int *, int * ); static void Negate( AstRegion *, int * ); static void Norm( AstFrame *, double[], int * ); static void NormBox( AstFrame *, double[], double[], AstMapping *, int * ); static void Offset( AstFrame *, const double[], const double[], double, double[], int * ); static void Overlay( AstFrame *, const int *, AstFrame *, int * ); static void PermAxes( AstFrame *, const int[], int * ); static void RegBaseBox( AstRegion *, double *, double *, int * ); static void RegBaseBox2( AstRegion *, double *, double *, int * ); static void RegClearAttrib( AstRegion *, const char *, char **, int * ); static void RegOverlay( AstRegion *, AstRegion *, int, int * ); static void RegSetAttrib( AstRegion *, const char *, char **, int * ); static void ReportPoints( AstMapping *, int, AstPointSet *, AstPointSet *, int * ); static void ResetCache( AstRegion *, int * ); static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); static void SetAxis( AstFrame *, int, AstAxis *, int * ); static void SetRegFS( AstRegion *, AstFrame *, int * ); static void ShowMesh( AstRegion *, int, const char *, int * ); static void ValidateAxisSelection( AstFrame *, int, const int *, const char *, int * ); static AstRegion *GetNegation( AstRegion *, int * ); static int GetBounded( AstRegion *, int * ); static AstRegion *GetDefUnc( AstRegion *, int * ); static AstRegion *GetUncFrm( AstRegion *, int, int * ); static AstRegion *GetUnc( AstRegion *, int, int * ); static int TestUnc( AstRegion *, int * ); static void ClearUnc( AstRegion *, int * ); static void SetUnc( AstRegion *, AstRegion *, int * ); static const char *GetDomain( AstFrame *, int * ); static int TestDomain( AstFrame *, int * ); static void ClearDomain( AstFrame *, int * ); static void SetDomain( AstFrame *, const char *, int * ); static const char *GetFormat( AstFrame *, int, int * ); static int TestFormat( AstFrame *, int, int * ); static void ClearFormat( AstFrame *, int, int * ); static void SetFormat( AstFrame *, int, const char *, int * ); static const char *GetLabel( AstFrame *, int, int * ); static int TestLabel( AstFrame *, int, int * ); static void ClearLabel( AstFrame *, int, int * ); static void SetLabel( AstFrame *, int, const char *, int * ); static const char *GetSymbol( AstFrame *, int, int * ); static int TestSymbol( AstFrame *, int, int * ); static void ClearSymbol( AstFrame *, int, int * ); static void SetSymbol( AstFrame *, int, const char *, int * ); static const char *GetTitle( AstFrame *, int * ); static void SetTitle( AstFrame *, const char *, int * ); static void ClearTitle( AstFrame *, int * ); static int TestTitle( AstFrame *, int * ); static const char *GetUnit( AstFrame *, int, int * ); static int TestUnit( AstFrame *, int, int * ); static void ClearUnit( AstFrame *, int, int * ); static void SetUnit( AstFrame *, int, const char *, int * ); static int GetDigits( AstFrame *, int * ); static int TestDigits( AstFrame *, int * ); static void ClearDigits( AstFrame *, int * ); static void SetDigits( AstFrame *, int, int * ); static int GetDirection( AstFrame *, int, int * ); static int TestDirection( AstFrame *, int, int * ); static void ClearDirection( AstFrame *, int, int * ); static void SetDirection( AstFrame *, int, int, int * ); static int GetActiveUnit( AstFrame *, int * ); static int TestActiveUnit( AstFrame *, int * ); static void SetActiveUnit( AstFrame *, int, int * ); static int GetMatchEnd( AstFrame *, int * ); static int TestMatchEnd( AstFrame *, int * ); static void ClearMatchEnd( AstFrame *, int * ); static void SetMatchEnd( AstFrame *, int, int * ); static int GetMaxAxes( AstFrame *, int * ); static int TestMaxAxes( AstFrame *, int * ); static void ClearMaxAxes( AstFrame *, int * ); static void SetMaxAxes( AstFrame *, int, int * ); static int GetMinAxes( AstFrame *, int * ); static int TestMinAxes( AstFrame *, int * ); static void ClearMinAxes( AstFrame *, int * ); static void SetMinAxes( AstFrame *, int, int * ); static int GetPermute( AstFrame *, int * ); static int TestPermute( AstFrame *, int * ); static void ClearPermute( AstFrame *, int * ); static void SetPermute( AstFrame *, int, int * ); static int GetPreserveAxes( AstFrame *, int * ); static int TestPreserveAxes( AstFrame *, int * ); static void ClearPreserveAxes( AstFrame *, int * ); static void SetPreserveAxes( AstFrame *, int, int * ); static double GetBottom( AstFrame *, int, int * ); static int TestBottom( AstFrame *, int, int * ); static void ClearBottom( AstFrame *, int, int * ); static void SetBottom( AstFrame *, int, double, int * ); static double GetTop( AstFrame *, int, int * ); static int TestTop( AstFrame *, int, int * ); static void ClearTop( AstFrame *, int, int * ); static void SetTop( AstFrame *, int, double, int * ); static double GetEpoch( AstFrame *, int * ); static int TestEpoch( AstFrame *, int * ); static void ClearEpoch( AstFrame *, int * ); static void SetEpoch( AstFrame *, double, int * ); static double GetObsAlt( AstFrame *, int * ); static int TestObsAlt( AstFrame *, int * ); static void ClearObsAlt( AstFrame *, int * ); static void SetObsAlt( AstFrame *, double, int * ); static double GetObsLat( AstFrame *, int * ); static int TestObsLat( AstFrame *, int * ); static void ClearObsLat( AstFrame *, int * ); static void SetObsLat( AstFrame *, double, int * ); static double GetObsLon( AstFrame *, int * ); static int TestObsLon( AstFrame *, int * ); static void ClearObsLon( AstFrame *, int * ); static void SetObsLon( AstFrame *, double, int * ); static AstSystemType GetSystem( AstFrame *, int * ); static int TestSystem( AstFrame *, int * ); static void ClearSystem( AstFrame *, int * ); static void SetSystem( AstFrame *, AstSystemType, int * ); static AstSystemType GetAlignSystem( AstFrame *, int * ); static int TestAlignSystem( AstFrame *, int * ); static void ClearAlignSystem( AstFrame *, int * ); static void SetAlignSystem( AstFrame *, AstSystemType, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static int GetNegated( AstRegion *, int * ); static int TestNegated( AstRegion *, int * ); static void ClearNegated( AstRegion *, int * ); static void SetNegated( AstRegion *, int, int * ); static int GetClosed( AstRegion *, int * ); static int TestClosed( AstRegion *, int * ); static void ClearClosed( AstRegion *, int * ); static void SetClosed( AstRegion *, int, int * ); static int GetMeshSize( AstRegion *, int * ); static int TestMeshSize( AstRegion *, int * ); static void ClearMeshSize( AstRegion *, int * ); static void SetMeshSize( AstRegion *, int, int * ); static double GetFillFactor( AstRegion *, int * ); static int TestFillFactor( AstRegion *, int * ); static void ClearFillFactor( AstRegion *, int * ); static void SetFillFactor( AstRegion *, double, int * ); static int GetRegionFS( AstRegion *, int * ); static int TestRegionFS( AstRegion *, int * ); static void ClearRegionFS( AstRegion *, int * ); static void SetRegionFS( AstRegion *, int, int * ); static int GetAdaptive( AstRegion *, int * ); static int TestAdaptive( AstRegion *, int * ); static void ClearAdaptive( AstRegion *, int * ); static void SetAdaptive( AstRegion *, int, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static const char *Abbrev( AstFrame *this_frame, int axis, const char *fmt, const char *str1, const char *str2, int *status ) { /* * Name: * Abbrev * Purpose: * Abbreviate a formatted Region axis value by skipping leading fields. * Type: * Private function. * Synopsis: * #include "region.h" * const char *Abbrev( AstFrame *this, int axis, const char *fmt, * const char *str1, const char *str2, int *status ) * Class Membership: * Region member function (over-rides the protected astAbbrev * method inherited from the Frame class). * Description: * This function compares two Region axis values that have been * formatted (using astFormat) and determines if they have any * redundant leading fields (i.e. leading fields in common which * can be suppressed when tabulating the values or plotting them on * the axis of a graph). * Parameters: * this * Pointer to the Region * axis * The number of the Region axis for which the values have * been formatted (axis numbering starts at zero for the first * axis). * fmt * Pointer to a constant null-terminated string containing the * format specification used to format the two values. * str1 * Pointer to a constant null-terminated string containing the * first formatted value. * str1 * Pointer to a constant null-terminated string containing the * second formatted value. * status * Pointer to the inherited status variable. * Returned Value: * A pointer into the "str2" string which locates the first * character in the first field that differs between the two * formatted values. * * If the two values have no leading fields in common, the returned * value will point at the start of string "str2". If the two * values are equal, it will point at the terminating null at the * end of this string. * Notes: * - This function assumes that the format specification used was * the same when both values were formatted and that they both * apply to the same Region axis. * - A pointer to the start of "str2" will be returned if this * function is invoked with the global error status set, or if it * should fail for any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ const char *result; /* Pointer value to return */ /* Check the global error status. */ if ( !astOK ) return str2; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astAbbrev" ); /* Obtain a pointer to the Region's current Frame and invoke this Frame's astAbbrev method to perform the processing. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astAbbrev( fr, axis, fmt, str1, str2 ); fr = astAnnul( fr ); /* If an error occurred, clear the result. */ if ( !astOK ) result = str2; /* Return the result. */ return result; } static double Angle( AstFrame *this_frame, const double a[], const double b[], const double c[], int *status ) { /* * Name: * Angle * Purpose: * Calculate the angle subtended by two points at a third point. * Type: * Private function. * Synopsis: * #include "region.h" * double Angle( AstFrame *this, const double a[], const double b[], * const double c[], int *status ) * Class Membership: * Region member function (over-rides the protected astAngle * method inherited from the Frame class). * Description: * This function finds the angle at point B between the line joining points * A and B, and the line joining points C and B. These lines will in fact be * geodesic curves appropriate to the Frame in use. For instance, in * SkyFrame, they will be great circles. * Parameters: * this * Pointer to the Frame. * a * An array of double, with one element for each Frame axis * (Naxes attribute) containing the coordinates of the first point. * b * An array of double, with one element for each Frame axis * (Naxes attribute) containing the coordinates of the second point. * c * An array of double, with one element for each Frame axis * (Naxes attribute) containing the coordinates of the third point. * status * Pointer to the inherited status variable. * Returned Value: * astAngle * The angle in radians, from the line AB to the line CB. If the * Frame is 2-dimensional, it will be in the range $\pm \pi$, * and positive rotation is in the same sense as rotation from * the positive direction of axis 2 to the positive direction of * axis 1. If the Frame has more than 2 axes, a positive value will * always be returned in the range zero to $\pi$. * Notes: * - A value of AST__BAD will also be returned if points A and B are * co-incident, or if points B and C are co-incident. * - A value of AST__BAD will also be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke this Frame's astAngle method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astAngle( fr, a, b, c ); fr = astAnnul( fr ); /* If an error occurred, clear the result. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static double AxAngle( AstFrame *this_frame, const double a[], const double b[], int axis, int *status ) { /* * Name: * AxAngle * Purpose: * Returns the angle from an axis, to a line through two points. * Type: * Private function. * Synopsis: * #include "region.h" * double AxAngle( AstFrame *this, const double a[], const double b[], int axis, int *status ) * Class Membership: * Region member function (over-rides the protected astAxAngle * method inherited from the Frame class). * Description: * This function finds the angle, as seen from point A, between the positive * direction of a specified axis, and the geodesic curve joining point * A to point B. * Parameters: * this * Pointer to the Frame. * a * An array of double, with one element for each Frame axis * (Naxes attribute) containing the coordinates of the first point. * b * An array of double, with one element for each Frame axis * (Naxes attribute) containing the coordinates of the second point. * axis * The number of the Frame axis from which the angle is to be * measured (one-based) * status * Pointer to the inherited status variable. * Returned Value: * The angle in radians, from the positive direction of the * specified axis, to the line AB. If the Frame is 2-dimensional, * it will be in the range $\pm \pi$, and positive rotation is in * the same sense as rotation from the positive direction of axis 2 * to the positive direction of axis 1. If the Frame has more than 2 * axes, a positive value will always be returned in the range zero * to $\pi$. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the require * position angle is undefined. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis - 1, 1, "astAxAngle" ); /* Obtain a pointer to the Region's encapsulated Frame and invoke the astAxAngle method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astAxAngle( fr, a, b, axis ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static double AxDistance( AstFrame *this_frame, int axis, double v1, double v2, int *status ) { /* * Name: * AxDistance * Purpose: * Find the distance between two axis values. * Type: * Private function. * Synopsis: * #include "region.h" * double AxDistance( AstFrame *this, int axis, double v1, double v2, int *status ) * Class Membership: * Region member function (over-rides the protected astAxDistance * method inherited from the Frame class). * Description: * This function returns a signed value representing the axis increment * from axis value v1 to axis value v2. * * For a simple Frame, this is a trivial operation returning the * difference between the two axis values. But for other derived classes * of Frame (such as a SkyFrame) this is not the case. * Parameters: * this * Pointer to the Frame. * axis * The index of the axis to which the supplied values refer. The * first axis has index 1. * v1 * The first axis value. * v2 * The second axis value. * status * Pointer to the inherited status variable. * Returned Value: * The distance between the two axis values. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input vaues has this value. * - A "bad" value will also be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis - 1, 1, "astAxDistance" ); /* Obtain a pointer to the Region's encapsulated Frame and invoke the astAxDistance method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astAxDistance( fr, axis, v1, v2 ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static double AxOffset( AstFrame *this_frame, int axis, double v1, double dist, int *status ) { /* * Name: * AxOffset * Purpose: * Add an increment onto a supplied axis value. * Type: * Private function. * Synopsis: * #include "region.h" * double AxOffset( AstFrame *this, int axis, double v1, double dist, int *status ) * Class Membership: * Region member function (over-rides the protected astAxOffset * method inherited from the Frame class). * Description: * This function returns an axis value formed by adding a signed axis * increment onto a supplied axis value. * * For a simple Frame, this is a trivial operation returning the * sum of the two supplied values. But for other derived classes * of Frame (such as a SkyFrame) this is not the case. * Parameters: * this * Pointer to the Frame. * axis * The index of the axis to which the supplied values refer. The * first axis has index 1. * v1 * The original axis value. * dist * The axis increment to add to the original axis value. * status * Pointer to the inherited status variable. * Returned Value: * The incremented axis value. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input vaues has this value. * - A "bad" value will also be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis - 1, 1, "astAxOffset" ); /* Obtain a pointer to the Region's encapsulated Frame and invoke the astAxOffset method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astAxOffset( fr, axis, v1, dist ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static AstPointSet *BndBaseMesh( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *+ * Name: * astBndBaseMesh * Purpose: * Return a PointSet containing points spread around part of the boundary * of a Region, in the base Frame. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astBndBaseMesh( AstRegion *this, double *lbnd, double *ubnd ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a set of points on the * boundary of the intersection between the supplied Region and the * supplied (current Frame) box. The mesh points refer to the base * Frame. If the boundary of the supplied Region does not intersect the * supplied box, then a PointSet containing a single bad point is * returned. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array holding the lower limits of the axis values * within the required box. Defined in the current Frame of the Region. * ubnd * Pointer to an array holding the upper limits of the axis values * within the required box. Defined in the current Frame of the Region. * Returned Value: * Pointer to the PointSet holding the base Frame mesh. The axis values * in this PointSet will have associated accuracies derived from the * uncertainties which were supplied when the Region was created. * * If the Region does not intersect the supplied box, the returned * PointSet will contain a single point with a value of AST__BAD on * every axis. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables: */ AstBox *box; AstCmpRegion *cmpreg; AstPointSet *result; double **ptr; int ic; int nc; /* Check the local error status. */ if ( !astOK ) return NULL; /* Form a Box describing the required box. */ box = astBox( this, 1, lbnd, ubnd, NULL, "", status ); /* Check there is partial overlap between the Regions.*/ if( astOverlap( this, box ) > 3 ) { /* Form a CmpRegion representing the intersection between the supplied Region and the above box. */ cmpreg = astCmpRegion( this, box, AST__AND, "", status ); /* Get the boundary mesh. */ result = astRegBaseMesh( cmpreg ); /* Free resources. */ cmpreg = astAnnul( cmpreg ); /* If the boundary of the supplied Region does not intersect the box, return a PointSet containing a single bad position. */ } else { nc = astGetNin( this->frameset ); result = astPointSet( 1, nc, "", status ); ptr = astGetPoints( result ); if( ptr ) { for( ic = 0; ic < nc; ic++ ) ptr[ ic ][ 0 ] = AST__BAD; } } /* Free resources. */ box = astAnnul( box ); /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } static AstPointSet *BndMesh( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *+ * Name: * astBndMesh * Purpose: * Return a PointSet containing points spread around part of the boundary * of a Region, in the current Frame. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astBndMesh( AstRegion *this, double *lbnd, double *ubnd ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a set of points on the * boundary of the intersection between the supplied Region and the * supplied box. The points refer to the current Frame of the * encapsulated FrameSet. If the boundary of the supplied Region does * not intersect the supplied box, then a PointSet containing a single * bad point is returned. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array holding the lower limits of the axis values * within the required box. Defined in the current Frame of the Region. * ubnd * Pointer to an array holding the upper limits of the axis values * within the required box. Defined in the current base Frame of the * Region. * Returned Value: * Pointer to the PointSet. The axis values in this PointSet will have * associated accuracies derived from the uncertainties which were * supplied when the Region was created. * * If the Region does not intersect the supplied box, the returned * PointSet will contain a single point with a value of AST__BAD on * every axis. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables: */ AstMapping *map; AstPointSet *ps1; AstPointSet *result; /* Initialise */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* Get the current->base Mapping from the Region. */ map = astGetMapping( this->frameset, AST__CURRENT, AST__BASE ); /* Use astBndBaseMesh to get a mesh of base Frame points within this base Frame bounding box. */ ps1 = astBndBaseMesh( this, lbnd, ubnd ); /* Transform it into the current Frame. */ if( ps1 ) result = astTransform( map, ps1, 0, NULL ); /* Free resources. */ map = astAnnul( map ); ps1 = astAnnul( ps1 ); /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } static AstPointSet *BTransform( AstRegion *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* *+ * Name: * astBTransform * Purpose: * Use a Region to transform a set of points in the base Frame. * Type: * Protected virtual function. * Synopsis: * #include "circle.h" * AstPointSet *astBTransform( AstRegion *this, AstPointSet *in, int forward, AstPointSet *out ) * Class Membership: * Region member function * Description: * This function takes a Region and a set of points within the base * Frame of the Region, and transforms the points by setting axis values * to AST__BAD for all points which are outside the region. Points inside * the region are copied unchanged from input to output. * Parameters: * this * Pointer to the Region. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - This is identical to the astTransform method for a Region except * that the supplied and returned points refer to the base Frame of * the Region, rather than the current Frame. *- */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ int old; /* Origial value of "nomap" flag */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Save the current value of the "nomap" flag for this Region,and then set it. Doing this tells the astRegMapping function (called by astRegTransform) to assume a unit map connects base and current Frame. */ old = this->nomap; this->nomap = 1; /* Invoke the usual astTransform method. The above setting of the "nomap" flag will cause the astTransform method to treat the base Frame as the current Frame. */ result = astTransform( this, in, forward, out ); /* Reset the "nomap" flag. */ this->nomap = old; /* Return a pointer to the output PointSet. */ return result; } static AstObject *Cast( AstObject *this_object, AstObject *obj, int *status ) { /* * Name: * Cast * Purpose: * Cast an Object into an instance of a sub-class. * Type: * Private function. * Synopsis: * #include "region.h" * AstObject *Cast( AstObject *this, AstObject *obj, int *status ) * Class Membership: * Region member function (over-rides the protected astCast * method inherited from the Frame class). * Description: * This function returns a deep copy of an ancestral component of the * supplied object. The required class of the ancestral component is * specified by another object. Specifically, if "this" and "new" are * of the same class, a copy of "this" is returned. If "this" is an * instance of a subclass of "obj", then a copy of the component * of "this" that matches the class of "obj" is returned. Otherwise, * a NULL pointer is returned without error. * Parameters: * this * Pointer to the Object to be cast. * obj * Pointer to an Object that defines the class of the returned Object. * The returned Object will be of the same class as "obj". * Returned Value: * A pointer to the new Object. NULL if "this" is not a sub-class of * "obj", or if an error occurs. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables; */ AstFrame *cfrm; AstObject *new; astDECLARE_GLOBALS int generation_gap; /* Initialise */ new = NULL; /* Check inherited status */ if( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* See how many steps up the class inheritance ladder it is from "obj" to this class (Region). A positive value is returned if Region is a sub-class of "obj". A negative value is returned if "obj" is a sub-class of Region. Zero is returned if "obj" is a Region. AST__COUSIN is returned if "obj" is not on the same line of descent as Region. */ generation_gap = astClassCompare( (AstObjectVtab *) &class_vtab, astVTAB( obj ) ); /* If "obj" is a Region or a sub-class of Region, we can cast by truncating the vtab for "this" so that it matches the vtab of "obJ", and then taking a deep copy of "this". */ if( generation_gap <= 0 && generation_gap != AST__COUSIN ) { new = astCastCopy( this_object, obj ); /* If "obj" is not a Region or a sub-class of Region (e.g. a Frame or some sub-class of Frame), we attempt to cast the current Frame of the encapsulated FrameSet into the class indicated by "obj". */ } else { cfrm = astGetFrame( ((AstRegion *) this_object)->frameset, AST__CURRENT ); new = astCast( cfrm, obj ); cfrm = astAnnul( cfrm ); } /* Return the new pointer. */ return new; } static void CheckPerm( AstFrame *this_frame, const int *perm, const char *method, int *status ) { /* * Name: * CheckPerm * Purpose: * Check that an array contains a valid permutation. * Type: * Private function. * Synopsis: * #include "region.h" * void CheckPerm( AstFrame *this, const int *perm, const char *method, int *status ) * Class Membership: * Region member function (over-rides the protected astCheckPerm * method inherited from the Frame class). * Description: * This function checks the validity of a permutation array that * will be used to permute the order of a Frame's axes. If the * permutation specified by the array is not valid, an error is * reported and the global error status is set. Otherwise, the * function returns without further action. * Parameters: * this * Pointer to the Frame. * perm * Pointer to an array of integers with the same number of * elements as there are axes in the Frame. For each axis, the * corresponding integer gives the (zero based) axis index to be * used to identify the information for that axis (using the * un-permuted axis numbering). To be valid, the integers in * this array should therefore all lie in the range zero to * (naxes-1) inclusive, where "naxes" is the number of Frame * axes, and each value should occur exactly once. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate a permutation array. This method name is used * solely for constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - Error messages issued by this function refer to the external * (public) numbering system used for axes (which is one-based), * whereas zero-based axis indices are used internally. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke this Frame's astCheckPerm method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astCheckPerm( fr, perm, method ); fr = astAnnul( fr ); } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Region member function (over-rides the astClearAttrib protected * method inherited from the Frame class). * Description: * This function clears the value of a specified attribute for a * Region, so that the default value will subsequently be used. * Parameters: * this * Pointer to the Region. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* Check the attribute name and clear the appropriate attribute. */ /* We first handle attributes that apply to the Region as a whole (rather than to the encapsulated FrameSet). */ /* Negated */ /* ------- */ if ( !strcmp( attrib, "negated" ) ) { astClearNegated( this ); /* Closed */ /* ------ */ } else if ( !strcmp( attrib, "closed" ) ) { astClearClosed( this ); /* FillFactor */ /* ---------- */ } else if ( !strcmp( attrib, "fillfactor" ) ) { astClearFillFactor( this ); /* MeshSize */ /* -------- */ } else if ( !strcmp( attrib, "meshsize" ) ) { astClearMeshSize( this ); /* Adaptive */ /* -------- */ } else if ( !strcmp( attrib, "adaptive" ) ) { astClearAdaptive( this ); /* We now check for atttributes of superclasses which apply to the Region as a whole. We do not want to pass these on to the encapsulated FrameSet. */ /* ID. */ /* --- */ } else if ( !strcmp( attrib, "id" ) ) { astClearID( this ); /* Ident. */ /* ------ */ } else if ( !strcmp( attrib, "ident" ) ) { astClearIdent( this ); /* Invert. */ /* ------- */ } else if ( !strcmp( attrib, "invert" ) ) { astClearInvert( this ); /* Report. */ /* ------- */ } else if ( !strcmp( attrib, "report" ) ) { astClearReport( this ); /* If the name was not recognised, test if it matches any of the read-only attributes of this class (including those of all superclasses). If it does, then report an error. */ } else if ( !strcmp( attrib, "class" ) || !strcmp( attrib, "nin" ) || !strcmp( attrib, "nobject" ) || !strcmp( attrib, "nout" ) || !strcmp( attrib, "bounded" ) || !strcmp( attrib, "refcount" ) || !strcmp( attrib, "tranforward" ) || !strcmp( attrib, "traninverse" ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Pass unrecognised attributes on to the Region's encapsulated FrameSet for further interpretation. Do not pass on FrameSet attributes since we pretend to the outside world that the encapsulated FrameSet is actually a Frame. */ } else if ( strcmp( attrib, "base" ) && strcmp( attrib, "current" ) && strcmp( attrib, "nframe" ) ) { /* If the Region is to adapt to coordinate system chanmges, use the public astClear method so that the current Frame in the encapsulated FrameSet will be re-mapped if the attribute changes require it. */ if( astGetAdaptive( this ) ) { astClear( this->frameset, attrib ); /* If the Region is not to adapt to coordinate system chanmges, use the astRegSetAttrib method which assigns the attribute setting to both current and base Frames in the FrameSet without causing any remapping to be performed. */ } else { astRegClearAttrib( this, attrib, NULL ); } } } static AstFrameSet *Conv( AstFrameSet *from, AstFrameSet *to, int *status ){ /* * Name: * Conv * Purpose: * Find Mapping between Frames * Type: * Private function. * Synopsis: * #include "region.h" * AstFrameSet *Conv( AstFrameSet *from, AstFrameSet *to, int *status ); * Class Membership: * Region member function * Description: * This function provides a convenient interface for astConvert. * It is like astConvert except it does not alter the base Frames of * the supplied FrameSets and does not require a Domain list. * Parameters: * from * Pointer to the source FrameSet. * to * Pointer to the source FrameSet. * status * Pointer to the inherited status variable. * Returned Value: * The conversion FrameSet (see astConvert). */ /* Local Variables: */ AstFrameSet *result; /* FrameSet to return */ int from_base; /* Index of original base Frame in "from" */ int to_base; /* Index of original base Frame in "to" */ /* Check the global error status. */ if( !astOK ) return NULL; /* Note the indices of the base Frames in the FrameSets. */ to_base = astGetBase( to ); from_base = astGetBase( from ); /* Invoke astConvert. */ result = astConvert( from, to, "" ); /* Re-instate original base Frames. */ astSetBase( to, to_base ); astSetBase( from, from_base ); /* Return the result. */ return result; } static AstFrameSet *Convert( AstFrame *from, AstFrame *to, const char *domainlist, int *status ) { /* * Name: * Convert * Purpose: * Determine how to convert between two coordinate systems. * Type: * Private function. * Synopsis: * #include "region.h" * AstFrameSet *Convert( AstFrame *from, AstFrame *to, * const char *domainlist, int *status ) * Class Membership: * Region member function (over-rides the public astConvert * method inherited fromm the Frame class). * Description: * This function compares two Regions and determines whether it * is possible to convert between the coordinate systems which * their current Frames represent. If conversion is possible, it * returns a FrameSet which describes the conversion and which may * be used (as a Mapping) to transform coordinate values in either * direction. * Parameters: * from * Pointer to a Region whose current Frame represents the * "source" coordinate system. Note that the Base attribute of * the Region may be modified by this function. * to * Pointer to a Region whose current Frame represents the * "destination" coordinate system. Note that the Base * attribute of the Region may be modified by this function. * domainlist * Pointer to a null-terminated character string containing a * comma-separated list of Frame domains. This may be used to * define a priority order for the different intermediate * coordinate systems that might be used to perform the * conversion. * * The function will first try to obtain a conversion by making * use only of intermediate Frames whose Domain attribute * matches the first domain in this list. If this fails, the * second domain in the list will be used, and so on, until * conversion is achieved. A blank domain (e.g. two consecutive * commas) indicates that all Frames should be considered, * regardless of their Domain attributes. The list is * case-insensitive and all white space is ignored. * status * Pointer to the inherited status variable. * Returned Value: * If the requested coordinate conversion is possible, the * function returns a pointer to a FrameSet which describes the * conversion. Otherwise, a null Object pointer (AST__NULL) is * returned without error. * * If a FrameSet is returned, it will contain two Frames. Frame * number 1 (its base Frame) will describe the source coordinate * system, corresponding to the "from" parameter. Frame number 2 * (its current Frame) will describe the destination coordinate * system, corresponding to the "to" parameter. The Mapping * which inter-relates these Frames will perform the required * conversion between the two coordinate systems. * Notes: * - The returned FrameSet will not contain any Regions. If one or * more of the supplied Frames are in fact Regions, the corresponding * Frames in any returned FrameSet will described the encapsulated * Frame, without any region information. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrameSet *result; /* Returned FrameSet */ /* Check the inherited status. */ if ( !astOK ) return NULL; /* If the "from" pointer is a Region, get a pointer to the current Frame of the encapsulated FrameSet and use it instead of the supplied pointer. */ if( astIsARegion( from ) ) { from = astGetFrame( ((AstRegion *) from)->frameset, AST__CURRENT ); } else { from = astClone( from ); } /* If the "to" pointer is a Region, get a pointer to the current Frame of the encapsulated FrameSet and use it instead of the supplied pointer. */ if( astIsARegion( to ) ) { to = astGetFrame( ((AstRegion *) to)->frameset, AST__CURRENT ); } else { to = astClone( to ); } /* Now invoke astConvert on the above Frames. */ result = astConvert( from, to, domainlist ); /* Annul the pointers used above. */ from = astAnnul( from ); to = astAnnul( to ); /* Return the result */ return result; } static AstFrameSet *ConvertX( AstFrame *to, AstFrame *from, const char *domainlist, int *status ) { /* * Name: * ConvertX * Purpose: * Determine how to convert between two coordinate systems. * Type: * Private function. * Synopsis: * #include "region.h" * AstFrameSet *astConvertX( AstFrame *to, AstFrame *from, * const char *domainlist ) * Class Membership: * Region member function (over-rides the protected astConvertX * method inherited from the Frame class). * Description: * This function performs the processing for the public astConvert * method and has exactly the same interface except that the order * of the first two arguments is swapped. This is a trick to allow * the astConvert method to be over-ridden by derived classes on * the basis of the class of either of its first two arguments. * * See the astConvert method for details of the interface. *- */ /* Local Variables: */ AstFrameSet *result; /* Returned FrameSet */ /* Check the inherited status. */ if ( !astOK ) return NULL; /* If the "to" pointer is a Region, get a pointer to the current Frame of the encapsulated FrameSet and use it instead of the supplied pointer. */ if( astIsARegion( to ) ) { to = astGetFrame( ((AstRegion *) to)->frameset, AST__CURRENT ); } else { to = astClone( to ); } /* If the "from" pointer is a Region, get a pointer to the current Frame of the encapsulated FrameSet and use it instead of the supplied pointer. */ if( astIsARegion( from ) ) { from = astGetFrame( ((AstRegion *) from)->frameset, AST__CURRENT ); } else { from = astClone( from ); } /* Now invoke astConvertX on the above Frames. */ result = astConvertX( to, from, domainlist ); /* Annul the pointers used above. */ from = astAnnul( from ); to = astAnnul( to ); /* Return the result */ return result; } static double Distance( AstFrame *this_frame, const double point1[], const double point2[], int *status ) { /* * Name: * Distance * Purpose: * Calculate the distance between two points. * Type: * Private function. * Synopsis: * #include "region.h" * double Distance( AstFrame *this, const double point1[], * const double point2[], int *status ) * Class Membership: * Region member function (over-rides the protected astDistance * method inherited from the Frame class). * Description: * This function finds the distance between two points whose * Region coordinates are given. The distance calculated is that * along the geodesic curve that joins the two points. * Parameters: * this * Pointer to the Region. * point1 * An array of double, with one element for each Region axis * containing the coordinates of the first point. * point2 * An array of double, with one element for each Region axis * containing the coordinates of the second point. * status * Pointer to the inherited status variable. * Returned Value: * The distance between the two points. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input coordinates has this value. * - A "bad" value will also be returned if this function is * invoked with the AST error status set or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame and invoke this Frame's astDistance method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astDistance( fr, point1, point2 ); fr = astAnnul( fr ); /* If an error occurred, clear the result. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two Objects are equivalent. * Type: * Private function. * Synopsis: * #include "region.h" * int Equal( AstObject *this_object, AstObject *that_object, int *status ) * Class Membership: * Region member function (over-rides the astEqual protected * method inherited from the Frame class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two Regions are equivalent. * Parameters: * this * Pointer to the first Region. * that * Pointer to the second Region. * status * Pointer to the inherited status variable. * Returned Value: * One if the Regions are equivalent, zero otherwise. * Notes: * - The Regions are equivalent if they are of the same class, have * equal PointSets, have equal base Frames, have equal current Frames, * and if the Mapping between base Frames is a UnitMap. In addition, the * Negated attribute must have the same value in both Regions, as must * the Closed attribute. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstFrame *bf1; AstFrame *bf2; AstFrame *cf1; AstFrame *cf2; AstMapping *m1; AstMapping *m2; AstRegion *that; AstRegion *this; const char *class1; const char *class2; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the two objects have the same class. */ class1 = astGetClass( this_object ); class2 = astGetClass( that_object ); if( astOK && !strcmp( class1, class2 ) ) { /* Obtain pointers to the two Region structures. */ this = (AstRegion *) this_object; that = (AstRegion *) that_object; /* Test their PointSets for equality. */ if( astEqual( this->points, that->points ) ){ /* Test their base Frames for equality. */ bf1 = astGetFrame( this->frameset, AST__BASE ); bf2 = astGetFrame( that->frameset, AST__BASE ); if( astEqual( bf1, bf2 ) ){ /* Test their current Frames for equality. */ cf1 = astGetFrame( this->frameset, AST__CURRENT ); cf2 = astGetFrame( that->frameset, AST__CURRENT ); if( astEqual( cf1, cf2 ) ){ /* Get the two Mappings and check that they are equal */ m1 = astGetMapping( this->frameset, AST__BASE, AST__CURRENT ); m2 = astGetMapping( that->frameset, AST__BASE, AST__CURRENT ); if( astEqual( m1, m2 ) ) { /* Test the Negated and Closed flags are equal */ if( astGetNegated( this ) == astGetNegated( that ) && astGetClosed( this ) == astGetClosed( that ) ) { result = 1; } } /* Free resources. */ m1 = astAnnul( m1 ); m2 = astAnnul( m2 ); } cf1 = astAnnul( cf1 ); cf2 = astAnnul( cf2 ); } bf1 = astAnnul( bf1 ); bf2 = astAnnul( bf2 ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static void ClearUnc( AstRegion *this, int *status ){ /* *+ * Name: * astClearUnc * Purpose: * Erase any uncertainty information in a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * void astClearUnc( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function erases all uncertainty information, whether default * or not, from a Region. * Parameters: * this * Pointer to the Region. *- */ /* Check the inherited status. */ if( !astOK ) return; /* Annul any user-supplied uncertainty. Also indicate that cached information may now be out of date. */ if( this->unc ) { this->unc = astAnnul( this->unc ); astResetCache( this ); } /* Annul any default uncertainty. */ if( this->defunc ) this->defunc = astAnnul( this->defunc ); } static AstFrameSet *FindFrame( AstFrame *target_frame, AstFrame *template, const char *domainlist, int *status ) { /* * Name: * FindFrame * Purpose: * Find a coordinate system with specified characteristics. * Type: * Private function. * Synopsis: * #include "region.h" * AstFrameSet *FindFrame( AstFrame *target, AstFrame *template, * const char *domainlist, int *status ) * Class Membership: * Region member function (over-rides the astFindFrame method * inherited from the Frame class). * Description: * This function uses a "template" Frame to search a Region to * identify a coordinate system which has a specified set of * characteristics. If a suitable coordinate system can be found, * the function returns a pointer to a FrameSet which describes the * required coordinate system and how to convert coordinates to and * from it. * Parameters: * target * Pointer to the target Region. * template * Pointer to the template Frame, which should be an instance of * the type of Frame you wish to find. * domainlist * Pointer to a null-terminated character string containing a * comma-separated list of Frame domains. This may be used to * establish a priority order for the different types of * coordinate system that might be found. * * The function will first try to find a suitable coordinate * system whose Domain attribute equals the first domain in this * list. If this fails, the second domain in the list will be * used, and so on, until a result is obtained. A blank domain * (e.g. two consecutive commas) indicates that any coordinate * system is acceptable (subject to the template) regardless of * its domain. * * This list is case-insensitive and all white space is ignored. * If you do not wish to restrict the domain in this way, you * should supply an empty string. * status * Pointer to the inherited status variable. * Returned Value: * If the search is successful, the function returns a pointer to a * FrameSet which contains the Frame found and a description of how * to convert to (and from) the coordinate system it * represents. Otherwise, a null Object pointer (AST__NULL) is * returned without error. * * If a FrameSet is returned, it will contain two Frames. Frame * number 1 (its base Frame) represents the target coordinate * system and will be the same as the target. Frame number 2 (its * current Frame) will be a Frame representing the coordinate system * which the function found. The Mapping which inter-relates these two * Frames will describe how to convert between their respective coordinate * systems. Note, the Frames in this FrameSet will not be Regions - * that is, they will be simple Frames or other derived classes. * Notes: * - A null Object pointer (AST__NULL) will be returned if this * function is invoked with the AST error status set, or if it * should fail for any reason. */ /* Local Variables: */ AstFrameSet *result; /* Pointer to result FrameSet */ AstFrame *fr; /* Pointer to encapsulated Frame */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the astFindFrame method on the current Frame of the encapsulated FrameSet within the target Region. */ fr = astGetFrame( ((AstRegion *) target_frame)->frameset, AST__CURRENT ); result = astFindFrame( fr, template, domainlist ); fr = astAnnul( fr ); /* Return the result. */ return result; } static const char *Format( AstFrame *this_frame, int axis, double value, int *status ) { /* * Name: * Format * Purpose: * Format a coordinate value for a Region axis. * Type: * Private function. * Synopsis: * #include "region.h" * const char *Format( AstFrame *this, int axis, double value, int *status ) * Class Membership: * Region member function (over-rides the astFormat method * inherited from the Frame class). * Description: * This function returns a pointer to a string containing the * formatted (character) version of a coordinate value for a * Region axis. The formatting applied is that specified by a * previous invocation of the astSetFormat method. A suitable * default format is applied if necessary. * Parameters: * this * Pointer to the Region. * axis * The number of the axis (zero-based) for which formatting is * to be performed. * value * The coordinate value to be formatted. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a null-terminated string containing the formatted * value. * Notes: * - The returned string pointer may point at memory allocated * within the Region object, or at static memory. The contents of * the string may be over-written or the pointer may become invalid * following a further invocation of the same function or deletion * of the Region. A copy of the string should therefore be made * if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ const char *result; /* Pointer value to return */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astFormat" ); /* Obtain a pointer to the Region's current Frame and invoke the astFormat method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astFormat( fr, axis, value ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static double Gap( AstFrame *this_frame, int axis, double gap, int *ntick, int *status ) { /* * Name: * Gap * Purpose: * Find a "nice" gap for tabulating Region axis values. * Type: * Private function. * Synopsis: * #include "region.h" * double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) * Class Membership: * Region member function (over-rides the protected astGap method * inherited from the Frame class). * Description: * This function returns a gap size which produces a nicely spaced * series of formatted values for a Region axis, the returned gap * size being as close as possible to the supplied target gap * size. It also returns a convenient number of divisions into * which the gap can be divided. * Parameters: * this * Pointer to the Region. * axis * The number of the axis (zero-based) for which a gap is to be found. * gap * The target gap size. * ntick * Address of an int in which to return a convenient number of * divisions into which the gap can be divided. * status * Pointer to the inherited status variable. * Returned Value: * The nice gap size. * Notes: * - A value of zero is returned if the target gap size is zero. * - A negative gap size is returned if the supplied gap size is negative. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Gap value to return */ /* Check the global error status. */ if ( !astOK ) return 0.0; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astGap" ); /* Obtain a pointer to the Region's current Frame and invoke this Frame's astGap method to obtain the required gap value. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astGap( fr, axis, gap, ntick ); fr = astAnnul( fr ); /* If an error occurred, clear the result. */ if ( !astOK ) result = 0.0; /* Return the result. */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "region.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * Region member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied Region, * in bytes. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstRegion *this; /* Pointer to Region structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the Region structure. */ this = (AstRegion *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->frameset ); result += astGetObjSize( this->points ); result += astGetObjSize( this->basemesh ); result += astGetObjSize( this->basegrid ); result += astGetObjSize( this->unc ); result += astGetObjSize( this->negation ); result += astGetObjSize( this->defunc ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Region member function (over-rides the protected astGetAttrib * method inherited from the Frame class). * Description: * This function returns a pointer to the value of a specified * attribute for a Region, formatted as a character string. * Parameters: * this * Pointer to the Region. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the Region, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Region. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRegion *this; /* Pointer to the Region structure */ const char *result; /* Pointer value to return */ double dval; /* Floating point attribute value */ int ival; /* Integer attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* We first handle attributes that apply to the Region as a whole (rather than to the encapsulated FrameSet). */ /* Negated */ /* ------- */ if ( !strcmp( attrib, "negated" ) ) { ival = astGetNegated( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Closed */ /* ------ */ } else if ( !strcmp( attrib, "closed" ) ) { ival = astGetClosed( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Adaptive */ /* -------- */ } else if ( !strcmp( attrib, "adaptive" ) ) { ival = astGetAdaptive( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* FillFactor */ /* ---------- */ } else if ( !strcmp( attrib, "fillfactor" ) ) { dval = astGetFillFactor( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* MeshSize */ /* -------- */ } else if ( !strcmp( attrib, "meshsize" ) ) { ival = astGetMeshSize( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Bounded */ /* ------- */ } else if ( !strcmp( attrib, "bounded" ) ) { ival = astGetBounded( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Now get the values of attributes inherited from parent classes. We do this to avoid the request being passed on to the encapsulated FrameSet below. */ /* Class. */ /* ------ */ } else if ( !strcmp( attrib, "class" ) ) { result = astGetClass( this ); /* ID. */ /* --- */ } else if ( !strcmp( attrib, "id" ) ) { result = astGetID( this ); /* Ident. */ /* ------ */ } else if ( !strcmp( attrib, "ident" ) ) { result = astGetIdent( this ); /* Invert. */ /* ------- */ } else if ( !strcmp( attrib, "invert" ) ) { ival = astGetInvert( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nin. */ /* ---- */ } else if ( !strcmp( attrib, "nin" ) ) { ival = astGetNin( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nobject. */ /* -------- */ } else if ( !strcmp( attrib, "nobject" ) ) { ival = astGetNobject( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nout. */ /* ----- */ } else if ( !strcmp( attrib, "nout" ) ) { ival = astGetNout( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* RefCount. */ /* --------- */ } else if ( !strcmp( attrib, "refcount" ) ) { ival = astGetRefCount( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Report. */ /* ------- */ } else if ( !strcmp( attrib, "report" ) ) { ival = astGetReport( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TranForward. */ /* ------------ */ } else if ( !strcmp( attrib, "tranforward" ) ) { ival = astGetTranForward( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TranInverse. */ /* ------------ */ } else if ( !strcmp( attrib, "traninverse" ) ) { ival = astGetTranInverse( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Pass unrecognised attributes on to the Region's encapsulated FrameSet for further interpretation. Do not pass on FrameSet attributes since we pretend to the outside world that the encapsulated FrameSet is actually a Frame. */ } else if ( strcmp( attrib, "base" ) && strcmp( attrib, "current" ) && strcmp( attrib, "nframe" ) ) { result = astGetAttrib( this->frameset, attrib ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static int GetBounded( AstRegion *this, int *status ) { /* *+ * Name: * astGetBounded * Purpose: * Is the Region bounded? * Type: * Protected function. * Synopsis: * int astGetBounded( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a flag indicating if the Region is bounded. * The implementation provided by the base Region class is suitable * for Region sub-classes representing the inside of a single closed * curve (e.g. Circle, Ellipse, Box, etc). Other sub-classes (such as * CmpRegion, PointList, etc ) may need to provide their own * implementations. * Parameters: * this * Pointer to the Region. * Returned Value: * Non-zero if the Region is bounded. Zero otherwise. *- */ /* For Regions which are defined by one or more closed curves such as Circles, Boxes, etc, the Region is bounded so long as it has not been negated. Classes for which this is not true should over-ride this implementation. */ return !astGetNegated( this ); } static AstAxis *GetAxis( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetAxis * Purpose: * Obtain a pointer to a specified Axis from a Region. * Type: * Private function. * Synopsis: * #include "region.h" * AstAxis *GetAxis( AstFrame *this, int axis, int *status ) * Class Membership: * Region member function (over-rides the astGetAxis method * inherited from the Frame class). * Description: * This function returns a pointer to the Axis object associated * with one of the axes of the current Frame of a Region. This * object describes the quantity which is represented along that * axis. * Parameters: * this * Pointer to the Region. * axis * The number of the axis (zero-based) for which an Axis pointer * is required. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the requested Axis object. * Notes: * - The reference count of the requested Axis object will be * incremented by one to reflect the additional pointer returned by * this function. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstAxis *result; /* Pointer to Axis */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astGetAxis" ); /* Obtain a pointer to the Region's encapsulated FrameSet and invoke this FrameSet's astGetAxis method to obtain the required Axis pointer. */ result = astGetAxis( this->frameset, axis ); /* If an error occurred, annul the result. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstRegion *GetDefUnc( AstRegion *this, int *status ) { /* *+ * Name: * astGetDefUnc * Purpose: * Obtain a pointer to the default uncertainty Region for a given Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *astGetDefUnc( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a pointer to a Region which represents the * default uncertainty associated with a position on the boundary of the * given Region. The returned Region refers to the base Frame within the * FrameSet encapsulated by the supplied Region. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstFrame *bfrm; /* Base Frame of supplied Region */ AstRegion *result; /* Returned pointer */ double *lbnd; /* Ptr. to array holding axis lower bounds */ double *ubnd; /* Ptr. to array holding axis upper bounds */ double c; /* Central axis value */ double hw; /* Half width of uncertainty interval */ int i; /* Axis index */ int nax; /* Number of base Frame axes */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the base Frame in the supplied Region. */ bfrm = astGetFrame( this->frameset, AST__BASE ); /* Get the number of base Frame axes. */ nax = astGetNaxes( bfrm ); /* Get the base frame bounding box of the supplied Region. The astRegBaseBox assumes the supplied Region has not been inverted. But if the Region contains other Regions (e.g. a Prism or CmpRegion, etc) then this assumption needs to be propagated to the component Regions, which astRegBaseBox does not do. For this reason we use astRegBaseBox2 instead. */ lbnd = astMalloc( sizeof( double)*(size_t) nax ); ubnd = astMalloc( sizeof( double)*(size_t) nax ); astRegBaseBox2( this, lbnd, ubnd ); /* Create a Box covering 1.0E-6 of this bounding box, centred on the centre of the box. */ if( astOK ) { for( i = 0; i < nax; i++ ) { if( ubnd[ i ] != DBL_MAX && lbnd[ i ] != -DBL_MAX ) { hw = fabs( 0.5E-6*( ubnd[ i ] - lbnd[ i ] ) ); c = 0.5*( ubnd[ i ] + lbnd[ i ] ); if( hw == 0.0 ) hw = c*0.5E-6; ubnd[ i ] = c + hw; lbnd[ i ] = c - hw; } else { ubnd[ i ] = 0.0; lbnd[ i ] = 0.0; } } result = (AstRegion *) astBox( bfrm, 1, lbnd, ubnd, NULL, "", status ); } /* Free resources. */ lbnd = astFree( lbnd ); ubnd = astFree( ubnd ); bfrm = astAnnul( bfrm ); /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } static AstRegion *GetNegation( AstRegion *this, int *status ) { /* *+ * Name: * astGetNegation * Purpose: * Obtain a pointer to a negated copy of the supplied Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *GetNegation( AstRegion *this, int *status ) * Class Membership: * Region virtual function. * Description: * This function returns a pointer to a Region which is a negated * copy of "this". The copy is cached in the Region structure for * future use. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* If the Region struture does not contain a pointer to a negated copy of itself, create one now. */ if( ! this->negation ) { this->negation = astCopy( this ); astNegate( this->negation ); } /* Return a clone of the negation pointer. */ return astClone( this->negation ); } static AstFrameSet *GetRegFS( AstRegion *this, int *status ) { /* *+ * Name: * astGetRegFS * Purpose: * Obtain a pointer to the FrameSet encapsulated within a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstFrameSet *astGetRegFS( AstRegion *this ) * Class Membership: * Region virtual function * Description: * This function returns a pointer to the FrameSet encapsulated by the * Region. This is a clone, not a deep copy, of the pointer stored * in the Region. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the FrameSet. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return the required pointer. */ return astClone( this->frameset ); } static AstPointSet *GetSubMesh( int *mask, AstPointSet *in, int *status ) { /* * Name: * GetSubMesh * Purpose: * Extract a selection of points from a PointSet. * Type: * Private function. * Synopsis: * #include "region.h" * AstPointSet *GetSubMesh( int *mask, AstPointSet *in, int *status ) * Class Membership: * Region member function * Description: * This function creates a new PointSet holding points selected from a * supplied PointSet. An integer mask is supplied to indicate which * points should be selected. * Parameters: * mask * Pointer to a mask array, Its size should be equal to the number * of points in the supplied PointSet. Each corresponding point will * be copied if the mask value is zero. * in * Pointer to the PointSet holding the input positions. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output PointSet. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ double **ptr_in; /* Pointers to input axis values */ double **ptr_out; /* Pointers to output axis values */ double *pin; /* Pointer to next input axis value */ double *pout; /* Pointer to next output axis value */ int *m; /* Pointer to next mask element */ int ic; /* Axis index */ int ip; /* Point index */ int nc; /* Number of axes in both PointSets */ int npin; /* Number of points in input PointSet */ int npout; /* Number of points in output PointSet */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get the length of the mask. */ npin = astGetNpoint( in ); /* Count the number of zeros in the mask. */ npout = 0; m = mask; for( ip = 0; ip < npin; ip++ ) { if( *(m++) == 0 ) npout++; } /* Create the output PointSet and get pointers to its data arrays. */ nc = astGetNcoord( in ); result = astPointSet( npout, nc, "", status ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Check pointers can be dereferenced safely. */ if( astOK ) { /* Copy the required axis values from the input to the output. */ for( ic = 0; ic < nc; ic++ ) { pin = ptr_in[ ic ]; pout = ptr_out[ ic ]; m = mask; for( ip = 0; ip < npin; ip++, pin++, m++ ) { if( *m == 0 ) *(pout++) = *pin; } } } /* Return a pointer to the output PointSet. */ return result; } static AstRegion *GetUnc( AstRegion *this, int def, int *status ){ /* *++ * Name: c astGetUnc f AST_GETUNC * Purpose: * Obtain uncertainty information from a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c AstRegion *astGetUnc( AstRegion *this, int def ) f RESULT = AST_GETUNC( THIS, DEF, STATUS ) * Class Membership: * Region method. * Description: * This function returns a Region which represents the uncertainty * associated with positions within the supplied Region. See c astSetUnc f AST_SETUNC * for more information about Region uncertainties and their use. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c def f DEF = LOGICAL (Given) * Controls what is returned if no uncertainty information has been * associated explicitly with the supplied Region. If c a non-zero value f .TRUE. * is supplied, then the default uncertainty Region used internally * within AST is returned (see "Applicability" below). If c zero is supplied, then NULL f .FALSE. is supplied, then AST__NULL * will be returned (without error). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetUnc() f AST_GETUNC = INTEGER * A pointer to a Region describing the uncertainty in the supplied * Region. * Applicability: * CmpRegion * The default uncertainty for a CmpRegion is taken from one of the * two component Regions. If the first component Region has a * non-default uncertainty, then it is used as the default uncertainty * for the parent CmpRegion. Otherwise, if the second component Region * has a non-default uncertainty, then it is used as the default * uncertainty for the parent CmpRegion. If neither of the * component Regions has non-default uncertainty, then the default * uncertainty for the CmpRegion is 1.0E-6 of the bounding box of * the CmpRegion. * Prism * The default uncertainty for a Prism is formed by combining the * uncertainties from the two component Regions. If a component * Region does not have a non-default uncertainty, then its default * uncertainty will be used to form the default uncertainty of the * parent Prism. * Region * For other classes of Region, the default uncertainty is 1.0E-6 * of the bounding box of the Region. If the bounding box has zero * width on any axis, then the uncertainty will be 1.0E-6 of the * axis value. * Notes: * - If uncertainty information is associated with a Region, and the * coordinate system described by the Region is subsequently changed * (e.g. by changing the value of its System attribute, or using the c astMapRegion f AST_MAPREGION * function), then the uncertainty information returned by this function * will be modified so that it refers to the coordinate system currently * described by the supplied Region. f - A null Object pointer (AST__NULL) will be returned if this f function is invoked with STATUS set to an error value, or if it c - A null Object pointer (NULL) will be returned if this c function is invoked with the AST error status set, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstRegion *result; /* Pointer to returned uncertainty Region */ AstRegion *unc; /* Pointer to original uncertainty Region */ /* Initialise */ result = NULL; /* Check inherited status */ if( !astOK ) return result; /* Check that we have an uncertainty Region to return (either assigned or default). */ if( def || astTestUnc( this ) ) { /* Obtain the uncertainty Region and take a copy so that we can modify it without affecting the supplied Region. */ unc = astGetUncFrm( this, AST__CURRENT ); result = astCopy( unc ); unc = astAnnul( unc ); /* In its current context, the uncertainty region is known to refer to the Frame of the supplied Region and so its RegionFS attribute will be set to zero, indicating that the uncertainty FrameSet need not be dumped. However, outside of AST this information cannot be implied, so clear the RegionFS attribute so that the returned pointer will include Frame information if it is dumped to a Channel. */ astClearRegionFS( result ); } /* Return the result. */ return result; } static AstRegion *GetUncFrm( AstRegion *this, int ifrm, int *status ) { /* *+ * Name: * astGetUncFrm * Purpose: * Obtain a pointer to the uncertainty Region for a given Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *astGetUncFrm( AstRegion *this, int ifrm ) * Class Membership: * Region virtual function. * Description: * This function returns a pointer to a Region which represents the * uncertainty associated with a position on the boundary of the given * Region. The returned Region can refer to the either the base or * the current Frame within the FrameSet encapsulated by the supplied * Region as specified by the "ifrm" parameter. If the returned Region is * re-centred at some point on the boundary of the supplied Region, then * the re-centred Region will represent the region in which the true * boundary position could be. * Parameters: * this * Pointer to the Region. * ifrm * The index of a Frame within the FrameSet encapsulated by "this". * The returned Region will refer to the requested Frame. It should * be either AST__CURRENT or AST__BASE. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A default uncertainty Region will be created if the supplied Region * does not have an uncertainty Region. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstFrame *frm; /* Current Frame from supplied Region */ AstMapping *map; /* Supplied to uncertainty Mapping */ AstRegion *result; /* Returned pointer */ AstRegion *unc; /* Base frame uncertainty Region to use */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the Region has an explicitly assigned base-frame uncertainty Region, use it. */ if( this->unc ) { unc = this->unc; /* If not, use the default base-frame uncertainty Region, creating it if necessary. */ } else { if( !this->defunc ) this->defunc = astGetDefUnc( this ); unc = this->defunc; } /* If the uncertainty Region is the base Frame is required, just return a clone of the uncertainty Region pointer. The Frame represented by an uncertainty Region will always (barring bugs!) be the base Frame of its parent Region. */ if( ifrm == AST__BASE ) { result = astClone( unc ); /* If the uncertainty Region is the current Frame is required... */ } else { /* Get a Mapping from the Frame represented by the uncertainty Region (the Region base Frame) to the Region current Frame. */ map = astGetMapping( this->frameset, AST__BASE, AST__CURRENT ); /* If this is a UnitMap, the uncertainty Region is already in the correct Frame, so just return the stored pointer. */ if( astIsAUnitMap( map ) ) { result = astClone( unc ); /* Otherwise, use this Mapping to map the uncertainty Region into the current Frame. */ } else { frm = astGetFrame( this->frameset, AST__CURRENT ); result = astMapRegion( unc, map, frm ); /* Free resources. */ frm = astAnnul( frm ); } map = astAnnul( map ); } /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } static int GetUseDefs( AstObject *this_object, int *status ) { /* * Name: * GetUseDefs * Purpose: * Get the value of the UseDefs attribute for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * int GetUseDefs( AstObject *this_object, int *status ) { * Class Membership: * Region member function (over-rides the protected astGetUseDefs * method inherited from the Frame class). * Description: * This function returns the value of the UseDefs attribute for a * Region. supplying a suitable default. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * - The USeDefs value. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ int result; /* Value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* If the UseDefs value for the Region has been set explicitly, use the Get method inherited from the parent Frame class to get its value. */ if( astTestUseDefs( this ) ) { result = (*parent_getusedefs)( this_object, status ); /* Otherwise, supply a default value equal to the UseDefs value of the encapsulated Frame. */ } else { fr = astGetFrame( this->frameset, AST__CURRENT ); result = astGetUseDefs( fr ); fr = astAnnul( fr ); } /* Return the result. */ return result; } static int TestUnc( AstRegion *this, int *status ) { /* *+ * Name: * astTestUnc * Purpose: * Does the Region contain non-default uncertainty information? * Type: * Protected function. * Synopsis: * int astTestUnc( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a flag indicating if the uncertainty Region in * the supplied Region was supplied explicit (i.e. is not a default * uncertainty Region). * Parameters: * this * Pointer to the Region. * Returned Value: * Non-zero if the uncertainty Region was supplied explicitly. * Zero otherwise. * Notes: * - Classes of Region that encapsulate two or more other Regions * inherit their default uncertainty from the encapsulated Regions. * Non-default uncertainty in the component Regions does not imply * that the parent Region has non-default uncertainty. *- */ /* Check the global error status. */ if ( !astOK ) return 0; return ( this->unc != NULL ); } static AstFrame *RegFrame( AstRegion *this, int *status ) { /* *+ * Name: * astRegFrame * Purpose: * Obtain a pointer to the current Frame for a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstFrame *astRegFrame( AstRegion *this ) * Class Membership: * Region virtual function * Description: * This function returns a pointer to the current Frame in the encapsulated * FrameSet. This is a clone, not a deep copy, of the pointer stored * in the FrameSet. For a deep copy, use astGetRegionFrame. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Frame. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return the required pointer. */ return astGetFrame( this->frameset, AST__CURRENT ); } static AstMapping *RegMapping( AstRegion *this, int *status ) { /* *+ * Name: * astRegMapping * Purpose: * Obtain a pointer to the simplified base->current Mapping for a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstMapping *astRegMapping( AstRegion *this ) * Class Membership: * Region member function * Description: * This function returns a pointer to the Mapping from the base to the * current Frame int he encapsulated FrameSet. The returned Mapping is * simplified before being returned. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Mapping. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstMapping *map; /* Unsimplified Mapping */ AstMapping *result; /* Simplified Mapping */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the "nomap" flag is set in the Region structure, re return a UnitMap. */ if( this->nomap ) { result = (AstMapping *) astUnitMap( astGetNin( this->frameset ), "", status ); /* Otherwise use the Mapping from the Region's FrameSet. */ } else { /* Get the Mapping */ map = astGetMapping( this->frameset, AST__BASE, AST__CURRENT ); /* Simplify it. */ result = astSimplify( map ); /* Annul the pointer to the unsimplified Mapping */ map = astAnnul( map ); } /* Return the required pointer. */ return result; } static int GetNaxes( AstFrame *this_frame, int *status ) { /* * Name: * GetNaxes * Purpose: * Determine how many axes a Region has. * Type: * Private function. * Synopsis: * #include "region.h" * int GetNaxes( AstFrame *this, int *status ) * Class Membership: * Region member function (over-rides the astGetNaxes method * inherited from the Frame class). * Description: * This function returns the number of axes for a Region. This is equal * to the number of axes in its current Frame. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * The number of Region axes (zero or more). * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame. */ fr = astGetFrame( this->frameset, AST__CURRENT ); /* Obtain the number of axes in this Frame. */ result = astGetNaxes( fr ); /* Annul the current Frame pointer. */ fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static const int *GetPerm( AstFrame *this_frame, int *status ) { /* * Name: * GetPerm * Purpose: * Access the axis permutation array for the current Frame of a Region. * Type: * Private function. * Synopsis: * #include "region.h" * const int *GetPerm( AstFrame *this, int *status ) * Class Membership: * Region member function (over-rides the astGetPerm protected * method inherited from the Frame class). * Description: * This function returns a pointer to the axis permutation array * for the current Frame of a Region. This array constitutes a * lookup-table that converts between an axis number supplied * externally and the corresponding index in the Frame's internal * axis arrays. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the current Frame's axis permutation array (a * constant array of int). Each element of this contains the * (zero-based) internal axis index to be used in place of the * external index which is used to address the permutation * array. If the current Frame has zero axes, this pointer will be * NULL. * Notes: * - The pointer returned by this function gives direct access to * data internal to the Frame object. It remains valid only so long * as the Frame exists. The permutation array contents may be * modified by other functions which operate on the Frame and this * may render the returned pointer invalid. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to Region structure */ const int *result; /* Result pointer value */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame and then obtain a pointer to its axis permutation array. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astGetPerm( fr ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static AstFrame *GetRegionFrame( AstRegion *this, int *status ) { /* *++ * Name: c astGetRegionFrame f AST_GETREGIONFRAME * Purpose: * Obtain a pointer to the encapsulated Frame within a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c AstFrame *astGetRegionFrame( AstRegion *this ) f RESULT = AST_GETREGIONFRAME( THIS, STATUS ) * Class Membership: * Region method. * Description: * This function returns a pointer to the Frame represented by a * Region. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetRegionFrame() f AST_GETREGIONFRAME = INTEGER * A pointer to a deep copy of the Frame represented by the Region. * Using this pointer to modify the Frame will have no effect on * the Region. To modify the Region, use the Region pointer directly. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstFrame *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the current Frame of the encapsulated FrameSet. */ fr = astGetFrame( this->frameset, AST__CURRENT ); /* Take a deep copy of it, and then annul the original pointer. */ result = astCopy( fr ); fr = astAnnul( fr ); /* If not OK, annul the returned pointer. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstFrameSet *GetRegionFrameSet( AstRegion *this, int *status ) { /* *++ * Name: c astGetRegionFrameSet f AST_GETREGIONFRAMESET * Purpose: * Obtain a pointer to the encapsulated FrameSet within a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c AstFrame *astGetRegionFrameSet( AstRegion *this ) f RESULT = AST_GETREGIONFRAMESET( THIS, STATUS ) * Class Membership: * Region method. * Description: * This function returns a pointer to the FrameSet encapsulated by a * Region. The base Frame is the Frame in which the box was originally * defined, and the current Frame is the Frame into which the Region * is currently mapped (i.e. it will be the same as the Frame returned c by astGetRegionFrame). f by AST_GETREGIONFRAME). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetRegionFrameSet() f AST_GETREGIONFRAMESET = INTEGER * A pointer to a deep copy of the FrameSet represented by the Region. * Using this pointer to modify the FrameSet will have no effect on * the Region. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return a deep copy of the encapsulated FrameSet. */ return astCopy( this->frameset ); } void astInitRegionVtab_( AstRegionVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitRegionVtab * Purpose: * Initialise a virtual function table for a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * void astInitRegionVtab( AstRegionVtab *vtab, const char *name ) * Class Membership: * Region vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Region class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitFrameVtab( (AstFrameVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsARegion) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstFrameVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearNegated = ClearNegated; vtab->GetNegated = GetNegated; vtab->SetNegated = SetNegated; vtab->TestNegated = TestNegated; vtab->ClearRegionFS = ClearRegionFS; vtab->GetRegionFS = GetRegionFS; vtab->SetRegionFS = SetRegionFS; vtab->TestRegionFS = TestRegionFS; vtab->ClearClosed = ClearClosed; vtab->GetClosed = GetClosed; vtab->SetClosed = SetClosed; vtab->TestClosed = TestClosed; vtab->ClearMeshSize = ClearMeshSize; vtab->GetMeshSize = GetMeshSize; vtab->SetMeshSize = SetMeshSize; vtab->TestMeshSize = TestMeshSize; vtab->ClearAdaptive = ClearAdaptive; vtab->GetAdaptive = GetAdaptive; vtab->SetAdaptive = SetAdaptive; vtab->TestAdaptive = TestAdaptive; vtab->ClearFillFactor = ClearFillFactor; vtab->GetFillFactor = GetFillFactor; vtab->SetFillFactor = SetFillFactor; vtab->TestFillFactor = TestFillFactor; vtab->ResetCache = ResetCache; vtab->RegTrace = RegTrace; vtab->GetBounded = GetBounded; vtab->TestUnc = TestUnc; vtab->ClearUnc = ClearUnc; vtab->GetRegionFrame = GetRegionFrame; vtab->GetRegionFrameSet = GetRegionFrameSet; vtab->MapRegion = MapRegion; vtab->Overlap = Overlap; vtab->OverlapX = OverlapX; vtab->Negate = Negate; vtab->BndMesh = BndMesh; vtab->BndBaseMesh = BndBaseMesh; vtab->RegBaseGrid = RegBaseGrid; vtab->RegBaseMesh = RegBaseMesh; vtab->RegSplit = RegSplit; vtab->RegBaseBox = RegBaseBox; vtab->RegBaseBox2 = RegBaseBox2; vtab->RegBasePick = RegBasePick; vtab->RegCentre = RegCentre; vtab->RegGrid = RegGrid; vtab->RegMesh = RegMesh; vtab->RegClearAttrib = RegClearAttrib; vtab->RegSetAttrib = RegSetAttrib; vtab->GetDefUnc = GetDefUnc; vtab->GetNegation = GetNegation; vtab->GetUncFrm = GetUncFrm; vtab->SetUnc = SetUnc; vtab->GetUnc = GetUnc; vtab->ShowMesh = ShowMesh; vtab->GetRegionBounds = GetRegionBounds; vtab->GetRegionBounds2 = GetRegionBounds2; vtab->GetRegionMesh = GetRegionMesh; vtab->GetRegionPoints = GetRegionPoints; vtab->RegOverlay = RegOverlay; vtab->RegFrame = RegFrame; vtab->RegDummyFS = RegDummyFS; vtab->RegMapping = RegMapping; vtab->RegPins = RegPins; vtab->RegTransform = RegTransform; vtab->BTransform = BTransform; vtab->GetRegFS = GetRegFS; vtab->SetRegFS = SetRegFS; vtab->MaskB = MaskB; vtab->MaskD = MaskD; vtab->MaskF = MaskF; vtab->MaskI = MaskI; vtab->MaskL = MaskL; vtab->MaskS = MaskS; vtab->MaskUB = MaskUB; vtab->MaskUI = MaskUI; vtab->MaskUL = MaskUL; vtab->MaskUS = MaskUS; #if HAVE_LONG_DOUBLE /* Not normally implemented */ vtab->MaskLD = MaskLD; #endif /* Save the inherited pointers to methods that will be extended, and store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; frame = (AstFrameVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_getusedefs = object->GetUseDefs; object->GetUseDefs = GetUseDefs; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif object->Cast = Cast; object->Equal = Equal; object->ClearAttrib = ClearAttrib; object->GetAttrib = GetAttrib; object->SetAttrib = SetAttrib; object->TestAttrib = TestAttrib; mapping->ReportPoints = ReportPoints; mapping->RemoveRegions = RemoveRegions; mapping->Simplify = Simplify; frame->Abbrev = Abbrev; frame->Angle = Angle; frame->AxAngle = AxAngle; frame->AxDistance = AxDistance; frame->AxOffset = AxOffset; frame->CheckPerm = CheckPerm; frame->ClearDigits = ClearDigits; frame->ClearDirection = ClearDirection; frame->ClearDomain = ClearDomain; frame->ClearFormat = ClearFormat; frame->ClearLabel = ClearLabel; frame->ClearMatchEnd = ClearMatchEnd; frame->ClearMaxAxes = ClearMaxAxes; frame->ClearMinAxes = ClearMinAxes; frame->ClearPermute = ClearPermute; frame->ClearPreserveAxes = ClearPreserveAxes; frame->ClearSymbol = ClearSymbol; frame->ClearTitle = ClearTitle; frame->ClearUnit = ClearUnit; frame->Convert = Convert; frame->ConvertX = ConvertX; frame->Distance = Distance; frame->FindFrame = FindFrame; frame->Format = Format; frame->Gap = Gap; frame->GetAxis = GetAxis; frame->GetDigits = GetDigits; frame->GetDirection = GetDirection; frame->GetDomain = GetDomain; frame->GetFormat = GetFormat; frame->GetLabel = GetLabel; frame->GetMatchEnd = GetMatchEnd; frame->GetMaxAxes = GetMaxAxes; frame->GetMinAxes = GetMinAxes; frame->GetNaxes = GetNaxes; frame->GetPerm = GetPerm; frame->GetPermute = GetPermute; frame->GetPreserveAxes = GetPreserveAxes; frame->GetSymbol = GetSymbol; frame->GetTitle = GetTitle; frame->GetUnit = GetUnit; frame->Intersect = Intersect; frame->IsUnitFrame = IsUnitFrame; frame->Match = Match; frame->Norm = Norm; frame->NormBox = NormBox; frame->Offset = Offset; frame->Offset2 = Offset2; frame->Overlay = Overlay; frame->PermAxes = PermAxes; frame->PickAxes = PickAxes; frame->Resolve = Resolve; frame->ResolvePoints = ResolvePoints; frame->SetAxis = SetAxis; frame->SetDigits = SetDigits; frame->SetDirection = SetDirection; frame->SetDomain = SetDomain; frame->SetFormat = SetFormat; frame->SetLabel = SetLabel; frame->SetMatchEnd = SetMatchEnd; frame->SetMaxAxes = SetMaxAxes; frame->SetMinAxes = SetMinAxes; frame->SetPermute = SetPermute; frame->SetPreserveAxes = SetPreserveAxes; frame->SetSymbol = SetSymbol; frame->SetTitle = SetTitle; frame->SetUnit = SetUnit; frame->SubFrame = SubFrame; frame->SystemCode = SystemCode; frame->SystemString = SystemString; frame->TestDigits = TestDigits; frame->TestDirection = TestDirection; frame->TestDomain = TestDomain; frame->TestFormat = TestFormat; frame->TestLabel = TestLabel; frame->TestMatchEnd = TestMatchEnd; frame->TestMaxAxes = TestMaxAxes; frame->TestMinAxes = TestMinAxes; frame->TestPermute = TestPermute; frame->TestPreserveAxes = TestPreserveAxes; frame->TestSymbol = TestSymbol; frame->TestTitle = TestTitle; frame->TestUnit = TestUnit; frame->Unformat = Unformat; frame->ValidateAxis = ValidateAxis; frame->ValidateAxisSelection = ValidateAxisSelection; frame->ValidateSystem = ValidateSystem; frame->LineDef = LineDef; frame->LineContains = LineContains; frame->LineCrossing = LineCrossing; frame->LineOffset = LineOffset; frame->MatchAxes = MatchAxes; frame->MatchAxesX = MatchAxesX; frame->GetActiveUnit = GetActiveUnit; frame->SetActiveUnit = SetActiveUnit; frame->TestActiveUnit = TestActiveUnit; frame->GetTop = GetTop; frame->SetTop = SetTop; frame->TestTop = TestTop; frame->ClearTop = ClearTop; frame->GetBottom = GetBottom; frame->SetBottom = SetBottom; frame->TestBottom = TestBottom; frame->ClearBottom = ClearBottom; frame->GetEpoch = GetEpoch; frame->SetEpoch = SetEpoch; frame->TestEpoch = TestEpoch; frame->ClearEpoch = ClearEpoch; frame->ClearObsAlt = ClearObsAlt; frame->TestObsAlt = TestObsAlt; frame->GetObsAlt = GetObsAlt; frame->SetObsAlt = SetObsAlt; frame->ClearObsLat = ClearObsLat; frame->TestObsLat = TestObsLat; frame->GetObsLat = GetObsLat; frame->SetObsLat = SetObsLat; frame->ClearObsLon = ClearObsLon; frame->TestObsLon = TestObsLon; frame->GetObsLon = GetObsLon; frame->SetObsLon = SetObsLon; frame->GetSystem = GetSystem; frame->SetSystem = SetSystem; frame->TestSystem = TestSystem; frame->ClearSystem = ClearSystem; frame->GetAlignSystem = GetAlignSystem; frame->SetAlignSystem = SetAlignSystem; frame->TestAlignSystem = TestAlignSystem; frame->ClearAlignSystem = ClearAlignSystem; /* Declare the copy constructor, destructor and class dump functions. */ astSetDelete( vtab, Delete ); astSetCopy( vtab, Copy ); astSetDump( vtab, Dump, "Region", "An area within a coordinate system" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static void Intersect( AstFrame *this_frame, const double a1[2], const double a2[2], const double b1[2], const double b2[2], double cross[2], int *status ) { /* * Name: * Intersect * Purpose: * Find the point of intersection between two geodesic curves. * Type: * Private function. * Synopsis: * #include "region.h" * void Intersect( AstFrame *this_frame, const double a1[2], * const double a2[2], const double b1[2], * const double b2[2], double cross[2], * int *status ) * Class Membership: * Region member function (over-rides the astIntersect method * inherited from the Frame class). * Description: * This function finds the coordinate values at the point of * intersection between two geodesic curves. Each curve is specified * by two points on the curve. * Parameters: * this * Pointer to the SkyFrame. * a1 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a point on the first * geodesic curve. * a2 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a second point on the * first geodesic curve. * b1 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a point on the second * geodesic curve. * b2 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a second point on * the second geodesic curve. * cross * An array of double, with one element for each Frame axis * in which the coordinates of the required intersection * point will be returned. These will be AST__BAD if the curves do * not intersect. * status * Pointer to the inherited status variable. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. * - For SkyFrames each curve will be a great circle, and in general * each pair of curves will intersect at two diametrically opposite * points on the sky. The returned position is the one which is * closest to point "a1". */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke the astIntersect method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astIntersect( fr, a1, a2, b1, b2, cross ); fr = astAnnul( fr ); } static int IsUnitFrame( AstFrame *this, int *status ){ /* * Name: * IsUnitFrame * Purpose: * Is this Frame equivalent to a UnitMap? * Type: * Private function. * Synopsis: * #include "region.h" * int IsUnitFrame( AstFrame *this, int *status ) * Class Membership: * Region member function (over-rides the protected astIsUnitFrame * method inherited from the Frame class). * Description: * This function returns a flag indicating if the supplied Frame is * equivalent to a UnitMap when treated as a Mapping (note, the Frame * class inherits from Mapping and therefore every Frame is also a Mapping). * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the supplied Frame is equivalent to * a UnitMap when treated as a Mapping. *- */ /* Check the global error status. */ if( !astOK ) return 0; /* The Region class is never equivalent to a UnitMap. */ return 0; } static int LineContains( AstFrame *this_frame, AstLineDef *l, int def, double *point, int *status ) { /* * Name: * LineContains * Purpose: * Determine if a line contains a point. * Type: * Private function. * Synopsis: * #include "region.h" * int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) * Class Membership: * Region member function (over-rides the protected astLineContains * method inherited from the Frame class). * Description: * This function determines if the supplied point is on the supplied * line within the supplied Frame. The start point of the line is * considered to be within the line, but the end point is not. The tests * are that the point of closest approach of the line to the point should * be between the start and end, and that the distance from the point to * the point of closest aproach should be less than 1.0E-7 of the length * of the line. * Parameters: * this * Pointer to the Frame. * l * Pointer to the structure defining the line. * def * Should be set non-zero if the "point" array was created by a * call to astLineCrossing (in which case it may contain extra * information following the axis values),and zero otherwise. * point * Point to an array containing the axis values of the point to be * tested, possibly followed by extra cached information (see "def"). * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the line contains the point. * Notes: * - The pointer supplied for "l" should have been created using the * astLineDef method. These structures contained cached information about * the lines which improve the efficiency of this method when many * repeated calls are made. An error will be reported if the structure * does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ int result; /* Returned value */ /* Initialise */ result =0; /* Obtain a pointer to the Region's current Frame and then invoke the method. Annul the Frame pointer afterwards. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); result = astLineContains( fr, l, def, point ); fr = astAnnul( fr ); /* Return the result. */ return result; } static int LineCrossing( AstFrame *this_frame, AstLineDef *l1, AstLineDef *l2, double **cross, int *status ) { /* * Name: * LineCrossing * Purpose: * Determine if two lines cross. * Type: * Private function. * Synopsis: * #include "region.h" * int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2, * double **cross, int *status ) * Class Membership: * Region member function (over-rides the protected astLineCrossing * method inherited from the Frame class). * Description: * This function determines if the two suplied line segments cross, * and if so returns the axis values at the point where they cross. * A flag is also returned indicating if the crossing point occurs * within the length of both line segments, or outside one or both of * the line segments. * Parameters: * this * Pointer to the Frame. * l1 * Pointer to the structure defining the first line. * l2 * Pointer to the structure defining the second line. * cross * Pointer to a location at which to put a pointer to a dynamically * alocated array containing the axis values at the crossing. If * NULL is supplied no such array is returned. Otherwise, the returned * array should be freed using astFree when no longer needed. If the * lines are parallel (i.e. do not cross) then AST__BAD is returned for * all axis values. Note usable axis values are returned even if the * lines cross outside the segment defined by the start and end points * of the lines. The order of axes in the returned array will take * account of the current axis permutation array if appropriate. Note, * sub-classes such as SkyFrame may append extra values to the end * of the basic frame axis values. A NULL pointer is returned if an * error occurs. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the lines cross at a point which is * within the [start,end) segment of both lines. If the crossing point * is outside this segment on either line, or if the lines are parallel, * zero is returned. Note, the start point is considered to be inside * the length of the segment, but the end point is outside. * Notes: * - The pointers supplied for "l1" and "l2" should have been created * using the astLineDef method. These structures contained cached * information about the lines which improve the efficiency of this method * when many repeated calls are made. An error will be reported if * either structure does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ int result; /* Returned value */ /* Initialise */ result =0; /* Obtain a pointer to the Region's current Frame and then invoke the method. Annul the Frame pointer afterwards. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); result = astLineCrossing( fr, l1, l2, cross ); fr = astAnnul( fr ); /* Return the result. */ return result; } static AstLineDef *LineDef( AstFrame *this_frame, const double start[2], const double end[2], int *status ) { /* * Name: * LineDef * Purpose: * Creates a structure describing a line segment in a 2D Frame. * Type: * Private function. * Synopsis: * #include "region.h" * AstLineDef *LineDef( AstFrame *this, const double start[2], * const double end[2], int *status ) * Class Membership: * Region member function (over-rides the protected astLineDef * method inherited from the Frame class). * Description: * This function creates a structure containing information describing a * given line segment within the supplied 2D Frame. This may include * information which allows other methods such as astLineCrossing to * function more efficiently. Thus the returned structure acts as a * cache to store intermediate values used by these other methods. * Parameters: * this * Pointer to the Frame. Must have 2 axes. * start * An array of 2 doubles marking the start of the line segment. * end * An array of 2 doubles marking the end of the line segment. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the memory structure containing the description of the * line. This structure should be freed using astFree when no longer * needed. A NULL pointer is returned (without error) if any of the * supplied axis values are AST__BAD. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstLineDef *result; /* Returned value */ /* Initialise */ result = NULL; /* Obtain a pointer to the Region's current Frame and then invoke the method. Annul the Frame pointer afterwards. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); result = astLineDef( fr, start, end ); fr = astAnnul( fr ); /* Return the result. */ return result; } static void LineOffset( AstFrame *this_frame, AstLineDef *line, double par, double prp, double point[2], int *status ){ /* * Name: * LineOffset * Purpose: * Find a position close to a line. * Type: * Private function. * Synopsis: * #include "region.h" * void LineOffset( AstFrame *this, AstLineDef *line, double par, * double prp, double point[2], int *status ) * Class Membership: * Region member function (over-rides the protected astLineOffset * method inherited from the Frame class). * Description: * This function returns a position formed by moving a given distance along * the supplied line, and then a given distance away from the supplied line. * Parameters: * this * Pointer to the Frame. * line * Pointer to the structure defining the line. * par * The distance to move along the line from the start towards the end. * prp * The distance to move at right angles to the line. Positive * values result in movement to the left of the line, as seen from * the observer, when moving from start towards the end. * status * Pointer to the inherited status variable. * Notes: * - The pointer supplied for "line" should have been created using the * astLineDef method. This structure contains cached information about the * line which improves the efficiency of this method when many repeated * calls are made. An error will be reported if the structure does not * refer to the Frame specified by "this". */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ /* Obtain a pointer to the Region's current Frame and then invoke the method. Annul the Frame pointer afterwards. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); astLineOffset( fr, line, par, prp, point ); fr = astAnnul( fr ); } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * Region member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstRegion *this; /* Pointer to Region structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the Region structure. */ this = (AstRegion *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->frameset, mode, extra, fail ); if( !result ) result = astManageLock( this->points, mode, extra, fail ); if( !result ) result = astManageLock( this->unc, mode, extra, fail ); if( !result ) result = astManageLock( this->negation, mode, extra, fail ); if( !result ) result = astManageLock( this->defunc, mode, extra, fail ); if( !result ) result = astManageLock( this->basemesh, mode, extra, fail ); if( !result ) result = astManageLock( this->basegrid, mode, extra, fail ); return result; } #endif static AstRegion *MapRegion( AstRegion *this, AstMapping *map0, AstFrame *frame0, int *status ) { /* *+ * Name: * astMapRegion * Purpose: * Transform a Region into a new Frame using a given Mapping. * Type: * Protected virtual function. * Synopsis: * #include "region.h" * AstRegion *astMapRegion( AstRegion *this, AstMapping *map, * AstFrame *frame ) * Class Membership: * Region method. * Description: * This function returns a pointer to a new Region which corresponds to * supplied Region in some other specified coordinate system. A * Mapping is supplied which transforms positions between the old and new * coordinate systems. The new Region may not be of the same class as * the original region. * Parameters: * this * Pointer to the Region. * map * Pointer to a Mapping which transforms positions from the * coordinate system represented by the supplied Region to the * coordinate system specified by "frame". The supplied Mapping should * define both forward and inverse transformations, and these * transformations should form a genuine inverse pair. That is, * transforming a position using the forward transformation and then * using the inverse transformation should produce the original input * position. Some Mapping classes (such as PermMap, MathMap, SphMap) * can result in Mappings for which this is not true. * frame * Pointer to a Frame describing the coordinate system in which * the new Region is required. * Returned Value: * astMapRegion() * A pointer to a new Region. This Region will represent the area * within the coordinate system specified by "frame" which corresponds * to the supplied Region. * Notes: * - This is the protected implementation of this function - it does * not simplify the returned Region. The public implementation is * astMapRegionID, which simplifies the returned Region. * - A null Object pointer (AST__NULL) will be returned if this * function is invoked with the AST error status set, or if it * should fail for any reason. *- */ /* Local Variables: */ AstFrame *frame; AstFrameSet *fs; AstMapping *map; AstPointSet *ps2; AstPointSet *ps1; AstPointSet *pst; AstRegion *result; double **ptr1; double **ptr2; int i; int icurr; int j; int nax1; int nax2; int np; int ok; /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If a FrameSet was supplied for the Mapping, use the base->current Mapping */ if( astIsAFrameSet( map0 ) ) { map = astGetMapping( (AstFrameSet *) map0, AST__BASE, AST__CURRENT ); } else { map = astClone( map0 ); } /* If a FrameSet was supplied for the Frame, use the current Frame. */ if( astIsAFrameSet( frame0 ) ) { frame = astGetFrame( (AstFrameSet *) frame0, AST__CURRENT ); } else { frame = astClone( frame0 ); } /* First check the Mapping is suitable. It must defined both a forward and an inverse Mapping. */ if( !astGetTranInverse( map ) ) { astError( AST__NODEF, "astMapRegion(%s): The supplied %s does not " "define an inverse transformation.", status, astGetClass( this ), astGetClass( map ) ); } else if( !astGetTranForward( map ) ) { astError( AST__NODEF, "astMapRegion(%s): The supplied %s does not " "define a forward transformation.", status, astGetClass( this ), astGetClass( map ) ); } /* It must not introduce any bad axis values. We can only perform this test reliably if the supplied Region has not bad axis values. */ ps1 = this->points; if( ps1 ) { nax1 = astGetNcoord( ps1 ); np = astGetNpoint( ps1 ); ptr1 = astGetPoints( ps1 ); if( ptr1 ) { ok = 1; for( i = 0; i < nax1 && ok; i++ ){ for( j = 0; j < np; j++ ) { if( ptr1[ i ][ j ] == AST__BAD ){ ok = 0; break; } } } if( ok ) { pst = astRegTransform( this, ps1, 1, NULL, NULL ); ps2 = astTransform( map, pst, 1, NULL ); nax2 = astGetNcoord( ps2 ); ptr2 = astGetPoints( ps2 ); if( ptr2 ) { for( i = 0; i < nax2 && ok; i++ ){ for( j = 0; j < np; j++ ) { if( ptr2[ i ][ j ] == AST__BAD ){ ok = 0; break; } } } if( !ok ) { astError( AST__NODEF, "astMapRegion(%s): The region which " "results from using the supplied %s to transform " "the supplied %s is undefined.", status, astGetClass( this ), astGetClass( map ), astGetClass( this ) ); } } ps2 = astAnnul( ps2 ); pst = astAnnul( pst ); } } } /* Take a deep copy of the supplied Region. */ result = astCopy( this ); /* Get a pointer to the encapsulated FrameSet. */ if( astOK ) { fs = result->frameset; /* Add in the new Frame and Mapping. First note the index of the original current Frame. */ icurr = astGetCurrent( fs ); astAddFrame( fs, AST__CURRENT, map, frame ); /* Remove the original current Frame. */ astRemoveFrame( fs, icurr ); /* The base and current Frames of the resulting FrameSet are now (in general) different and so the Region should include its FrameSet in any Dump. */ astSetRegionFS( result, 1 ); } /* Since the Mapping has been changed, any cached information calculated on the basis of the Mapping properties may no longer be up to date. */ astResetCache( this ); /* Free resources */ map = astAnnul( map ); frame = astAnnul( frame ); /* If not OK, annul the returned pointer. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } /* *++ * Name: c astMask f AST_MASK * Purpose: * Mask a region of a data grid. * Type: * Public virtual function. * Synopsis: c #include "region.h" c int astMask( AstRegion *this, AstMapping *map, int inside, int ndim, c const int lbnd[], const int ubnd[], in[], c val ) f RESULT = AST_MASK( THIS, MAP, INSIDE, NDIM, LBND, UBND, IN, VAL, f STATUS ) * Class Membership: * Mapping method. * Description: * This is a set of functions for masking out regions within gridded data * (e.g. an image). The functions modifies a given data grid by * assigning a specified value to all samples which are inside (or outside c if "inside" is zero) f if INSIDE is .FALSE.) * the specified Region. * * You should use a masking function which matches the numerical * type of the data you are processing by replacing in c the generic function name astMask by an appropriate 1- or f the generic function name AST_MASK by an appropriate 1- or * 2-character type code. For example, if you are masking data c with type "float", you should use the function astMaskF (see f with type REAL, you should use the function AST_MASKR (see * the "Data Type Codes" section below for the codes appropriate to * other numerical types). * Parameters: c this f THIS = INTEGER (Given) * Pointer to a Region. c map f MAP = INTEGER (Given) * Pointer to a Mapping. The forward transformation should map * positions in the coordinate system of the supplied Region * into pixel coordinates as defined by the c "lbnd" and "ubnd" parameters. A NULL pointer f LBND and UBND arguments. A value of AST__NULL * can be supplied if the coordinate system of the supplied Region * corresponds to pixel coordinates. This is equivalent to * supplying a UnitMap. * * The number of inputs for this Mapping (as given by its Nin attribute) * should match the number of axes in the supplied Region (as given * by the Naxes attribute of the Region). * The number of outputs for the Mapping (as given by its Nout attribute) * should match the number of c grid dimensions given by the value of "ndim" f grid dimensions given by the value of NDIM * below. c inside f INSIDE = INTEGER (Given) * A boolean value which indicates which pixel are to be masked. If c a non-zero value f .TRUE. * is supplied, then all grid pixels with centres inside the supplied * Region are assigned the value given by c "val", f VAL, * and all other pixels are left unchanged. If c zero f .FALSE. * is supplied, then all grid pixels with centres not inside the supplied * Region are assigned the value given by c "val", f VAL, * and all other pixels are left unchanged. Note, the Negated * attribute of the Region is used to determine which pixel are * inside the Region and which are outside. So the inside of a Region * which has not been negated is the same as the outside of the * corresponding negated Region. * * For types of Region such as PointList which have zero volume, * pixel centres will rarely fall exactly within the Region. For * this reason, the inclusion criterion is changed for zero-volume * Regions so that pixels are included (or excluded) if any part of * the Region passes through the pixel. For a PointList, this means * that pixels are included (or excluded) if they contain at least * one of the points listed in the PointList. c ndim f NDIM = INTEGER (Given) * The number of dimensions in the input grid. This should be at * least one. c lbnd f LBND( NDIM ) = INTEGER (Given) c Pointer to an array of integers, with "ndim" elements, f An array * containing the coordinates of the centre of the first pixel * in the input grid along each dimension. c ubnd f UBND( NDIM ) = INTEGER (Given) c Pointer to an array of integers, with "ndim" elements, f An array * containing the coordinates of the centre of the last pixel in * the input grid along each dimension. * c Note that "lbnd" and "ubnd" together define the shape f Note that LBND and UBND together define the shape * and size of the input grid, its extent along a particular c (j'th) dimension being ubnd[j]-lbnd[j]+1 (assuming the c index "j" to be zero-based). They also define f (J'th) dimension being UBND(J)-LBND(J)+1. They also define * the input grid's coordinate system, each pixel having unit * extent along each dimension with integral coordinate values * at its centre. c in f IN( * ) = (Given and Returned) c Pointer to an array, with one element for each pixel in the f An array, with one element for each pixel in the * input grid, containing the data to be masked. The * numerical type of this array should match the 1- or * 2-character type code appended to the function name (e.g. if c you are using astMaskF, the type of each array element c should be "float"). f you are using AST_MASKR, the type of each array element f should be REAL). * * The storage order of data within this array should be such * that the index of the first grid dimension varies most * rapidly and that of the final dimension least rapidly c (i.e. Fortran array indexing is used). f (i.e. normal Fortran array storage order). * * On exit, the samples specified by c "inside" are set to the value of "val". f INSIDE are set to the value of VAL. * All other samples are left unchanged. c val f VAL = (Given) * This argument should have the same type as the elements of c the "in" array. It specifies the value used to flag the f the IN array. It specifies the value used to flag the * masked data (see c "inside"). f INSIDE). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astMask() f AST_MASK = INTEGER * The number of pixels to which a value of c "badval" f BADVAL * has been assigned. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * - An error will be reported if the overlap of the Region and * the array cannot be determined. * Data Type Codes: * To select the appropriate masking function, you should c replace in the generic function name astMask with a f replace in the generic function name AST_MASK with a * 1- or 2-character data type code, so as to match the numerical * type of the data you are processing, as follows: c - D: double c - F: float c - L: long int c - UL: unsigned long int c - I: int c - UI: unsigned int c - S: short int c - US: unsigned short int c - B: byte (signed char) c - UB: unsigned byte (unsigned char) f - D: DOUBLE PRECISION f - R: REAL f - I: INTEGER f - UI: INTEGER (treated as unsigned) f - S: INTEGER*2 (short integer) f - US: INTEGER*2 (short integer, treated as unsigned) f - B: BYTE (treated as signed) f - UB: BYTE (treated as unsigned) * c For example, astMaskD would be used to process "double" c data, while astMaskS would be used to process "short int" c data, etc. f For example, AST_MASKD would be used to process DOUBLE f PRECISION data, while AST_MASKS would be used to process f short integer data (stored in an INTEGER*2 array), etc. f f For compatibility with other Starlink facilities, the codes W f and UW are provided as synonyms for S and US respectively (but f only in the Fortran interface to AST). *-- */ /* Define a macro to implement the function for a specific data type. */ #define MAKE_MASK(X,Xtype) \ static int Mask##X( AstRegion *this, AstMapping *map, int inside, int ndim, \ const int lbnd[], const int ubnd[], \ Xtype in[], Xtype val, int *status ) { \ \ /* Local Variables: */ \ AstFrame *grid_frame; /* Pointer to Frame describing grid coords */ \ AstRegion *used_region; /* Pointer to Region to be used by astResample */ \ Xtype *c; /* Pointer to next array element */ \ Xtype *d; /* Pointer to next array element */ \ Xtype *out; /* Pointer to the array used for resample output */ \ Xtype *tmp_out; /* Pointer to temporary output array */ \ double *lbndgd; /* Pointer to array holding lower grid bounds */ \ double *ubndgd; /* Pointer to array holding upper grid bounds */ \ int *lbndg; /* Pointer to array holding lower grid bounds */ \ int *ubndg; /* Pointer to array holding upper grid bounds */ \ int idim; /* Loop counter for coordinate dimensions */ \ int ipix; /* Loop counter for pixel index */ \ int nax; /* Number of Region axes */ \ int nin; /* Number of Mapping input coordinates */ \ int nout; /* Number of Mapping output coordinates */ \ int npix; /* Number of pixels in supplied array */ \ int npixg; /* Number of pixels in bounding box */ \ int result; /* Result value to return */ \ \ /* Initialise. */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Obtain value for the Naxes attribute of the Region. */ \ nax = astGetNaxes( this ); \ \ /* If supplied, obtain values for the Nin and Nout attributes of the Mapping. */ \ if( map ) { \ nin = astGetNin( map ); \ nout = astGetNout( map ); \ \ /* If OK, check that the number of mapping inputs matches the \ number of axes in the Region. Report an error if necessary. */ \ if ( astOK && ( nax != nin ) ) { \ astError( AST__NGDIN, "astMask"#X"(%s): Bad number of mapping " \ "inputs (%d).", status, astGetClass( this ), nin ); \ astError( AST__NGDIN, "The %s given requires %d coordinate value%s " \ "to specify a position.", status, \ astGetClass( this ), nax, ( nax == 1 ) ? "" : "s" ); \ } \ \ /* If OK, check that the number of mapping outputs matches the \ number of grid dimensions. Report an error if necessary. */ \ if ( astOK && ( ndim != nout ) ) { \ astError( AST__NGDIN, "astMask"#X"(%s): Bad number of mapping " \ "outputs (%d).", status, astGetClass( this ), nout ); \ astError( AST__NGDIN, "The pixel grid requires %d coordinate value%s " \ "to specify a position.", status, \ ndim, ( ndim == 1 ) ? "" : "s" ); \ } \ \ /* Create a new Region by mapping the supplied Region with the supplied \ Mapping. The resulting Region represents a region in grid coordinates. */ \ grid_frame = astFrame( ndim, "Domain=grid", status ); \ used_region = astMapRegion( this, map, grid_frame ); \ grid_frame = astAnnul( grid_frame ); \ \ /* If no Mapping was supplied check that the number of grid dimensions \ matches the number of axes in the Region.*/ \ } else if ( astOK && ( ( ndim != nax ) || ( ndim < 1 ) ) ) { \ used_region = NULL; \ astError( AST__NGDIN, "astMask"#X"(%s): Bad number of input grid " \ "dimensions (%d).", status, astGetClass( this ), ndim ); \ if ( ndim != nax ) { \ astError( AST__NGDIN, "The %s given requires %d coordinate value%s " \ "to specify an input position.", status, \ astGetClass( this ), nax, ( nax == 1 ) ? "" : "s" ); \ } \ \ /* If no Mapping was supplied and the parameters look OK, clone the \ supplied Region pointer for use later on. */ \ } else { \ used_region = astClone( this ); \ } \ \ /* Check that the lower and upper bounds of the input grid are \ consistent. Report an error if any pair is not. */ \ if ( astOK ) { \ for ( idim = 0; idim < ndim; idim++ ) { \ if ( lbnd[ idim ] > ubnd[ idim ] ) { \ astError( AST__GBDIN, "astMask"#X"(%s): Lower bound of " \ "input grid (%d) exceeds corresponding upper bound " \ "(%d).", status, astGetClass( this ), \ lbnd[ idim ], ubnd[ idim ] ); \ astError( AST__GBDIN, "Error in input dimension %d.", status, \ idim + 1 ); \ break; \ } \ } \ } \ \ /* Allocate memory, and then get the bounding box of this new Region in its \ current Frame (grid coordinates). This bounding box assumes the region \ has not been negated. */ \ lbndg = astMalloc( sizeof( int )*(size_t) ndim ); \ ubndg = astMalloc( sizeof( int )*(size_t) ndim ); \ lbndgd = astMalloc( sizeof( double )*(size_t) ndim ); \ ubndgd = astMalloc( sizeof( double )*(size_t) ndim ); \ if( astOK ) { \ astGetRegionBounds( used_region, lbndgd, ubndgd ); \ \ /* We convert the floating point bounds to integer pixel bounds, and at \ the same time expand the box by 2 pixels at each edge to ensure that \ rounding errors etc do not cause any of the Region to fall outside (or \ on) the box. Do not let the expanded box extend outside the supplied \ array bounds. Also note the total number of pixels in the supplied \ array, and in the bounding box. */ \ npix = 1; \ npixg = 1; \ for ( idim = 0; idim < ndim; idim++ ) { \ if( lbndgd[ idim ] != AST__BAD && ubndgd[ idim ] != AST__BAD ) { \ lbndg[ idim ] = MAX( lbnd[ idim ], (int)( lbndgd[ idim ] + 0.5 ) - 2 ); \ ubndg[ idim ] = MIN( ubnd[ idim ], (int)( ubndgd[ idim ] + 0.5 ) + 2 ); \ } else { \ lbndg[ idim ] = lbnd[ idim ]; \ ubndg[ idim ] = ubnd[ idim ]; \ } \ npix *= ( ubnd[ idim ] - lbnd[ idim ] + 1 ); \ npixg *= ( ubndg[ idim ] - lbndg[ idim ] + 1 ); \ if( npixg <= 0 ) break; \ } \ \ /* If the bounding box is null, return without action. */ \ if( npixg > 0 && astOK ) { \ \ /* All points outside this box are either all inside, or all outside, the \ Region. So we can speed up processing by setting all the points which are \ outside the box to the supplied data value (if required). This is \ faster than checking each point individually using the Transform method \ of the Region. We do this by supplying an alternative output array to \ the resampling function below, which has been pre-filled with "val" at \ every pixel. */ \ if( ( inside != 0 ) == ( astGetNegated( used_region ) != 0 ) ) { \ \ /* Allocate memory for the alternative output array, and fill it with \ "val". */ \ tmp_out = astMalloc( sizeof( Xtype )*(size_t) npix ); \ if( tmp_out ) { \ c = tmp_out; \ for( ipix = 0; ipix < npix; ipix++ ) *(c++) = val; \ result = npix - npixg; \ } \ \ /* Indicate that we will use this temporary array rather than the \ supplied array. */ \ out = tmp_out; \ \ /* If the outside of the grid box is outside the region of interest it \ will be unchanged in the resturned array. Therefore we can use the \ supplied array as the output array below. */ \ } else { \ tmp_out = NULL; \ out = in; \ } \ \ /* Temporarily invert the Region if required. The Region Transform methods \ leave interior points unchanged and assign AST__BAD to exterior points. \ This is the opposite of what we want (which is to leave exterior \ points unchanged and assign VAL to interior points), so we negate the \ region if the inside is to be assigned the value VAL.*/ \ if( inside ) astNegate( used_region ); \ \ /* Invoke astResample to mask just the region inside the bounding box found \ above (specified by lbndg and ubndg), since all the points outside this \ box will already contain their required value. */ \ result += astResample##X( used_region, ndim, lbnd, ubnd, in, NULL, AST__NEAREST, \ NULL, NULL, 0, 0.0, 100, val, ndim, \ lbnd, ubnd, lbndg, ubndg, out, NULL ); \ \ /* Revert to the original setting of the Negated attribute. */ \ if( inside ) astNegate( used_region ); \ \ /* If required, copy the output data from the temporary output array to \ the supplied array, and then free the temporary output array. */ \ if( tmp_out ) { \ c = tmp_out; \ d = in; \ for( ipix = 0; ipix < npix; ipix++ ) *(d++) = *(c++); \ tmp_out = astFree( tmp_out ); \ }\ }\ } \ \ /* Free resources */ \ ubndg = astFree( ubndg ); \ lbndg = astFree( lbndg ); \ ubndgd = astFree( ubndgd ); \ lbndgd = astFree( lbndgd ); \ used_region = astAnnul( used_region ); \ \ /* If an error occurred, clear the returned result. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } /* Expand the above macro to generate a function for each required data type. */ #if HAVE_LONG_DOUBLE /* Not normally implemented */ MAKE_MASK(LD,long double) #endif MAKE_MASK(D,double) MAKE_MASK(L,long int) MAKE_MASK(UL,unsigned long int) MAKE_MASK(I,int) MAKE_MASK(UI,unsigned int) MAKE_MASK(S,short int) MAKE_MASK(US,unsigned short int) MAKE_MASK(B,signed char) MAKE_MASK(UB,unsigned char) MAKE_MASK(F,float) /* Undefine the macro. */ #undef MAKE_MASK static int Match( AstFrame *this_frame, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * Match * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Private function. * Synopsis: * #include "region.h" * int Match( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * Region member function (over-rides the protected astMatch * method inherited from the Frame class). * Description: * This function matches the current Frame of a "template" Region * to a "target" frame and determines whether it is possible to * convert coordinates between them. If it is, a Mapping that * performs the transformation is returned along with a new Frame * that describes the coordinate system that results when this * Mapping is applied to the current Frame of the target * Region. In addition, information is returned to allow the axes * in this "result" Frame to be associated with the corresponding * axes in the target and template Frames from which they are * derived. * Parameters: * template * Pointer to the template Region, whose current Frame * describes the coordinate system (or set of possible * coordinate systems) into which we wish to convert our * coordinates. * target * Pointer to the target Frame. This describes the coordinate * system in which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case. * template_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the index of the axis in the * template Region's current Frame from which it is * derived. If it is not derived from any template Region * axis, a value of -1 will be returned instead. * target_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the index of the target Frame axis * from which it is derived. If it is not derived from any * target Frame axis, a value of -1 will be returned instead. * map * Address of a location where a pointer to a new Mapping will * be returned if the requested coordinate conversion is * possible. If returned, the forward transformation of this * Mapping may be used to convert coordinates between the target * Frame and the result Frame (see below) and the inverse * transformation will convert in the opposite direction. * result * Address of a location where a pointer to a new Frame will be * returned if the requested coordinate conversion is * possible. If returned, this Frame describes the coordinate * system that results from applying the returned Mapping * (above) to the "target" coordinate system. In general, this * Frame will combine attributes from (and will therefore be * more specific than) both the target Frame and the current * Frame of the template Region. In particular, when the * template allows the possibility of transformaing to any one * of a set of alternative coordinate systems, the "result" * Frame will indicate which of the alternatives was used. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the requested coordinate * conversion is possible. Otherwise zero is returned (this will * not in itself result in an error condition). * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to Region's current Frame */ int match; /* Result to be returned */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Invoke the parent astMatch method on the current Frame within the encapsulated FrameSet within the Region. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); match = astMatch( fr, target, matchsub, template_axes, target_axes, map, result ); fr = astAnnul( fr ); /* Return the result. */ return match; } static void MatchAxes( AstFrame *frm1_frame, AstFrame *frm2, int *axes, int *status ) { /* * Name: * MatchAxes * Purpose: * Find any corresponding axes in two Frames. * Type: * Private function. * Synopsis: * #include "region.h" * void MatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes ) * int *status ) * Class Membership: * Region member function (over-rides the protected astMatchAxes * method inherited from the Frame class). * Description: * This function looks for corresponding axes within two supplied * Frames. An array of integers is returned that contains an element * for each axis in the second supplied Frame. An element in this array * will be set to zero if the associated axis within the second Frame * has no corresponding axis within the first Frame. Otherwise, it * will be set to the index (a non-zero positive integer) of the * corresponding axis within the first supplied Frame. * Parameters: * frm1 * Pointer to the first Frame. * frm2 * Pointer to the second Frame. * axes * Pointer to an * integer array in which to return the indices of the axes (within * the second Frame) that correspond to each axis within the first * Frame. Axis indices start at 1. A value of zero will be stored * in the returned array for each axis in the first Frame that has * no corresponding axis in the second Frame. * * The number of elements in this array must be greater than or * equal to the number of axes in the first Frame. * status * Pointer to inherited status value. * Notes: * - Corresponding axes are identified by the fact that a Mapping * can be found between them using astFindFrame or astConvert. Thus, * "corresponding axes" are not necessarily identical. For instance, * SkyFrame axes in two Frames will match even if they describe * different celestial coordinate systems */ /* Local Variables: */ AstFrame *frm1; /* Pointer to Region's current Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the astMatchAxesX method on frm2, passing it the current Frame within the encapsulated FrameSet within the Region as "frm1". */ frm1 = astGetFrame( ((AstRegion *) frm1_frame)->frameset, AST__CURRENT ); astMatchAxesX( frm2, frm1, axes ); frm1 = astAnnul( frm1 ); } static void MatchAxesX( AstFrame *frm2_frame, AstFrame *frm1, int *axes, int *status ) { /* * Name: * MatchAxesX * Purpose: * Find any corresponding axes in two Frames. * Type: * Private function. * Synopsis: * #include "region.h" * void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes ) * int *status ) * Class Membership: * Region member function (over-rides the protected astMatchAxesX * method inherited from the Frame class). * This function looks for corresponding axes within two supplied * Frames. An array of integers is returned that contains an element * for each axis in the second supplied Frame. An element in this array * will be set to zero if the associated axis within the second Frame * has no corresponding axis within the first Frame. Otherwise, it * will be set to the index (a non-zero positive integer) of the * corresponding axis within the first supplied Frame. * Parameters: * frm2 * Pointer to the second Frame. * frm1 * Pointer to the first Frame. * axes * Pointer to an integer array in which to return the indices of * the axes (within the first Frame) that correspond to each axis * within the second Frame. Axis indices start at 1. A value of zero * will be stored in the returned array for each axis in the second * Frame that has no corresponding axis in the first Frame. * * The number of elements in this array must be greater than or * equal to the number of axes in the second Frame. * status * Pointer to inherited status value. * Notes: * - Corresponding axes are identified by the fact that a Mapping * can be found between them using astFindFrame or astConvert. Thus, * "corresponding axes" are not necessarily identical. For instance, * SkyFrame axes in two Frames will match even if they describe * different celestial coordinate systems */ /* Local Variables: */ AstFrame *frm2; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the current Frame in the FrameSet. */ frm2 = astGetFrame( ((AstRegion *) frm2_frame)->frameset, AST__CURRENT ); /* Invoke the astMatchAxesX on the current Frame. */ astMatchAxesX( frm2, frm1, axes ); /* Free resources */ frm2 = astAnnul( frm2 ); } static void Negate( AstRegion *this, int *status ) { /* *++ * Name: c astNegate f AST_NEGATE * Purpose: * Negate the area represented by a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astNegate( AstRegion *this ) f CALL AST_NEGATE( THIS, STATUS ) * Class Membership: * Region method. * Description: * This function negates the area represented by a Region. That is, * points which were previously inside the region will then be * outside, and points which were outside will be inside. This is * acomplished by toggling the state of the Negated attribute for * the supplied region. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Toggle the Negated attribute. */ astSetNegated( this, astGetNegated( this ) ? 0 : 1 ); } static void Norm( AstFrame *this_frame, double value[], int *status ) { /* * Name: * Norm * Purpose: * Normalise a set of Region coordinates. * Type: * Private function. * Synopsis: * #include "region.h" * void Norm( AstAxis *this, double value[], int *status ) * Class Membership: * Region member function (over-rides the astNorm method * inherited from the Frame class). * Description: * This function converts a set of coordinate values for the * current Frame of a Region, which might potentially be * unsuitable for display to a user (for instance, may lie outside * the expected range of values) into a set of acceptable * alternative values suitable for display. * * Typically, for Frames whose axes represent cyclic values (such * as angles or positions on the sky), this function wraps an * arbitrary set of coordinates, so that they lie within the first * cycle (say zero to 2*pi or -pi/2 to +pi/2). For Frames with * ordinary linear axes, without constraints, this function will * typically return the original coordinate values unchanged. * Parameters: * this * Pointer to the Region. * value * An array of double, with one element for each Region axis. * This should contain the initial set of coordinate values, * which will be modified in place. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to the current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame and invoke this Frame's astNorm method to obtain the new values. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astNorm( fr, value ); fr = astAnnul( fr ); } static void NormBox( AstFrame *this_frame, double lbnd[], double ubnd[], AstMapping *reg, int *status ) { /* * Name: * NormBox * Purpose: * Extend a box to include effect of any singularities in the Frame. * Type: * Private function. * Synopsis: * #include "region.h" * void astNormBox( AstFrame *this, double lbnd[], double ubnd[], * AstMapping *reg, int *status ) * Class Membership: * Region member function (over-rides the astNormBox method inherited * from the Frame class). * Description: * This function modifies a supplied box to include the effect of any * singularities in the co-ordinate system represented by the Frame. * For a normal Cartesian coordinate system, the box will be returned * unchanged. Other classes of Frame may do other things. For instance, * a SkyFrame will check to see if the box contains either the north * or south pole and extend the box appropriately. * Parameters: * this * Pointer to the Frame. * lbnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * lower axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * ubnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * upper axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * reg * A Mapping which should be used to test if any singular points are * inside or outside the box. The Mapping should leave an input * position unchanged if the point is inside the box, and should * set all bad if the point is outside the box. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to the current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame and invoke this Frame's astNormBox method to obtain the new values. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astNormBox( fr, lbnd, ubnd, reg ); fr = astAnnul( fr ); } static void Offset( AstFrame *this_frame, const double point1[], const double point2[], double offset, double point3[], int *status ) { /* * Name: * Offset * Purpose: * Calculate an offset along a geodesic curve. * Type: * Public virtual function. * Synopsis: * #include "region.h" * void Offset( AstFrame *this, * const double point1[], const double point2[], * double offset, double point3[], int *status ) * Class Membership: * Region member function (over-rides the protected astOffset * method inherited from the Frame class). * Description: * This function finds the Region coordinate values of a point * which is offset a specified distance along the geodesic curve * between two other points. * Parameters: * this * Pointer to the Region. * point1 * An array of double, with one element for each Region axis. * This should contain the coordinates of the point marking the * start of the geodesic curve. * point2 * An array of double, with one element for each Region axis * This should contain the coordinates of the point marking the * end of the geodesic curve. * offset * The required offset from the first point along the geodesic * curve. If this is positive, it will be towards the second * point. If it is negative, it will be in the opposite * direction. This offset need not imply a position lying * between the two points given, as the curve will be * extrapolated if necessary. * point3 * An array of double, with one element for each Region axis * in which the coordinates of the required point will be * returned. * status * Pointer to the inherited status variable. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. * - "Bad" coordinate values will also be returned if the two * points supplied are coincident (or otherwise fail to uniquely * specify a geodesic curve) but the requested offset is non-zero. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's current Frame and invoke this Frame's astOffset method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astOffset( fr, point1, point2, offset, point3 ); fr = astAnnul( fr ); } static double Offset2( AstFrame *this_frame, const double point1[2], double angle, double offset, double point2[2], int *status ){ /* * Name: * Offset2 * Purpose: * Calculate an offset along a geodesic curve in a 2D Frame. * Type: * Private function. * Synopsis: * #include "region.h" * double Offset2( AstFrame *this, const double point1[2], double angle, * double offset, double point2[2], int *status ); * Class Membership: * Region member function (over-rides the protected astOffset2 * method inherited from the Frame class). * Description: * This function finds the Frame coordinate values of a point which * is offset a specified distance along the geodesic curve at a * given angle from a specified starting point. It can only be * used with 2-dimensional Frames. * * For example, in a basic Frame, this offset will be along the * straight line joining two points. For a more specialised Frame * describing a sky coordinate system, however, it would be along * the great circle passing through two sky positions. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of the * point marking the start of the geodesic curve. * angle * The angle (in radians) from the positive direction of the second * axis, to the direction of the required position, as seen from * the starting position. Positive rotation is in the sense of * rotation from the positive direction of axis 2 to the positive * direction of axis 1. * offset * The required offset from the first point along the geodesic * curve. If this is positive, it will be in the direction of the * given angle. If it is negative, it will be in the opposite * direction. * point2 * An array of double, with one element for each Frame axis * in which the coordinates of the required point will be returned. * status * Pointer to the inherited status variable. * Returned Value: * The direction of the geodesic curve at the end point. That is, the * angle (in radians) between the positive direction of the second * axis and the continuation of the geodesic curve at the requested * end point. Positive rotation is in the sense of rotation from * the positive direction of axis 2 to the positive direction of axis 1. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - An error will be reported if the Frame is not 2-dimensional. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double result; /* Value to return */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke the astOffset2 method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astOffset2( fr, point1, angle, offset, point2 ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static int Overlap( AstRegion *this, AstRegion *that, int *status ){ /* *++ * Name: c astOverlap f AST_OVERLAP * Purpose: * Test if two regions overlap each other. * Type: * Public virtual function. * Synopsis: c #include "region.h" c int astOverlap( AstRegion *this, AstRegion *that ) f RESULT = AST_OVERLAP( THIS, THAT, STATUS ) * Class Membership: * Region method. * Description: * This function returns an integer value indicating if the two * supplied Regions overlap. The two Regions are converted to a commnon * coordinate system before performing the check. If this conversion is * not possible (for instance because the two Regions represent areas in * different domains), then the check cannot be performed and a zero value * is returned to indicate this. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the first Region. c that f THAT = INTEGER (Given) * Pointer to the second Region. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astOverlap() f AST_OVERLAP = INTEGER * A value indicating if there is any overlap between the two Regions. * Possible values are: * * 0 - The check could not be performed because the second Region * could not be mapped into the coordinate system of the first * Region. * * 1 - There is no overlap between the two Regions. * * 2 - The first Region is completely inside the second Region. * * 3 - The second Region is completely inside the first Region. * * 4 - There is partial overlap between the two Regions. * * 5 - The Regions are identical to within their uncertainties. * * 6 - The second Region is the exact negation of the first Region * to within their uncertainties. * Notes: * - The returned values 5 and 6 do not check the value of the Closed * attribute in the two Regions. * - A value of zero will be returned if this function is invoked with the * AST error status set, or if it should fail for any reason. *-- * Implementation Notes: * This function is simply a wrap-up for the protected astOverlapX * method which performs the required processing but swaps the order * of the two arguments. This is a trick to allow the astOverlap method * to be over-ridden by derived classes on the basis of the class of either * of the two arguments. */ /* Check the global error status. */ if ( !astOK ) return 0; /* Invoke the "astOverlapX" method with the two arguments swapped. */ return astOverlapX( that, this ); } static int OverlapX( AstRegion *that, AstRegion *this, int *status ){ /* *+ * Name: * astOverlapX * Purpose: * Test if two regions overlap each other. * Type: * Protected virtual function. * Synopsis: * #include "region.h" * int astOverlapX( AstRegion *that, AstRegion *this ) * Class Membership: * Region method. * Description: * This function performs the processing for the public astOverlap * method and has exactly the same interface except that the order * of the two arguments is swapped. This is a trick to allow * the astOverlap method to be over-ridden by derived classes on * the basis of the class of either of its two arguments. * * See the astOverlap method for details of the interface. *- */ /* Local Variables: */ AstFrame *bfrm_reg1; /* Pointer to base Frame in "reg1" Frame */ AstFrame *frm_reg1; /* Pointer to current Frame in "reg1" Frame */ AstFrameSet *fs0; /* FrameSet connecting Region Frames */ AstFrameSet *fs; /* FrameSet connecting Region Frames */ AstMapping *cmap; /* Mapping connecting Region Frames */ AstMapping *map; /* Mapping form "reg2" current to "reg1" base */ AstMapping *map_reg1; /* Pointer to current->base Mapping in "reg1" */ AstPointSet *ps1; /* Mesh covering second Region */ AstPointSet *ps3; /* Mesh covering first Region */ AstPointSet *ps4; /* Mesh covering first Region */ AstPointSet *ps2; /* Mesh covering second Region */ AstPointSet *reg2_mesh; /* Mesh covering second Region */ AstPointSet *reg1_mesh; /* Mesh covering first Region */ AstPointSet *reg2_submesh; /* Second Region mesh minus boundary points */ AstRegion *reg1; /* Region to use as the first Region */ AstRegion *reg2; /* Region to use as the second Region */ AstRegion *unc1; /* "unc" mapped into Frame of first Region */ AstRegion *unc; /* Uncertainty in second Region */ double **ptr1; /* Pointer to mesh axis values */ double **ptr; /* Pointer to pointset data */ double *p; /* Pointer to next axis value */ int *mask; /* Mask identifying common boundary points */ int allbad; /* Were all axis values bad? */ int allgood; /* Were all axis values good? */ int bnd1; /* Does reg1 have a finite boundary */ int bnd2; /* Does reg2 have a finite boundary */ int bnd_that; /* Does "that" have a finite boundary */ int bnd_this; /* Does "this" have a finite boundary */ int case1; /* First region inside second region? */ int first; /* First pass? */ int good; /* Any good axis values found? */ int i; /* Mesh axis index */ int iax; /* Axis index */ int inv0; /* Original FrameSet Invert flag */ int ip; /* Index of point */ int j; /* Mesh point index */ int nc; /* Number of axis values per point */ int np; /* Number of points in mesh */ int result; /* Value to return */ int reg1_neg; /* Was "reg1" negated to make it bounded? */ int reg2_neg; /* Was "reg2" negated to make it bounded? */ int that_neg; /* Was "that" negated to make it bounded? */ int this_neg; /* Was "this" negated to make it bounded? */ int touch; /* Do the Regions touch? */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Return 5 if the two Regions are equal using the astEqual method. */ if( astEqual( this, that ) ) { return 5; /* Return 6 if the two Regions are equal using the Equal method after temporarily negating the first. */ } else { astNegate( this ); result = astEqual( this, that ); astNegate( this ); if( result ) return 6; } /* Get a FrameSet which connects the Frame represented by the second Region to the Frame represented by the first Region. Check that the conection is defined. */ fs0 = astConvert( that, this, "" ); if( !fs0 ) return 0; inv0 = astGetInvert( fs0 ); /* The rest of this function tests for overlap by representing one of the Regions as a mesh of points along its boundary, and then checking to see if any of the points in this mesh fall inside or outside the other Region. This can only be done if the Region has a boundary of finite length (e.g. Circles, Boxes, etc). Other Regions (e.g. some Intervals) do not have finite boundaries and consequently report an error if an attempt is made to represent them using a boundary mesh. We now therefore check to see if either of the two Regions has a finite boundary length. This will be the case if the region is bounded, or if it can be made bounded simply by negating it. If a Region is unbounded regardless of the setting of its Negated flag, then it does not have a finite boundary. We leave the Negated attributes (temporaily) set to the values that cause the Regions to be bounded. Set flags to indicate if the Regions have been negated. */ bnd_this = astGetBounded( this ); if( !bnd_this ) { astNegate( this ); bnd_this = astGetBounded( this ); if( ! bnd_this ) { astNegate( this ); this_neg = 0; } else { this_neg = 1; } } else { this_neg = 0; } bnd_that = astGetBounded( that ); if( !bnd_that ) { astNegate( that ); bnd_that = astGetBounded( that ); if( ! bnd_that ) { astNegate( that ); that_neg = 0; } else { that_neg = 1; } } else { that_neg = 0; } /* If neither Regions has a finite boundary, then we cannot currently determine any overlap, so report an error. Given more time, it is probably possible to think of some way of determining overlap between two unbounded Regions, but it will probably not be a common requirement and so is currently put off to a rainy day. */ if( !bnd_this && !bnd_that && astOK ) { astError( AST__INTER, "astOverlap(Region): Neither of the two " "supplied Regions (classes %s and %s) has a finite " "boundary.", status, astGetClass(this), astGetClass(that) ); astError( AST__INTER, "The current implementation of astOverlap " "cannot determine the overlap between two Regions " "unless at least one of them has a finite boundary." , status); } /* If only one of the two Regions has a finite boundary, we must use its mesh first. Choose the finite boundary Region as the "second" region. Also store a flag indicating if the first Region has a finite boundary. */ if( bnd_that ) { reg1 = this; reg2 = that; bnd1 = bnd_this; bnd2 = bnd_that; reg1_neg = this_neg; reg2_neg = that_neg; } else { reg1 = that; reg2 = this; bnd1 = bnd_that; bnd2 = bnd_this; reg1_neg = that_neg; reg2_neg = this_neg; } /* We may need to try again with the above selections swapped. We only do this once though. Set a flag to indicate that we are about to start the first pass. */ first = 1; L1: /* Get a FrameSet which connects the Frame represented by the second Region to the Frame represented by the first Region. Check that the conection is defined. */ fs = astClone( fs0 ); astSetInvert( fs, (reg2 == that ) ? inv0 : 1 - inv0 ); if( fs ) { /* Get a pointer to the Frame represented by the first Region. */ frm_reg1 = astGetFrame( reg1->frameset, AST__CURRENT ); /* Get a pointer to the Mapping from current to base Frame in the first Region. */ map_reg1 = astGetMapping( reg1->frameset, AST__CURRENT, AST__BASE ); /* Get the Mapping from the current Frame of the second Region to the current Frame of the first Region. */ cmap = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* Combine these Mappings to get the Mapping from current Frame of the second region to the base Frame of the first Region. */ map = (AstMapping *) astCmpMap( cmap, map_reg1, 1, "", status ); /* Get a mesh of points covering the second Region. These points are within the current Frame of the second Region. */ reg2_mesh = astRegMesh( reg2 ); /* Transform this mesh into the base Frame of the first Region. */ ps1 = astTransform( map, reg2_mesh, 1, NULL ); /* Check there are some good points in the transformed pointset. */ good = 0; np = astGetNpoint( ps1 ); nc = astGetNcoord( ps1 ); ptr1 = astGetPoints( ps1 ); if( ptr1 ) { for( i = 0; i < nc && !good; i++ ) { for( j = 0; j < np; j++ ) { if( ptr1[ i ][ j ] != AST__BAD ) { good = 1; break; } } } } /* If the transformed mesh contains no good points, swap the regions and try again. */ if( !good ) { fs = astAnnul( fs ); frm_reg1 = astAnnul( frm_reg1 ); map_reg1 = astAnnul( map_reg1 ); cmap = astAnnul( cmap ); map = astAnnul( map ); reg2_mesh = astAnnul( reg2_mesh ); ps1 = astAnnul( ps1 ); if( first ) { first = 0; if( !bnd_that ) { reg1 = this; reg2 = that; bnd1 = bnd_this; bnd2 = bnd_that; reg1_neg = this_neg; reg2_neg = that_neg; } else { reg1 = that; reg2 = this; bnd1 = bnd_that; bnd2 = bnd_this; reg1_neg = that_neg; reg2_neg = this_neg; } goto L1; } else { return 0; } } /* Also transform the Region describing the positional uncertainty within the second supplied Region into the base Frame of the first supplied Region. */ unc = astGetUncFrm( reg2, AST__CURRENT ); bfrm_reg1 = astGetFrame( reg1->frameset, AST__BASE ); unc1 = astMapRegion( unc, map, bfrm_reg1 ); /* See if all points within this transformed mesh fall on the boundary of the first Region, to within the joint uncertainty of the two Regions. If so the two Regions have equivalent boundaries. We can only do this is the first region is bounded. */ if( astRegPins( reg1, ps1, unc1, &mask ) && good ) { /* If the boundaries are equivalent, the Regions are either identical or are mutually exclusive. To distinguish between these cases, we looked at the Bounded attributes. If the Bounded attribute is the same for both Regions then they are identical, otherwise they are mutually exclusive. */ result = ( ( !reg1_neg && bnd1 ) == ( !reg2_neg && bnd2 ) ) ? 5 : 6; /* If the boundaries of the two Regions are not equivalent. */ } else { /* Create a new PointSet containing those points from the mesh which are not on the boundary of the first Region. These points are identified by the mask array created by the astRegPins method above. */ reg2_submesh = GetSubMesh( mask, reg2_mesh, status ); /* Transform the points in the submesh of the second Region into the current Frame of the first Region. */ (void ) astAnnul( ps1 ); ps1 = astTransform( cmap, reg2_submesh, 1, NULL ); /* Transform this submesh using the first Region as a Mapping. Any points outside the first region will be set bad in the output PointSet. */ ps2 = astTransform( (AstMapping *) reg1, ps1, 1, NULL ); /* Get the number of axes and points in this PointSet. */ nc = astGetNcoord( ps2 ); np = astGetNpoint( ps2 ); /* Note if there were any common points (i.e. points on the boundary of both regions). */ touch = ( astGetNpoint( reg2_mesh ) != np ); /* Get pointers to the axis data in this PointSet, and check they can be used safely. */ ptr = astGetPoints( ps2 ); if( astOK ) { /* Loop round all points checking if the axis values are bad. We want a flag saying if there are any good axis values and another flag saying if there are any bad axis values. */ allbad = 1; allgood = 1; for( iax = 0; iax < nc; iax++ ) { p = ptr[ iax ]; for( ip = 0; ip < np; ip++,p++ ) { if( *p == AST__BAD ) { allgood = 0; if( !allbad ) break; } else { allbad = 0; if( !allgood ) break; } } } /* If the entire mesh of the (potentially negated) second Region was either on the boundary of, or inside, the (potentially negated) first region, determine the result depending on whether the regions have been negated and whether they are bounded. Check for impossible states (or maybe just errors in my logic). */ if( allgood ) { /* Second region has a mesh so it must be bounded. */ if( !bnd2 && astOK ) { astError( AST__INTER, "astOverlap(%s): Inconsistent " "state 1 (internal AST programming error).", status, astGetClass( this ) ); /* If the first region has been made bounded by negating it... */ } else if( reg1_neg ) { if( bnd1 ) { /* If the second region has been made bounded by negating it, then the unnegated first region is completely inside the unnegated second region. */ if( reg2_neg ) { result = 2; /* If the second region was bounded without negating it, then there is no overlap between the unnegated first region and the second region. */ } else { result = 1; } /* If the first region has been negated then it should not be unbounded. This is ensured by the nature of the code that sets the "this_neg" and "that_neg" flags above. */ } else if( astOK ) { astError( AST__INTER, "astOverlap(%s): Inconsistent " "state 2 (internal AST programming error).", status, astGetClass( this ) ); } /* If the first region was bounded without negating it, but the second region was made bounded by negating it, there is partial overlap. */ } else if( reg2_neg ) { result = 4; /* If the first region was bounded without negating it, but the second region was also bounded without negating it, the second region is completely inside the first region. */ } else { result = 3; } /* If part of the mesh of the second Region was inside the first region, and part was outside, then there is partial ocverlap. */ } else if( !allbad ) { result = 4; /* If no part of the mesh of the (possibly negated) second Region was inside the (possibly negated) first region ... */ } else { /* First deal with cases where the first region is unbounded. */ if( !bnd1 ) { if( reg1_neg && astOK ) { astError( AST__INTER, "astOverlap(%s): Inconsistent " "state 5 (internal AST programming error).", status, astGetClass( this ) ); } else if( reg2_neg ){ result = 2; } else { result = 1; } /* The second region has a mesh so it must be bounded. */ } else if( !bnd2 && astOK ) { astError( AST__INTER, "astOverlap(%s): Inconsistent " "state 6 (internal AST programming error).", status, astGetClass( this ) ); /* So now we know both (possibly negated) regions are bounded. */ } else { /* We know that none of the reg2 mesh points are inside the bounded reg1. But this still leaves two cases: 1) reg1 could be contained completely within reg2, or 2) there is no overlap between reg2 and reg1. To distinguish between these two cases we use reg2 to transform a point on the boundary of reg1. First get a mesh on the boundary of reg1. */ reg1_mesh = astRegMesh( reg1 ); /* Transform this mesh into the coordinate system of the second Region. */ ps3 = astTransform( cmap, reg1_mesh, 0, NULL ); /* Transform the points in this mesh using the second Region as a Mapping. Any points outside the second region will be set bad in the output PointSet. */ ps4 = astTransform( (AstMapping *) reg2, ps3, 1, NULL ); /* Get pointers to the axis data in this PointSet,and check they can be used safely. */ ptr = astGetPoints( ps4 ); if( astOK ) { /* Test the firts point and set a flag indicating if we are in case 1 (if not, we must be in case 2). */ case1 = ( ptr[ 0 ][ 0 ] != AST__BAD ); /* Apply logic similar to the other cases to determine the result. */ if( reg1_neg ) { if( case1 == ( reg2_neg != 0 ) ) { result = 3; } else { result = 4; } } else { if( case1 == ( reg2_neg != 0 ) ) { result = 1; } else { result = 2; } } } /* Free resources. */ reg1_mesh = astAnnul( reg1_mesh ); ps3 = astAnnul( ps3 ); ps4 = astAnnul( ps4 ); } } } /* If there was no intersection or overlap, but the regions touch, then we consider there to be an intersection if either region is closed. */ if( touch && result == 1 ) { if( astGetClosed( this) || astGetClosed( that ) ) result = 4; } /* Free resources.*/ reg2_submesh = astAnnul( reg2_submesh ); ps2 = astAnnul( ps2 ); } /* Free resources.*/ fs = astAnnul( fs ); bfrm_reg1 = astAnnul( bfrm_reg1 ); frm_reg1 = astAnnul( frm_reg1 ); map_reg1 = astAnnul( map_reg1 ); cmap = astAnnul( cmap ); map = astAnnul( map ); ps1 = astAnnul( ps1 ); reg2_mesh = astAnnul( reg2_mesh ); unc = astAnnul( unc ); unc1 = astAnnul( unc1 ); if( mask) mask = astFree( mask ); } fs0 = astAnnul( fs0 ); /* The returned value should take account of whether "this" or "that" is the first Region. If "this" was used as the first Region, then the result value calculated above is already correct. If "that" was used as the first Region, then we need to change the result to swap "this" and "that". */ if( reg1 == that ) { if( result == 2 ) { result = 3; } else if( result == 3 ) { result = 2; } } /* Re-instate the original Negated flags. */ if( this_neg ) astNegate( this ); if( that_neg ) astNegate( that ); /* If not OK, return zero. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static void Overlay( AstFrame *template_frame, const int *template_axes, AstFrame *result, int *status ) { /* * Name: * Overlay * Purpose: * Overlay the attributes of a template Region on to another Frame. * Type: * Private function. * Synopsis: * #include "region.h" * void Overlay( AstFrame *template, const int *template_axes, * AstFrame *result, int *status ) * Class Membership: * Region member function (over-rides the protected astOverlay * method inherited from the Frame class). * Description: * This function overlays attributes from the current Frame of a * Region on to another Frame, so as to over-ride selected * attributes of that second Frame. Normally only those attributes * which have been specifically set in the template will be * transferred. This implements a form of defaulting, in which a * Frame acquires attributes from the template, but retains its * original attributes (as the default) if new values have not * previously been explicitly set in the template. * Parameters: * template * Pointer to the template Region, for whose current Frame * values should have been explicitly set for any attribute * which is to be transferred. * template_axes * Pointer to an array of int, with one element for each axis of * the "result" Frame (see below). For each axis in the result * frame, the corresponding element of this array should contain * the (zero-based) index of the axis in the current Frame of * the template Region to which it corresponds. This array is * used to establish from which template Frame axis any * axis-dependent attributes should be obtained. * * If any axis in the result Frame is not associated with a * template Frame axis, the corresponding element of this array * should be set to -1. * * If a NULL pointer is supplied, the template and result axis * indicies are assumed to be identical. * result * Pointer to the Frame which is to receive the new attribute values. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the current Frame in the Region and invoke its astOverlay method to overlay its attributes. Annul the Frame pointer afterwards. */ fr = astGetFrame( ((AstRegion *) template_frame)->frameset, AST__CURRENT ); astOverlay( fr, template_axes, result ); fr = astAnnul( fr ); } static void PermAxes( AstFrame *this_frame, const int perm[], int *status ) { /* * Name: * PermAxes * Purpose: * Permute the order of a Region's axes. * Type: * Private function. * Synopsis: * #include "region.h" * void PermAxes( AstFrame *this, const int perm[], int *status ) * Class Membership: * Region member function (over-rides the astPermAxes method * inherited from the Frame class). * Description: * This function permutes the order in which the axes in the * current Frame of a Region occur. * Parameters: * this * Pointer to the Region. * perm * An array of int (with one element for each axis of the * Region's current Frame) which lists the axes in their new * order. Each element of this array should be a (zero-based) * axis index identifying the axes according to their old * (un-permuted) order. * status * Pointer to the inherited status variable. * Notes: * - Only genuine permutations of the axis order are permitted, so * each axis must be referenced exactly once in the "perm" array. * - If more than one axis permutation is applied to the same Frame * in a Region, the effects are cumulative. */ /* Local Variables: */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Invoke the astPermAxes method on the encapsulated FrameSet. */ astPermAxes( this->frameset, perm ); } static AstFrame *PickAxes( AstFrame *this_frame, int naxes, const int axes[], AstMapping **map, int *status ) { /* * Name: * PickAxes * Purpose: * Create a new Frame by picking axes from a Region. * Type: * Private function. * Synopsis: * #include "region.h" * AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[], * AstMapping **map, int *status ) * Class Membership: * Region member function (over-rides the astPickAxes protected * method inherited from the Frame class). * Description: * This function creates a new Frame whose axes are copies of axes * picked from the encapsulated Frame of an existing Region. Other * Frame attributes are also copied from this existing Frame to the * new Frame. Zero or more of the original axes may be picked in * any order, but each can be used only once. Additional axes (with * default characteristics) may be included in the new Frame if * required. * * Optionally, a Mapping that converts between the original Frame's * axes and those of the new Frame may also be returned. * Parameters: * this * Pointer to the Region. * naxes * The number of axes required in the new Frame. * axes * Pointer to an array of int with naxes elements. This should * contain (zero based) axis indices specifying the axes which * are to be included in the new Frame, in the order * required. Each axis index may occur only once. * * If additional (default) axes are also to be included, the * corresponding elements of this array should be set to -1. * map * Address of a location to receive a pointer to a new * Mapping. This will be a PermMap (or a UnitMap as a special * case) that describes the axis permutation that has taken * place between the current Frame of the Region and the new * Frame. The forward transformation will convert from the * original Region's axes to the new one's, and vice versa. * * If this Mapping is not required, a NULL value may be supplied * for this parameter. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the new Frame. * Notes: * - The class of object returned may differ from that of the * original current Frame, depending on which axes are * selected. For example, if a single axis is picked from a * SkyFrame (which always has two axes), the resulting Frame cannot * be a valid SkyFrame, so will revert to the parent class (Frame) * instead. * - The new Frame contains a deep copy of all the data selected * from the original current Frame. Modifying the new Frame will * therefore not affect the Region or the Frames it contains. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *cfrm; /* Current Frame from input Region */ AstFrame *frame; /* Pointer to Frame to be returned */ AstMapping *cbmap; /* Base->current Mapping from input Region */ AstMapping *fsmap; /* Mapping from selected current to base axes */ AstRegion *breg; /* Region spanning selected base Frame axes */ AstRegion *creg; /* Region spanning selected current Frame axes */ AstRegion *this; /* Pointer to Region structure */ int *base_axes; /* Holds selected base frame axis indices */ int def; /* Were any default axes requested? */ int i; /* Axis index */ int nbase; /* No. of selected base Frame axes */ /* Initialise the returned pointers. */ if ( map ) *map = NULL; frame = NULL; /* Check the global error status. */ if ( !astOK ) return frame; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Check that a valid set of axes is being selected . */ astValidateAxisSelection( this, naxes, axes, "astPickAxes" ); /* Pick the required axes from the current Frame of the encapsulated FrameSet. */ cfrm = astGetFrame( this->frameset, AST__CURRENT ); frame = astPickAxes( cfrm, naxes, axes, map ); /* See if any default axes are to be included in the returned Frame. */ def = 0; for( i = 0; i < naxes; i++ ) { if( axes[ i ] < 0 ) def = 1; } /* Regions cannot yet include extra default axes in the returned Frame so return a basic Frame if any default axes were requested. */ if( ! def ) { /* We now see if the requested set of current Frame axes correspond to a unique set of base Frame axes. If they do, we may be able to return a Region spanning the selected axes rather than just a Frame. The check is performed by attempting to split the current->base Mapping. */ cbmap = astGetMapping( this->frameset, AST__CURRENT, AST__BASE ); base_axes = astMapSplit( cbmap, naxes, axes, &fsmap ); /* Check the Mapping could be split. */ if( base_axes ) { /* Store the number of base Frame axes that correspond to the requested set of current Frame axes. */ nbase = astGetNout( fsmap ); /* Attempt to create a new Region that spans the corresponding set of base Frame axes. */ breg = astRegBasePick( this, nbase, base_axes ); if( breg ) { /* Use the split Mapping to map the base Frame region into the requested Frame. We invert the "fsmap" first so that it maps the selected base Frame axes into the selected current Frame axes. */ astInvert( fsmap ); creg = astMapRegion( breg, fsmap, frame ); /* Copy properties from the old Region to the new Region. */ astRegOverlay( creg, this, 0 ); /* Return this new Region in place of the simple Frame found above. */ (void) astAnnul( frame ); frame = (AstFrame *) creg; /* Free resources */ breg = astAnnul( breg ); } fsmap = astAnnul( fsmap ); base_axes = astFree( base_axes ); } cbmap = astAnnul( cbmap ); } cfrm = astAnnul( cfrm ); /* If an error occurred, annul the Mapping pointer (if requested) and the new Frame pointer. */ if ( !astOK ) { if ( map ) *map = astAnnul( *map ); frame = astAnnul( frame ); } /* Return the pointer to the new Frame. */ return frame; } static void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *+ * Name: * astRegBaseBox * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Protected function. * Synopsis: * #include "region.h" * void astRegBaseBox( AstRegion *this, double *lbnd, double *ubnd ) * Class Membership: * Region virtual function. * Description: * This function returns the upper and lower axis bounds of a Region in * the base Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. *- */ /* Check the inherited status. */ if( !astOK ) return; /* This abstract implementation simply reports an error. All sub-classes of Region should over-ride this to return appropriate values. */ astError( AST__INTER, "astRegBaseBox(%s): The %s class does not implement " "the astRegBaseBox method inherited from the Region class " "(internal AST programming error).", status, astGetClass( this ), astGetClass( this ) ); } static void RegBaseBox2( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *+ * Name: * astRegBaseBox2 * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Protected function. * Synopsis: * #include "region.h" * void astRegBaseBox2( AstRegion *this, double *lbnd, double *ubnd ) * Class Membership: * Region virtual function. * Description: * This function is similar to astRegBaseBox in that it returns the * upper and lower axis bounds of a Region in the base Frame of the * encapsulated FrameSet. But, in addition to assuming that the * supplied Region has not been negated, it also assumes that any * component Regions contained within the supplied Region have not been * negated. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. *- */ /* This base class implementation simply calls astRegBaseBox. Sub-classes which contain component Regions should override it. */ astRegBaseBox( this, lbnd, ubnd ); } static AstPointSet *RegBaseGrid( AstRegion *this, int *status ){ /* *+ * Name: * astRegBaseGrid * Purpose: * Return a PointSet containing points spread through the volume of a * Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astRegBaseGrid( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a set of points spread * through the volume of the Region. The points refer to the base Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * Returned Value: * Pointer to the PointSet. If the Region is unbounded, a NULL pointer * will be returned. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables: */ AstBox *box; AstFrame *frmb; AstPointSet *ps1; AstPointSet *ps2; AstPointSet *result; double **ptr2; double **ptr; double *lbnd; double *ubnd; int good; int ic; int ip; int ipr; int meshsize; int naxb; int np; int npnt2; int ntry; /* Initialise */ result= NULL; /* Check the local error status. */ if ( !astOK ) return NULL; /* If the Region structure contains a pointer to a PointSet holding positions spread over the volume of the Region in the base Frame, return it. */ if( this->basegrid ) { result = astClone( this->basegrid ); /* Otherwise, check the Region is bounded. */ } else if( astGetBounded( this ) ) { /* Get the original MeshSize attribute. */ meshsize = astGetMeshSize( this ); /* Get the base Frame bounding box. */ naxb = astGetNin( this->frameset ); lbnd = astMalloc( sizeof( double )*(size_t)naxb ); ubnd = astMalloc( sizeof( double )*(size_t)naxb ); astRegBaseBox( this, lbnd, ubnd ); /* Create a Box covering this bounding box. */ frmb = astGetFrame( this->frameset, AST__BASE ); box = astBox( frmb, 1, lbnd, ubnd, NULL, "", status ); /* Loop until we have a grid of nearly the right size. Make at most three attempts. */ ipr = 0; np = meshsize; ntry = 0; while( ntry++ < 3 ) { /* Copy the MeshSize attribute to the new Box since this will be used by the invocation of astRegBaseGrid below. */ astSetMeshSize( box, np ); /* Invoke the Box astRegGrid method. Note, the Box class overrides this implementation of astRegBaseGrid and does not (must not) invoke this implementation, in order to avoid an infinite loop. */ ps1 = astRegBaseGrid( box ); /* Some of the base Frame points in the above bounding box will fall outside the supplied Region. Use the Region as a Mapping to determine which they are. Since the points are base Frame points, use astBTransform rather than astTransform. */ ps2 = astBTransform( this, ps1, 1, NULL ); /* We now create a PointSet which is a copy of "ps2" but with all the bad points (i.e. the points in the bounding box grid which are not inside the supplied Region) removed. Create a result PointSet which is the same size as "ps2", then copy just the good points from "ps2" to the result PointSet, keeping a record of the number of points copied. */ ptr2 = astGetPoints( ps2 ); npnt2 = astGetNpoint( ps2 ); result = astPointSet( npnt2, naxb, "", status ); ptr = astGetPoints( result ); if( astOK ) { /* Initialise the index of the next point to be stored in "result". */ ipr = 0; /* Loop round all points in "ps2" */ for( ip = 0; ip < npnt2; ip++ ) { /* Copy each axis value for this point from "ps2" to "result". If a bad axis value is encountered, flag that the point is bad and break out of the axis loop. */ good = 1; for( ic = 0; ic < naxb; ic++ ) { if( ptr2[ ic ][ ip ] == AST__BAD ) { good = 0; break; } else { ptr[ ic ][ ipr ] = ptr2[ ic ][ ip ]; } } /* If the current point has no bad axis values, increment the index of the next point to be stored in "result". */ if( good ) ipr++; } } /* Free resources */ ps1 = astAnnul( ps1 ); ps2 = astAnnul( ps2 ); /* Leave the loop if an error has occurred. */ if( !astOK ) break; /* If the number of points in the grid is within 5% of the target value, it is good enough, so break. */ if( fabs( (double)( ipr - meshsize ) )/meshsize < 0.05 ) break; /* Otherwise, adjust the target size of the grid by the ratio by which it is in error. Don't do this if we have reached the maximum number of re-tries. */ if( ntry < 3 ) { if( ipr == 0 ) { np *= 10; } else { np *= (double)meshsize/(double)ipr; } result = astAnnul( result ); } } /* Truncate the "result" PointSet to exclude any unused space at the end of the axis values arrays. */ if( astOK ) astSetNpoint( result, ipr ); /* Free resources */ lbnd = astFree( lbnd ); ubnd = astFree( ubnd ); frmb = astAnnul( frmb ); box = astAnnul( box ); /* Cache the new grid for future use. */ if( astOK ) this->basegrid = astClone( result ); } /* Annul the result if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result */ return result; } static AstRegion **RegSplit( AstRegion *this, int *nlist, int *status ){ /* *+ * Name: * astRegSplit * Purpose: * Split a Region into a list of disjoint component Regions. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion **astRegSplit( AstRegion *this, int *nlist ) * Class Membership: * Region virtual function. * Description: * This function splits the supplied Region into a set of disjoint * component Regions. If the Region cannot be split, then the returned * array contains only one pointer - a clone of the supplied Region * pointer. * Parameters: * this * Pointer to the Region. * nlist * Pointer to an int in which to return the number of elements in * the returned array. * Returned Value: * Pointer to dynamically alloctaed memory holding an array of Region * pointers. The length of this array is given by the value returned * in "*nlist". The pointers in the returned array should be annulled * using astAnnul when no longer needed, and the memory used to hold * the array should be freed using astFree. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables; */ AstRegion **result; /* Initialise. */ result = NULL; *nlist = 0; /* Check the local error status. */ if ( !astOK ) return result; /* The base class just returns an array containing a clone of the supplied Region pointer. */ result = astMalloc( sizeof( *result ) ); if( astOK ) { result[ 0 ] = astClone( this ); *nlist = 1; } if( !astOK ) { result = astFree( result ); *nlist = 0; } return result; } static AstPointSet *RegBaseMesh( AstRegion *this, int *status ){ /* *+ * Name: * astRegBaseMesh * Purpose: * Return a PointSet containing points spread around the boundary of a * Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astRegBaseMesh( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a set of points on the * boundary of the Region. The points refer to the base Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * Returned Value: * Pointer to the PointSet. The axis values in this PointSet will have * associated accuracies derived from the uncertainties which were * supplied when the Region was created. * * If the Region has no boundary (i.e. is equivalent to a NullRegion), the * returned PointSet will contain a single point with a value of AST__BAD * on every axis. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Check the local error status. */ if ( !astOK ) return NULL; /* This abstract method must be over-ridden by each concrete sub-class. Report an error if this null imlementation is called.*/ astError( AST__INTER, "astRegBaseMesh(%s): The %s class does not implement " "the astRegBaseMesh method inherited from the Region class " "(internal AST programming error).", status, astGetClass( this ), astGetClass( this ) ); return NULL; } static AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes, int *status ){ /* *+ * Name: * astRegBasePick * Purpose: * Return a Region formed by picking selected base Frame axes from the * supplied Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *astRegBasePick( AstRegion *this, int naxes, const int *axes ) * Class Membership: * Region virtual function. * Description: * This function attempts to return a Region that is spanned by selected * axes from the base Frame of the encapsulated FrameSet of the supplied * Region. This may or may not be possible, depending on the class of * Region. If it is not possible a NULL pointer is returned. * Parameters: * this * Pointer to the Region. * naxes * The number of base Frame axes to select. * axes * An array holding the zero-based indices of the base Frame axes * that are to be selected. * Returned Value: * Pointer to the Region, or NULL if no region can be formed. * Notes: * - This base implementation returns NULL unless all base Frame axes * are selected (possibly in a permuted order). * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables: */ AstFrame *fr; /* Pointer to the Region's base Frame */ AstRegion *result; /* The returned Region pointer */ int found; /* Has the current axis index been found yet? */ int i; /* Axis index */ int j; /* Index into the "axes" array */ int nax; /* No. of base Frame axes */ int ok; /* Are we doing a genuine axis permutation? */ int unit; /* Is the axis permutation a unit map? */ /* Initialise */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* Get a pointer to the base Frame int he encapsulated FrameSet. */ fr = astGetFrame( this->frameset, AST__BASE ); /* See how many axes it has. We only proceed if we are selecting all axes in the base Frame. */ nax = astGetNaxes( fr ); if( nax == naxes ) { /* We now check that the axes array is a genuine permutation of all axes. This means that all axis indices must occur once, and only once, within the "axes" array. Look for each axis index in turn. */ unit = 1; ok = 1; for( i = 0; i < nax && ok; i++ ) { /* Check each element of the axes array to see if it holds the axis index currently being looked for. */ found = 0; for( j = 0; j < nax; j++ ) { /* If so, if this axis index has already been found, break out of the loop. */ if( axes[ j ] == i ) { if( found ) { ok = 0; break; } found = 1; /* Note if we do not have a unit map (i.e. each axis is permuted onto itself). */ if( i != j ) unit = 0; } } /* If the axis index was not found, we do not have a genuine axis permutation. */ if( !found ) ok = 0; } /* If we have a genuine axis permutation, create a Region which is a copy of the supplied region and set it to represent its base Frame. */ if( ok ) { result = astCopy( this ); astSetRegFS( result, fr ); /* If the axis selection is not equivalent to a unit mapping, we now permute the axes. */ if( !unit ) astPermAxes( result, axes ); } } /* Free resources. */ fr = astAnnul( fr ); /* Returned the result. */ return result; } static double *RegCentre( AstRegion *this, double *cen, double **ptr, int index, int ifrm, int *status ){ /* *+ * Name: * astRegCentre * Purpose: * Re-centre a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * double *astRegCentre( AstRegion *this, double *cen, double **ptr, * int index, int ifrm ) * Class Membership: * Region virtual function. * Description: * This function shifts the centre of the supplied Region to a * specified position, or returns the current centre of the Region. * Parameters: * this * Pointer to the Region. * cen * Pointer to an array of axis values, giving the new centre. * Supply a NULL value for this in order to use "ptr" and "index" to * specify the new centre. * ptr * Pointer to an array of pointers, one for each axis in the Region. * Each pointer locates an array of axis values. This is the format * returned by the PointSet method astGetPoints. Only used if "cen" * is NULL. * index * The index of the point within the arrays identified by "ptr" at * which is stored the coords for the new centre position. Only used * if "cen" is NULL. * ifrm * Should be AST__BASE or AST__CURRENT. Indicates whether the centre * position is supplied and returned in the base or current Frame of * the FrameSet encapsulated within "this". * Returned Value: * If both "cen" and "ptr" are NULL then a pointer to a newly * allocated dynamic array is returned which contains the centre * coords of the Region. This array should be freed using astFree when * no longer needed. If either of "ptr" or "cen" is not NULL, then a * NULL pointer is returned. * Notes: * - Any bad (AST__BAD) centre axis values are ignored. That is, the * centre value on such axes is left unchanged. * - Some Region sub-classes do not have a centre. Such classes will report * an AST__INTER error code if this method is called with either "ptr" or * "cen" not NULL. If "ptr" and "cen" are both NULL, then no error is * reported if this method is invoked on a Region of an unsuitable class, * but NULL is always returned. *- */ /* Local Variables: */ double *result; /* Initialise */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* This abstract method must be over-ridden by each concrete sub-class which allows the centre to be shifted. Report an error if this null imlementation is called to set a new centre. If it is called to enquire the current centre, then return a NULL pointer. */ if( ptr || cen ) astError( AST__INTER, "astRegCentre(%s): The %s " "class does not implement the astRegCentre method " "inherited from the Region class (internal AST " "programming error).", status, astGetClass( this ), astGetClass( this ) ); return NULL; } static void RegClearAttrib( AstRegion *this, const char *aattrib, char **base_attrib, int *status ) { /* *+ * Name: * astRegClearAttrib * Purpose: * Clear an attribute value for a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * void astRegClearAttrib( AstRegion *this, const char *aattrib, * char **base_attrib ) * Class Membership: * Region virtual function * Description: * This function clears the value of a named attribute in both the base * and current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * aattrib * Pointer to a null terminated string holding the attribute name. * base_attrib * Address of a location at which to return a pointer to the null * terminated string holding the attribute name which was cleared in * the base Frame of the encapsulated FrameSet. This may differ from * the supplied attribute if the supplied attribute contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. *- */ /* Local Variables: */ AstFrame *frm; AstMapping *junkmap; AstMapping *map; AstRegion *unc; char *attrib; char *battrib; char buf1[ 100 ]; int *outs; int axis; int baxis; int i; int len; int nc; int rep; /* Check the global error status. */ if ( !astOK ) return; /* Produce a lower case version of the attribute name string */ nc = strlen( aattrib ); attrib = astMalloc( nc + 1 ); for( i = 0; i < nc; i++ ) attrib[ i ] = tolower( aattrib[ i ] ); attrib[ nc ] = 0; /* Clear the attribute in the current Frame in the encapsulated FrameSet. Use the protected astClearAttrib method which does not cause the Frame to be remapped within the FrameSet. */ frm = astGetFrame( this->frameset, AST__CURRENT ); astClearAttrib( frm, attrib ); frm = astAnnul( frm ); /* Indicate that we should use the supplied attribute name with the base Frame. */ battrib = NULL; /* If the attribute name contains an axis number, we need to create a new attribute name which refers to the corresponding base Frame axis (since the base<->current Mapping may permute the axes). First parse the supplied attribute name to locate any axis index. */ len = strlen( attrib ); if( nc = 0, ( 2 == astSscanf( attrib, "%[^(](%d) %n", buf1, &axis, &nc ) ) && ( nc >= len ) ) { /* If found, convert the axis index from one-based to zero-based. */ axis--; /* See if the specified current Frame axis is connected to one and only one base Frame axis. If so, get the index of the base Frame axis. */ map = astGetMapping( this->frameset, AST__CURRENT, AST__BASE ); outs = astMapSplit( map, 1, &axis, &junkmap ); if( junkmap && astGetNout( junkmap ) == 1 ) { baxis = outs[ 0 ]; /* If the base Frame axis index is different to the current Frame axis index, create a new attribute name string using the base Frame axis index. */ if( baxis != axis ) { battrib = astMalloc( strlen( attrib ) + 10 ); if( battrib ) sprintf( battrib, "%s(%d)", buf1, baxis + 1 ); } /* If there is no one base Frame axis which corresponds to the supplied current Frame axis, report an error. */ } else if( astOK ) { astError( AST__INTER, "astRegClearAttrib(%s): Unable to clear " "attribute \"%s\" in the base Frame of the %s", status, astGetClass( this ), attrib, astGetClass( this ) ); astError( AST__INTER, "There is no base Frame axis corresponding " "to current Frame axis %d\n", status, axis + 1 ); } /* Free resources */ outs = astFree( outs ); if( junkmap ) junkmap = astAnnul( junkmap ); map = astAnnul( map ); } /* Clear the appropriate attribute name in the base Frame. This time ensure that any error caused by the attribute name is annulled. Also clear it in any uncertainty Region (the current Frame of the uncertainty Region is assumed to be equivalent to the base Frame of the parent Region). */ frm = astGetFrame( this->frameset, AST__BASE ); if( frm ) { rep = astReporting( 0 ); astClearAttrib( frm, battrib ? battrib : attrib ); if( astTestUnc( this ) ) { unc = astGetUncFrm( this, AST__BASE ); astRegClearAttrib( unc, battrib ? battrib : attrib, NULL ); unc = astAnnul( unc ); } if( astStatus == AST__BADAT ) astClearStatus; astReporting( rep ); } frm = astAnnul( frm ); /* If required return the modified base Frame attribute name. Otherwise, free it. */ if( base_attrib ) { if( battrib ) { *base_attrib = battrib; } else { *base_attrib = astStore( NULL, attrib, strlen( attrib ) + 1 ); } } else { battrib = astFree( battrib ); } /* Since the base Frame has been changed, any cached information calculated on the basis of the base Frame properties may no longer be up to date. */ astResetCache( this ); /* Free resources. */ attrib = astFree( attrib ); } static AstPointSet *RegGrid( AstRegion *this, int *status ){ /* *+ * Name: * astRegGrid * Purpose: * Return a PointSet containing points spread through the volume of a * Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astRegGrid( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a mesh of points spread * throughout the volume of the Region. The points refer to the current * Frame of the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * Returned Value: * Pointer to the PointSet. The axis values in this PointSet will have * associated accuracies derived from the uncertainties which were * supplied when the Region was created. Annul the pointer using * astAnnul when it is no longer needed. * Notes: * - It should not be assumed that the returned points are evenly * spaced withint he volume. * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables; */ AstMapping *map; /* Base -> current Frame Mapping */ AstPointSet *result; /* Pointer to returned PointSet */ /* Initialise the returned pointer */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* If the Region structure does not contain a pointer to a PointSet holding positions evenly spread over the volume of the Region in the base Frame, create one now. Note, we cannot cache the grid in the current Frame in this way since the current Frame grid depends on the proprties of the current Frame (e.g. System) which can be changed at any time. */ if( !this->basegrid ) this->basegrid = astRegBaseGrid( this ); /* Get the simplified base->current Mapping */ map = astRegMapping( this ); /* If the Mapping is a UnitMap, just return a clone of the PointSet pointer stored in the Region structure. */ if( astIsAUnitMap( map ) ){ result = astClone( this->basegrid ); /* Otherwise, create a new PointSet holding the above points transformed into the current Frame. */ } else { result = astTransform( map, this->basegrid, 1, NULL ); } /* Free resources.*/ map = astAnnul( map ); /* If an error has occurred, annul the returned PointSet. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *RegMesh( AstRegion *this, int *status ){ /* *+ * Name: * astRegMesh * Purpose: * Return a PointSet containing points spread over the boundary of a * Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astRegMesh( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a PointSet containing a mesh of points on the * boundary of the Region. The points refer to the current Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * Returned Value: * Pointer to the PointSet. The axis values in this PointSet will have * associated accuracies derived from the uncertainties which were * supplied when the Region was created. Annul the pointer using * astAnnul when it is no longer needed. * Notes: * - It should not be assumed that the returned points are evenly * spaced on the boundary. * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables; */ AstMapping *map; /* Base -> current Frame Mapping */ AstPointSet *bmesh; /* Base Frame mesh */ AstPointSet *result; /* Pointer to returned PointSet */ /* Initialise the returned pointer */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* Get a pointer to a PointSet holding positions evenly spread over the boundary of the Region in the base Frame. */ bmesh = astRegBaseMesh( this ); /* Get the simplified base->current Mapping */ map = astRegMapping( this ); /* If the Mapping is a UnitMap, just return a clone of the mesh PointSet pointer. */ if( astIsAUnitMap( map ) ){ result = astClone( bmesh ); /* Otherwise, create a new PointSet holding the above points transformed into the current Frame. */ } else { result = astTransform( map, bmesh, 1, NULL ); } /* Free resources.*/ bmesh = astAnnul( bmesh ); map = astAnnul( map ); /* If an error has occurred, annul the returned PointSet. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static int RegDummyFS( AstRegion *this, int *status ){ /* *+ * Name: * astRegDummyFS * Purpose: * Check if a Region has a dummy FrameSet. * Type: * Protected function. * Synopsis: * #include "region.h" * int astRegDummyFS( AstRegion *this ) * Class Membership: * Region virtual function. * Description: * This function returns a flag indicating if the supplied Region has * a dummy FrameSet. * * The astDump method for a Region may choose not to include the * Region's FrameSet in the dump, depending on the value of the * RegionFS attribute and the nature of the FrameSet. If the FrameSet * is omitted from the Dump, then special action has to be taken when * the dump is subsequently read in and used to re-create the Region. * On encounterting such a dump, the astLoadRegion function will create * a dummy FrameSet and associate it with the reconstructed Region. * The new Region should not be used however until this dummy FrameSet * has been replaced by the correct FrameSet. Performing this replacement * is the responsibility of the parent class (i.e. the class which choose * to omit the FrameSet from the dump). These will usually be Region * classes which encapsulate other Regions, such as CmpRegion, Prism, * Stc, etc. * * This function can be used by astLoad... methods in sub-classes to * determine if a newly loaded component Region has a dummy FrameSet. If * so the astLoad function should either use the astSetRegFS method to * store a new FrameSet in the component Region. If the parent Region * itself has a dummy FrameSet (i.e. is a component Region contained * within a higher level Region) then it cannot do this and should * ignore the presence of the dummy FrameSet (it then becomes the * responsibility of hte parent Region to load appropriate FrameSets * into all its components). * Parameters: * this * Pointer to the Region. * Returned Value: * Non-zero if the Region has a dummy FrameSet. *- */ /* Check the inherited status. */ if( !astOK ) return 0; /* The Ident attribute of the FrameSet will be set to DUMMY_FS if the FrameSet is a dummy. */ return !strcmp( astGetIdent( this->frameset ), DUMMY_FS ); } static int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, int **mask, int *status ){ /* *+ * Name: * astRegPins * Purpose: * Check if a set of points fall on the boundary of a given Region. * Type: * Protected function. * Synopsis: * #include "region.h" * int astRegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, * int **mask ) * Class Membership: * Region virtual function. * Description: * This function returns a flag indicating if the supplied set of * points all fall on the boundary of the given Region. * * Some tolerance is allowed, as specified by the uncertainty Region * stored in the supplied Region "this", and the supplied uncertainty * Region "unc" which describes the uncertainty of the supplied points. * Parameters: * this * Pointer to the Region. * pset * Pointer to the PointSet. The points are assumed to refer to the * base Frame of the FrameSet encapsulated by "this". * unc * Pointer to a Region representing the uncertainties in the points * given by "pset". The Region is assumed to represent the base Frame * of the FrameSet encapsulated by "this". Zero uncertainity is assumed * if NULL is supplied. * mask * Pointer to location at which to return a pointer to a newly * allocated dynamic array of ints. The number of elements in this * array is equal to the value of the Npoint attribute of "pset". * Each element in the returned array is set to 1 if the * corresponding position in "pset" is on the boundary of the Region * and is set to zero otherwise. A NULL value may be supplied * in which case no array is created. If created, the array should * be freed using astFree when no longer needed. * Returned Value: * Non-zero if the points all fall on the boundary of the given * Region, to within the tolerance specified. Zero otherwise. *- */ /* Check the inherited status. */ if( !astOK ) return 0; /* This abstract implementation simply reports an error. All sub-classes of Region should over-ride this to return appropriate values. */ astError( AST__INTER, "astRegPins(%s): The %s class does not implement " "the astRegPins method inherited from the Region class " "(internal AST programming error).", status, astGetClass( this ), astGetClass( this ) ); return 0; } static void GetRegionBounds( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *++ * Name: c astGetRegionBounds f AST_GETREGIONBOUNDS * Purpose: * Returns the bounding box of Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astGetRegionBounds( AstRegion *this, double *lbnd, double *ubnd ) f CALL AST_GETREGIONBOUNDS( THIS, LBND, UBND, STATUS ) * Class Membership: * Region method. * Description: c This function f This routine * returns the upper and lower limits of a box which just encompasses * the supplied Region. The limits are returned as axis values within * the Frame represented by the Region. The value of the Negated * attribute is ignored (i.e. it is assumed that the Region has not * been negated). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c lbnd f LBND() = DOUBLE PRECISION (Returned) c Pointer to an f An * array in which to return the lower axis bounds covered by the Region. * It should have at least as many elements as there are axes in the * Region. If an axis has no lower limit, the returned value will * be the largest possible negative value. c ubnd f UBND() = DOUBLE PRECISION (Returned) c Pointer to an f An * array in which to return the upper axis bounds covered by the Region. * It should have at least as many elements as there are axes in the * Region. If an axis has no upper limit, the returned value will * be the largest possible positive value. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - The value of the Negated attribute is ignored (i.e. it is assumed that * the Region has not been negated). * - If an axis has no extent on an axis then the lower limit will be * returned larger than the upper limit. Note, this is different to an * axis which has a constant value (in which case both lower and upper * limit will be returned set to the constant value). * - If the bounds on an axis cannot be determined, AST__BAD is returned for * both upper and lower bounds *-- */ /* Local Variables: */ AstFrame *frm; /* Current Frame */ AstMapping *smap; /* Simplified base -> current Mapping */ AstPointSet *bmesh; /* PointSet holding base Frame mesh */ AstPointSet *cmesh; /* PointSet holding current Frame mesh */ double **bptr; /* Pointer to PointSet coord arrays */ double *blbnd; /* Lower bounds in base Frame */ double *bubnd; /* Upper bounds in base Frame */ double *p; /* Array of values for current axis */ double width; /* Width of bounding box on i'th axis */ int i; /* Axis count */ int ip; /* Index of current corner */ int j; /* Timer for low/high swaps */ int jmax; /* Increment between low/high swaps */ int lo; /* Assign low bound to next corner? */ int nbase; /* Number of base Frame axes */ int ncur; /* Number of current Frame axes */ int npos; /* Number of box corners */ /* Check the inherited status. */ if( !astOK ) return; /* Get the simplified base to current Mapping. */ smap = astRegMapping( this ); /* If the simplified Mapping is a UnitMap, just store the base box bounds in the returned arrays */ if( astIsAUnitMap( smap ) ) { astRegBaseBox( this, lbnd, ubnd ); /* Otherwise, we get a mesh of points over the boundary of the Region within the base Frame, transform them into the current Frame, and find their bounds. */ } else { /* If the Region is bounded, we can get a genuine mesh of points on the boundary of the Region. */ if( astGetBounded( this ) ) { bmesh = astRegBaseMesh( this ); /* If the Region is not bounded, no mesh can be created so we use the corners of the base frame bounding box instead. */ } else { /* Get workspace to hold the bounds of the region within the base Frame. */ nbase = astGetNin( smap ); blbnd = astMalloc( sizeof( double )*nbase ); bubnd = astMalloc( sizeof( double )*nbase ); /* Get the base Frame bounding box. */ astRegBaseBox( this, blbnd, bubnd ); /* Get the number of corners in the base Frame bounding box. */ npos = pow( 2, nbase ); /* Create a PointSet to hold the positions at the corners in the base frame box. */ bmesh = astPointSet( npos, nbase, " ", status ); bptr = astGetPoints( bmesh ); if( bptr ) { /* Store the coordinates of the box corners in the PointSet. */ jmax = 1; for( i = 0; i < nbase; i++ ) { p = bptr[ i ]; lo = 1; j = 0; for( ip = 0; ip < npos; ip++,j++ ) { if( j == jmax ) { lo = 1 - lo; j = 0; } p[ ip ] = lo ? blbnd[ i ] : bubnd[ i ]; } jmax *= 2; } } /* Release resources. */ blbnd = astFree( blbnd ); bubnd = astFree( bubnd ); } /* Create a new PointSet holding the above points transformed into the current Frame. */ cmesh = astTransform( smap, bmesh, 1, NULL ); /* Get the axis bounds of this PointSet. */ astBndPoints( cmesh, lbnd, ubnd ); /* There is a possibility that these bounds may span a singularity in the coordinate system such as the RA=0 line in a SkyFrame. So for each axis we ensure the width (i.e. "ubnd-lbnd" ) is correct. */ frm = astGetFrame( this->frameset, AST__CURRENT ); ncur = astGetNaxes( frm ); for( i = 0; i < ncur; i++ ) { width = astAxDistance( frm, i + 1, lbnd[ i ], ubnd[ i ] ); if( width != AST__BAD ) { ubnd[ i ] = lbnd[ i ] + width; } else { ubnd[ i ] = AST__BAD; lbnd[ i ] = AST__BAD; } } /* Release resources. */ frm = astAnnul( frm ); bmesh = astAnnul( bmesh ); cmesh = astAnnul( cmesh ); } smap = astAnnul( smap ); } static void GetRegionBounds2( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* *+ * Name: * astGetRegionBounds * Purpose: * Returns the bounding box of Region. * Type: * Protected virtual function. * Synopsis: * #include "region.h" * void astGetRegionBounds2( AstRegion *this, double *lbnd, double *ubnd ) * Class Membership: * Region method. * Description: * This function is like astGetRegionBounds, in that it returns the upper * and lower limits of a box which just encompasses the supplied Region, * as axis values within the Frame represented by the Region. But, in * addition to assuming that the supplied Region has not been negated, it * also assumes that any component Regions contained within the supplied * Region have not been negated. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region. It should have at least as many elements * as there are axes in the Region. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region. It should have at least as many elements * as there are axes in the Region. * Notes: * - The value of the Negated attribute is ignored (i.e. it is assumed that * the Region has not been negated). The Nagated attributes of any * component Regions are also ignored. *- */ /* Local Variables: */ AstMapping *smap; /* Simplified base -> current Mapping */ double *lbndb; /* Pointer to lower bounds on base box */ double *ubndb; /* Pointer to upper bounds on base box */ int i; /* Axis count */ int nbase; /* Number of base Frame axes */ int ncur; /* Number of current Frame axes */ /* Check the inherited status. */ if( !astOK ) return; /* Find the number of axes in the base and current Frames of the encapsulated FrameSet. */ nbase = astGetNin( this->frameset ); ncur = astGetNout( this->frameset ); /* Get the bounding box in the base Frame of the encapsulated FrameSet. */ lbndb = astMalloc( sizeof( double )*(size_t) nbase ); ubndb = astMalloc( sizeof( double )*(size_t) nbase ); astRegBaseBox2( this, lbndb, ubndb ); /* Get the simplified base to current Mapping. */ smap = astRegMapping( this ); /* Check pointers can be used safely. */ if( smap ) { /* If the simplified Mapping is a UnitMap, just copy the base box bounds to the returned arrays */ if( astIsAUnitMap( smap ) ) { for( i = 0; i < ncur; i++ ) { lbnd[ i ] = lbndb[ i ]; ubnd[ i ] = ubndb[ i ]; } /* Otherwise, use astMapBox to find the corresponding current Frame limits. */ } else { for( i = 0; i < ncur; i++ ) { astMapBox( smap, lbndb, ubndb, 1, i, lbnd + i, ubnd + i, NULL, NULL ); } } } /* Release resources. */ smap = astAnnul( smap ); lbndb = astFree( lbndb ); ubndb = astFree( ubndb ); } static void GetRegionMesh( AstRegion *this, int surface, int maxpoint, int maxcoord, int *npoint, double *points, int *status ){ /* *++ * Name: c astGetRegionMesh f AST_GETREGIONMESH * Purpose: * Return a mesh of points covering the surface or volume of a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astGetRegionMesh( AstRegion *this, int surface, int maxpoint, c int maxcoord, int *npoint, double *points ) f CALL AST_GETREGIONMESH( THIS, SURFACE, MAXPOINT, MAXCOORD, NPOINT, f POINTS, STATUS ) * Class Membership: * Region method. * Description: c This function f This routine * returns the axis values at a mesh of points either covering the * surface (i.e. boundary) of the supplied Region, or filling the * interior (i.e. volume) of the Region. The number of points in * the mesh is approximately equal to the MeshSize attribute. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c surface f SURFACE = LOGICAL (Given) c If non-zero, f If .TRUE., * the returned points will cover the surface or the Region. * Otherwise, they will fill the interior of the Region. c maxpoint f MAXPOINT = INTEGER (Given) * If zero, the number of points in the mesh is returned in c "*npoint", f NPOINT, * but no axis values are returned and all other parameters are ignored. * If not zero, the supplied value should be the length of the c second dimension of the "points" f first dimension of the POINTS * array. An error is reported if the number of points in the mesh * exceeds this number. c maxcoord f MAXCOORD = INTEGER (Given) * The length of the c first dimension of the "points" array. f second dimension of the POINTS array. * An error is reported if the number of axes in the supplied Region * exceeds this number. c npoint f NPOINT = INTEGER (Returned) c A pointer to an integer in which to return the f The * number of points in the returned mesh. c points f POINTS( MAXPOINT, MAXCOORD ) = DOUBLE PRECISION (Returned) c The address of the first element in a 2-dimensional array of c shape "[maxcoord][maxpoint]", in which to return the coordinate c values at the mesh positions. These are stored such that the c value of coordinate number "coord" for point number "point" is c found in element "points[coord][point]". f An array in which to return the coordinates values at the mesh f positions. These are stored such that the value of coordinate f number COORD for point number POINT is found in element f POINTS(POINT,COORD). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - An error is reported if the Region is unbounded. * - If the coordinate system represented by the Region has been * changed since it was first created, the returned axis values refer * to the new (changed) coordinate system, rather than the original * coordinate system. Note however that if the transformation from * original to new coordinate system is non-linear, the shape within * the new coordinate system may be distorted, and so may not match * that implied by the name of the Region subclass (Circle, Box, etc). *-- */ /* Local Variables: */ AstPointSet *pset; /* PointSet holding mesh/grid axis values */ double **ptr; /* Pointer to mesh/grid axes values */ double *p; /* Pointer to next input axis value */ double *q; /* Pointer to next output axis value */ int j; /* Axis index */ int nc; /* No. of axes to copy */ /* Initialise */ *npoint = 0; /* Check the inherited status. */ if( !astOK ) return; /* Report an error if the Region is unbounded. */ if( !astGetBounded( this ) ) { if( astOK ) astError( AST__MBBNF, "astGetRegionMesh(%s): The supplied %s" " is unbounded so no mesh can be created to cover " "it.", status, astGetClass( this ), astGetClass( this ) ); } else { /* Get the mesh or grid as required. If only the size of the mesh or grid is required, get it in the base Frame as there is no need to spend the extra time transforming it into the current Frame. */ if( maxpoint == 0 ){ if( surface ) { pset = astRegBaseMesh( this ); } else { pset = astRegBaseGrid( this ); } } else { if( surface ) { pset = astRegMesh( this ); } else { pset = astRegGrid( this ); } } /* Return the number of points in the mesh or grid. */ *npoint = astGetNpoint( pset ); /* Do nothing more unless a non-zero array size was supplied. */ if( *npoint > 0 && maxpoint != 0 && astOK ) { /* Check the supplied array is large enough. */ if( *npoint > maxpoint ) { astError( AST__DIMIN, "astGetRegionMesh(%s): The supplied " "array can hold up to %d points but the %s supplied " "has %d points on its mesh (programming error).", status, astGetClass( this ), maxpoint, astGetClass( this ), *npoint ); } /* Get the dimensionality of the PointSet, and get a pointer to the axis values. */ nc = astGetNcoord( pset ); ptr = astGetPoints( pset ); /* Check pointers can be used safely. */ if ( astOK ) { /* Check the supplied array has room for all the axes. */ if( nc > maxcoord ) { astError( AST__DIMIN, "astGetRegionMesh(%s): The supplied " "array can hold up to %d axes but the %s supplied " "has %d axes (programming error).", status, astGetClass( this ), maxcoord, astGetClass( this ), nc ); /* If all is OK, copy the current Frame axis values into the supplied array. */ } else { /* Loop round the axes to be copied. */ for( j = 0; j < nc; j++ ) { /* Get points to the first element of the input and output arrays. */ p = ptr[ j ]; q = points + j*maxpoint; /* Copying the axis values. */ (void) memcpy( q, p, sizeof( double )*( *npoint ) ); } } } } /* Free resources. */ pset = astAnnul( pset ); } } static void GetRegionPoints( AstRegion *this, int maxpoint, int maxcoord, int *npoint, double *points, int *status ){ /* *++ * Name: c astGetRegionPoints f AST_GETREGIONPOINTS * Purpose: * Returns the positions that define the given Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astGetRegionPoints( AstRegion *this, int maxpoint, int maxcoord, c int *npoint, double *points ) f CALL AST_GETREGIONPOINTS( THIS, MAXPOINT, MAXCOORD, NPOINT, POINTS, f STATUS ) * Class Membership: * Region method. * Description: c This function f This routine * returns the axis values at the points that define the supplied * Region. The particular meaning of these points will depend on the * type of class supplied, as listed below under "Applicability:". * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c maxpoint f MAXPOINT = INTEGER (Given) * If zero, the number of points needed to define the Region is * returned in c "*npoint", f NPOINT, * but no axis values are returned and all other parameters are ignored. * If not zero, the supplied value should be the length of the c second dimension of the "points" f first dimension of the POINTS * array. An error is reported if the number of points needed to define * the Region exceeds this number. c maxcoord f MAXCOORD = INTEGER (Given) * The length of the c first dimension of the "points" array. f second dimension of the POINTS array. * An error is reported if the number of axes in the supplied Region * exceeds this number. c npoint f NPOINT = INTEGER (Returned) c A pointer to an integer in which to return the f The * number of points defining the Region. c points f POINTS( MAXPOINT, MAXCOORD ) = DOUBLE PRECISION (Returned) c The address of the first element in a 2-dimensional array of c shape "[maxcoord][maxpoint]", in which to return c the coordinate values at the positions that define the Region. c These are stored such that the value of coordinate number c "coord" for point number "point" is found in element c "points[coord][point]". f An array in which to return the coordinates values at the f positions that define the Region. These are stored such that the f value of coordinate number COORD for point number POINT f is found in element POINTS(POINT,COORD). f STATUS = INTEGER (Given and Returned) f The global status. * Applicability: * Region * All Regions have this attribute. * Box * The first returned position is the Box centre, and the second is * a Box corner. * Circle * The first returned position is the Circle centre, and the second is * a point on the circumference. * CmpRegion * Returns a value of zero for c "*npoint" f NPOINT * and leaves the supplied array contents unchanged. To find the * points defining a CmpRegion, use this method on the component * Regions, which can be accessed by invoking c astDecompose f AST_DECOMPOSE * on the CmpRegion. * Ellipse * The first returned position is the Ellipse centre. The second is * the end of one of the axes of the ellipse. The third is some * other point on the circumference of the ellipse, distinct from * the second point. * Interval * The first point corresponds to the lower bounds position, and * the second point corresponds to the upper bounds position. These * are reversed to indicate an extcluded interval rather than an * included interval. See the Interval constructor for more * information. * NullRegion * Returns a value of zero for c "*npoint" f NPOINT * and leaves the supplied array contents unchanged. * PointList * The positions returned are those that were supplied when the * PointList was constructed. * Polygon * The positions returned are the vertex positions that were supplied * when the Polygon was constructed. * Prism * Returns a value of zero for c "*npoint" f NPOINT * and leaves the supplied array contents unchanged. To find the * points defining a Prism, use this method on the component * Regions, which can be accessed by invoking c astDecompose f AST_DECOMPOSE * on the CmpRegion. * Notes: * - If the coordinate system represented by the Region has been * changed since it was first created, the returned axis values refer * to the new (changed) coordinate system, rather than the original * coordinate system. Note however that if the transformation from * original to new coordinate system is non-linear, the shape within * the new coordinate system may be distorted, and so may not match * that implied by the name of the Region subclass (Circle, Box, etc). *-- */ /* Local Variables: */ AstPointSet *pset; /* PointSet holding PointList axis values */ double **ptr; /* Pointer to axes values in the PointList */ double *p; /* Pointer to next input axis value */ double *q; /* Pointer to next output axis value */ int j; /* Axis index */ int nc; /* No. of axes to copy */ /* Initialise */ *npoint = 0; /* Check the inherited status. */ if( !astOK ) return; /* Return the number of points used to define the Region, if any. */ *npoint = this->points ? astGetNpoint( this->points ) : 0; /* Do nothing more unless a non-zero array size was supplied. */ if( *npoint > 0 && maxpoint != 0 ) { /* Transform the base Frame axis values into the current Frame. */ pset = astTransform( this->frameset, this->points, 1, NULL ); /* Get the dimensionality of this PointList, and get a pointer to the axis values. */ nc = astGetNcoord( pset ); ptr = astGetPoints( pset ); /* Check pointers can be used safely. */ if ( astOK ) { /* Check the supplied array has room for all the axis values. */ if( nc > maxcoord ) { astError( AST__DIMIN, "astGetRegionPoints(%s): The supplied " "array can hold up to %d axes but the %s supplied " "has %d axes (programming error).", status, astGetClass( this ), maxcoord, astGetClass( this ), nc ); } else if( *npoint > maxpoint ) { astError( AST__DIMIN, "astGetRegionPoints(%s): The supplied " "array can hold up to %d points but the %s supplied " "requires %d points to describe it (programming " "error).", status, astGetClass( this ), maxpoint, astGetClass( this ), *npoint ); /* If all is OK, copy the transformed axis values into the supplied array. */ } else { /* Loop round the axes to be copied. */ for( j = 0; j < nc; j++ ) { /* Get points to the first element of the input and output arrays. */ p = ptr[ j ]; q = points + j*maxpoint; /* Copying the axis values. */ (void) memcpy( q, p, sizeof( double )*( *npoint ) ); } } } /* Free resources. */ pset = astAnnul( pset ); } } static void RegOverlay( AstRegion *this, AstRegion *that, int unc, int *status ){ /* *+ * Name: * astRegOverlay * Purpose: * Copy properties from one Region to another. * Type: * Protected function. * Synopsis: * #include "region.h" * void astRegOverlay( AstRegion *this, AstRegion *that, int unc ) * Class Membership: * Region virtual function. * Description: * This function copies selected properties from "that" to "this". * It is intended to be called by sub-classes which need to create a * similar copy of an existing Region. For instance, subclass * implementations of the Simplify method will usually use this * function to ensure that the simplified Region loooks like the original * Region. * Parameters: * this * Pointer to the new Region. * that * Pointer to the old Region. * unc * If non-zero, any uncertainty in "this" is cleared if "that" has * no uncertainty. If zero, any uncertainty in "this" is left * unchanged. *- */ /* Check the inherited status. */ if( !astOK ) return; /* Copy the required attribute values. */ this->negated = that->negated; this->closed = that->closed; this->regionfs = that->regionfs; this->adaptive = that->adaptive; /* Clear things that depend on the number of axes. */ if( astGetNaxes( this ) == astGetNaxes( that ) ) { if( astTestMeshSize( that ) ) astSetMeshSize( this, astGetMeshSize( that ) ); if( astTestFillFactor( that ) ) astSetFillFactor( this, astGetFillFactor( that ) ); } else { astClearMeshSize( this ); astClearFillFactor( this ); } /* If required, clear uncertainty in "this" if "that" has no uncertainty. */ if( unc && !astTestUnc( that ) ) astClearUnc( this ); } static void RegSetAttrib( AstRegion *this, const char *asetting, char **base_setting, int *status ) { /* *+ * Name: * astRegSetAttrib * Purpose: * Set an attribute value for a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * void astRegSetAttrib( AstRegion *this, const char *asetting, * char **base_setting ) * Class Membership: * Region virtual function * Description: * This function assigns an attribute value to both the base and * current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * asetting * Pointer to a null terminated attribute setting string. The supplied * string will be interpreted using the public interpretation * implemented by astSetAttrib. This can be different to the * interpretation of the protected accessor functions. For instance, * the public interpretation of an unqualified floating point value for * the Epoch attribute is to interpet the value as a gregorian year, * but the protected interpretation is to interpret the value as an * MJD. * base_setting * Address of a location at which to return a pointer to the null * terminated attribute setting string which was applied to the * base Frame of the encapsulated FrameSet. This may differ from * the supplied setting if the supplied setting contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. *- */ /* Local Variables: */ AstFrame *frm; AstMapping *junkmap; AstMapping *map; AstRegion *unc; char *setting; char *bsetting; char buf1[ 100 ]; int *outs; int axis; int baxis; int i; int len; int nc; int rep; int value; /* Check the global error status. */ if ( !astOK ) return; /* Produce a lower case version of the setting string */ nc = strlen( asetting ); setting = astMalloc( nc + 1 ); for( i = 0; i < nc; i++ ) setting[ i ] = tolower( asetting[ i ] ); setting[ nc ] = 0; /* Apply the setting to the current Frame in the encapsulated FrameSet. Use the protected astSetAttrib method which does not cause the Frame to be remapped within the FrameSet. */ frm = astGetFrame( this->frameset, AST__CURRENT ); astSetAttrib( frm, setting ); frm = astAnnul( frm ); /* Indicate that we should use the supplied setting with the base Frame. */ bsetting = NULL; /* If the attribute name contains an axis number, we need to create a new attribute setting which refers to the corresponding base Frame axis (since the base<->current Mapping may permute the axes). First parse the supplied attribute setting to locate any axis index. */ len = strlen( setting ); if( nc = 0, ( 2 == astSscanf( setting, "%[^(](%d)= %n%*s %n", buf1, &axis, &value, &nc ) ) && ( nc >= len ) ) { /* If found, convert the axis index from one-based to zero-based. */ axis--; /* See if the specified current Frame axis is connected to one and only one base Frame axis. If so, get the index of the base Frame axis. */ map = astGetMapping( this->frameset, AST__CURRENT, AST__BASE ); outs = astMapSplit( map, 1, &axis, &junkmap ); if( junkmap && astGetNout( junkmap ) == 1 ) { baxis = outs[ 0 ]; /* If the base Frame axis index is different to the current Frame axis index, create a new setting string using the base Frame axis index. */ if( baxis != axis ) { bsetting = astMalloc( strlen( setting ) + 10 ); if( bsetting ) { sprintf( bsetting, "%s(%d)=%s", buf1, baxis + 1, setting + value ); } } /* If there is no one base Frame axis which corresponds to the supplied current Frame axis, report an error. */ } else if( astOK ) { astError( AST__INTER, "astRegSetAttrib(%s): Unable to apply " "attribute setting \"%s\" to the base Frame in the %s", status, astGetClass( this ), setting, astGetClass( this ) ); astError( AST__INTER, "There is no base Frame axis corresponding " "to current Frame axis %d\n", status, axis + 1 ); } /* Free resources */ outs = astFree( outs ); if( junkmap ) junkmap = astAnnul( junkmap ); map = astAnnul( map ); } /* Apply the appropriate attribute setting to the base Frame. This time ensure that any error caused by the attribute setting is annulled. Also apply it to any uncertainty Region (the current Frame of the uncertainty Region is assumed to be equivalent to the base Frame of the parent Region). */ frm = astGetFrame( this->frameset, AST__BASE ); if( frm ) { rep = astReporting( 0 ); astSetAttrib( frm, bsetting ? bsetting : setting ); if( astTestUnc( this ) ) { unc = astGetUncFrm( this, AST__BASE ); astRegSetAttrib( unc, bsetting ? bsetting : setting, NULL ); unc = astAnnul( unc ); } if( astStatus == AST__BADAT ) astClearStatus; astReporting( rep ); } frm = astAnnul( frm ); /* If required return the modified base Frame setting. Otherwise, free it. */ if( base_setting ) { if( bsetting ) { *base_setting = bsetting; } else { *base_setting = astStore( NULL, setting, strlen( setting ) + 1 ); } } else { bsetting = astFree( bsetting ); } /* Since the base Frame has been changed, any cached information calculated on the basis of the base Frame properties may no longer be up to date. */ astResetCache( this ); /* Free resources. */ setting = astFree( setting ); } static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) { /* * Name: * RemoveRegions * Purpose: * Remove any Regions from a Mapping. * Type: * Private function. * Synopsis: * #include "region.h" * AstMapping *RemoveRegions( AstMapping *this, int *status ) * Class Membership: * Region method (over-rides the astRemoveRegions method inherited * from the Frame class). * Description: * This function searches the supplied Mapping (which may be a * compound Mapping such as a CmpMap) for any component Mappings * that are instances of the AST Region class. It then creates a new * Mapping from which all Regions have been removed. If a Region * cannot simply be removed (for instance, if it is a component of a * parallel CmpMap), then it is replaced with an equivalent UnitMap * in the returned Mapping. * * The implementation provided by the Region class just returns the * equivalent Frame. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the modified mapping. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* The Region class just returns a pointer to a deep copy of the Region's equivalent Frame. */ return astGetRegionFrame( (AstRegion *)this_mapping ); } static void ReportPoints( AstMapping *this_mapping, int forward, AstPointSet *in_points, AstPointSet *out_points, int *status ) { /* * Name: * ReportPoints * Purpose: * Report the effect of transforming a set of points using a Region. * Type: * Private function. * Synopsis: * #include "region.h" * void ReportPoints( AstMapping *this, int forward, * AstPointSet *in_points, AstPointSet *out_points, int *status ) * Class Membership: * Region member function (over-rides the protected astReportPoints * method inherited from the Frame class). * Description: * This function reports the coordinates of a set of points before * and after being transformed by a Region, by writing them to * standard output. * Parameters: * this * Pointer to the Region. * forward * A non-zero value indicates that the Region's forward * coordinate transformation has been applied, while a zero * value indicates the inverse transformation. * in_points * Pointer to a PointSet which is associated with the * coordinates of a set of points before the Region was * applied. * out_points * Pointer to a PointSet which is associated with the * coordinates of the same set of points after the Region has * been applied. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_mapping; /* Obtain a pointer to the Region's current Frame and invoke its astReportPoints method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astReportPoints( (AstMapping *) fr, forward, in_points, out_points ); fr = astAnnul( fr ); } static void ResetCache( AstRegion *this, int *status ){ /* *+ * Name: * astResetCache * Purpose: * Clear cached information within the supplied Region. * Type: * Protected function. * Synopsis: * #include "region.h" * void astResetCache( AstRegion *this ) * Class Membership: * Region virtual function * Description: * This function clears cached information from the supplied Region * structure. * Parameters: * this * Pointer to the Region. *- */ if( this ) { if( this->basemesh ) this->basemesh = astAnnul( this->basemesh ); if( this->basegrid ) this->basegrid = astAnnul( this->basegrid ); if( this->negation ) this->negation = astAnnul( this->negation ); } } static void Resolve( AstFrame *this_frame, const double point1[], const double point2[], const double point3[], double point4[], double *d1, double *d2, int *status ){ /* * Name: * Resolve * Purpose: * Resolve a vector into two orthogonal components * Type: * Private function. * Synopsis: * #include "region.h" * void Resolve( AstFrame *this, const double point1[], * const double point2[], const double point3[], * double point4[], double *d1, double *d2, int *status ); * Class Membership: * Region member function (over-rides the protected astResolve * method inherited from the Frame class). * Description: * This function resolves a vector into two perpendicular components. * The vector from point 1 to point 2 is used as the basis vector. * The vector from point 1 to point 3 is resolved into components * parallel and perpendicular to this basis vector. The lengths of the * two components are returned, together with the position of closest * aproach of the basis vector to point 3. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vector to be resolved. * point2 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. * point3 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the vector to be * resolved. * point4 * An array of double, with one element for each Frame axis * in which the coordinates of the point of closest approach of the * basis vector to point 3 will be returned. * d1 * The address of a location at which to return the distance from * point 1 to point 4 (that is, the length of the component parallel * to the basis vector). Positive values are in the same sense as * movement from point 1 to point 2. * d2 * The address of a location at which to return the distance from * point 4 to point 3 (that is, the length of the component * perpendicular to the basis vector). The value is always positive. * status * Pointer to the inherited status variable. * Notes: * - Each vector used in this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the required * output values are undefined. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke this Frame's astResolve method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astResolve( fr, point1, point2, point3, point4, d1, d2 ); fr = astAnnul( fr ); } static AstPointSet *ResolvePoints( AstFrame *this_frame, const double point1[], const double point2[], AstPointSet *in, AstPointSet *out, int *status ) { /* * Name: * ResolvePoints * Purpose: * Resolve a set of vectors into orthogonal components * Type: * Private function. * Synopsis: * #include "region.h" * AstPointSet *ResolvePoints( AstFrame *this, const double point1[], * const double point2[], AstPointSet *in, * AstPointSet *out ) * Class Membership: * Region member function (over-rides the astResolvePoints method * inherited from the Frame class). * Description: * This function takes a Frame and a set of vectors encapsulated * in a PointSet, and resolves each one into two orthogonal components, * returning these two components in another PointSet. * * This is exactly the same as the public astResolve method, except * that this method allows many vectors to be processed in a single call, * thus reducing the computational cost of overheads of many * individual calls to astResolve. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vectors to be resolved. * point2 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. * in * Pointer to the PointSet holding the ends of the vectors to be * resolved. * out * Pointer to a PointSet which will hold the length of the two * resolved components. A NULL value may also be given, in which * case a new PointSet will be created by this function. * Returned Value: * Pointer to the output (possibly new) PointSet. The first axis will * hold the lengths of the vector components parallel to the basis vector. * These values will be signed (positive values are in the same sense as * movement from point 1 to point 2. The second axis will hold the lengths * of the vector components perpendicular to the basis vector. These * values will always be positive. * Notes: * - The number of coordinate values per point in the input * PointSet must match the number of axes in the supplied Frame. * - If an output PointSet is supplied, it must have space for * sufficient number of points and 2 coordinate values per point. * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke this Frame's astResolve method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astResolvePoints( fr, point1, point2, in, out ); fr = astAnnul( fr ); /* Return a pointer to the output PointSet. */ return result; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * Region member function (extends the astSetAttrib method * inherited from the Frame class). * Description: * This function assigns an attribute value for a Region, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the Region. * setting * Pointer to a null terminated string specifying the new * attribute value. * status * Pointer to the inherited status variable. * Notes: * - This protected method is intended to be invoked by the Object * astSet method and makes additional attributes accessible to it. */ /* Local Variables: */ AstRegion *this; /* Pointer to the Region structure */ double dval; /* Floating point attribute value */ int ival; /* Integer attribute value */ int id; /* Offset of ID string */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* Obtain the length of the setting string. */ len = strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* We first handle attributes that apply to the Region as a whole (rather than to the encapsulated Frame). */ /* Negated */ /* ------- */ if ( nc = 0, ( 1 == astSscanf( setting, "negated= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetNegated( this, ival ); /* Closed */ /*------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "closed= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetClosed( this, ival ); /* FillFactor */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "fillfactor= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetFillFactor( this, dval ); /* MeshSize */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "meshsize= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetMeshSize( this, ival ); /* Adaptive */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "adaptive= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetAdaptive( this, ival ); /* Now do attributes inherited from parent classes. We do these here to avoid the settings being passed on to the encapsulated FrameSet below. */ /* ID. */ /* --- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "id=%n%*[^\n]%n", &id, &nc ) ) && ( nc >= len ) ) { astSetID( this, setting + id ); /* Ident. */ /* ------ */ } else if ( nc = 0, ( 0 == astSscanf( setting, "ident=%n%*[^\n]%n", &id, &nc ) ) && ( nc >= len ) ) { astSetIdent( this, setting + id ); /* Invert. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "invert= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetInvert( this, ival ); /* Report. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "report= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetReport( this, ival ); /* Define macros to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) #define AXISMATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "(%*d)=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* If the attribute was not recognised, use this macro to report an error if a read-only attribute has been specified. */ } else if ( MATCH( "class" ) || MATCH( "nin" ) || MATCH( "nobject" ) || MATCH( "bounded" ) || MATCH( "nout" ) || MATCH( "refcount" ) || MATCH( "tranforward" ) || MATCH( "traninverse" ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Pass unrecognised attributes on to the Region's encapsulated FrameSet for further interpretation. Do not pass on FrameSet attributes since we pretend to the outside world that the encapsulated FrameSet is actually a Frame. */ } else if ( !MATCH( "base" ) && !MATCH( "current" ) && !MATCH( "nframe" ) ) { /* If the Region is to adapt to coordinate system chanmges, use the public astSet method so that the current Frame in the encapsulated FrameSet will be re-mapped if the attribute changes require it. */ if( astGetAdaptive( this ) ) { astSet( this->frameset, setting, status ); /* If the Region is not to adapt to coordinate system chanmges, use the astRegSetAttrib method which assigns the attribute setting to both current and base Frames in the FrameSet without causing any remapping to be performed. */ } else { astRegSetAttrib( this, setting, NULL ); } } /* Undefine macros local to this function. */ #undef MATCH } static void SetAxis( AstFrame *this_frame, int axis, AstAxis *newaxis, int *status ) { /* * Name: * SetAxis * Purpose: * Set a new Axis for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * void SetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status ) * Class Membership: * Region member function (over-rides the astSetAxis method * inherited from the Frame class). * Description: * This function allows a new Axis object to be associated with one * of the axes of the current Frame in a Region, replacing the * previous one. Each Axis object contains a description of the * quantity represented along one of the Frame's axes, so this * function allows this description to be exchanged for another * one. * Parameters: * this * Pointer to the Region. * axis * The index (zero-based) of the axis whose associated Axis * object is to be replaced. * newaxis * Pointer to the new Axis object. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index supplied. */ (void) astValidateAxis( this, axis, 1, "astSetAxis" ); /* Obtain a pointer to the Region's current Frame and invoke this Frame's astSetAxis method to assign the new Axis object. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astSetAxis( fr, axis, newaxis ); fr = astAnnul( fr ); } static void SetRegFS( AstRegion *this, AstFrame *frm, int *status ) { /* *+ * Name: * astSetRegFS * Purpose: * Stores a new FrameSet in a Region * Type: * Protected function. * Synopsis: * #include "region.h" * void astSetRegFS( AstRegion *this, AstFrame *frm ) * Class Membership: * Region virtual function. * Description: * This function creates a new FrameSet and stores it in the supplied * Region. The new FrameSet contains two copies of the supplied * Frame, connected by a UnitMap. * Parameters: * this * Pointer to the Region. * frm * The Frame to use. *- */ /* Local Variables: */ AstFrame *f1; /* Copy of supplied Frame */ AstFrame *f2; /* Copy of supplied Frame */ AstFrameSet *fs; /* New FrameSet */ AstRegion *unc; /* Uncertainty Region */ AstUnitMap *um; /* UnitMap connecting base anc current Frames */ /* Check the global error status. */ if ( !astOK ) return; /* Take a copy of the supplied Frame. */ f1 = astCopy( frm ); /* Create the new FrameSet. First take another copy of the supplied Frame so that modifications using the supplied pointer will not affect the new FrameSet. We create two copies (rather than 1) because the base and current Frames must be independant objects - otherwise attribute changes done to one will also appear in the other. Then construct the FrameSet containing the two Frame copies connected by a UnitMap. */ f2 = astCopy( f1 ); fs = astFrameSet( f1, "", status ); um = astUnitMap( astGetNaxes( f1 ), "", status ); astAddFrame( fs, AST__BASE, um, f2 ); um = astAnnul( um ); f2 = astAnnul( f2 ); /* Annul any existing FrameSet */ if( this->frameset ) (void) astAnnul( this->frameset ); /* Use the new FrameSet */ this->frameset = fs; /* If any uncertainty Region has a zero value for its RegionFS attribute, it will currently contain a dummy FrameSet rather than the correct FrameSet. The correct FrameSet has copies of the base Frame of the new Region as both its current and base Frames, and these are connected by a UnitMap (this is equivalent to a FrameSet containing a single Frame). */ if( astTestUnc( this ) ) { unc = astGetUncFrm( this, AST__BASE ); if( unc && !astGetRegionFS( unc ) ) astSetRegFS( unc, f1 ); unc = astAnnul( unc ); } /* Free remaining resourvces */ f1 = astAnnul( f1 ); } static void SetUnc( AstRegion *this, AstRegion *unc, int *status ){ /* *++ * Name: c astSetUnc f AST_SETUNC * Purpose: * Store uncertainty information in a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astSetUnc( AstRegion *this, AstRegion *unc ) f CALL AST_SETUNC( THIS, UNC, STATUS ) * Class Membership: * Region method. * Description: * Each Region (of any class) can have an "uncertainty" which specifies * the uncertainties associated with the boundary of the Region. This * information is supplied in the form of a second Region. The uncertainty * in any point on the boundary of a Region is found by shifting the * associated "uncertainty" Region so that it is centred at the boundary * point being considered. The area covered by the shifted uncertainty * Region then represents the uncertainty in the boundary position. * The uncertainty is assumed to be the same for all points. * * The uncertainty is usually specified when the Region is created, but * this c function f routine * allows it to be changed at any time. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region which is to be assigned a new uncertainty. c unc f UNC = INTEGER (Given) * Pointer to the new uncertainty Region. This must be of a class for * which all instances are centro-symetric (e.g. Box, Circle, Ellipse, * etc.) or be a Prism containing centro-symetric component Regions. * A deep copy of the supplied Region will be taken, so subsequent * changes to the uncertainty Region using the supplied pointer will * have no effect on the Region c "this". f THIS. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstFrame *frm; /* Current Frame from FrameSet */ AstFrameSet *fs2; /* FrameSet from "unc" current Frame to "this" base Frame */ AstFrameSet *fs; /* FrameSet in "this" supplied Region */ AstMapping *map2; /* Base->current Mapping from FrameSet */ AstMapping *map; /* Base->current Mapping from FrameSet */ AstMapping *smap; /* Simplified base->current Mapping */ double *cen0; /* Pointer to array holding original centre */ double **ptr_reg; /* Pointer to axis values for Region's Pointset */ int changed; /* Has the uncertainty been changed? */ /* Check the inherited status. */ if( !astOK ) return; /* Annul any existing uncertainty Region. */ if( this->unc ) { this->unc = astIsAObject( this->unc ) ? astAnnul( this->unc ) : NULL; changed = 1; } else { changed = 0; } /* Check an uncertainty Region was supplied, and is of a usable class (i.e. a class which can be re-centred). */ cen0 = unc ? astRegCentre( unc, NULL, NULL, 0, 0 ) : NULL; if( cen0 ) { cen0 = astFree( cen0 ); /* Map it into the same Frame as that represented by the base Frame in the supplied Region. */ fs = this->frameset; astInvert( fs ); fs2 = Conv( unc->frameset, fs, status ); astInvert( fs ); if( fs2 ) { map = astGetMapping( fs2, AST__BASE, AST__CURRENT ); frm = astGetFrame( fs2, AST__CURRENT ); this->unc = astMapRegion( unc, map, frm ); if( this->unc ) { /* Ensure the Region is bounded. We know that negating an unbounded Region will make it bounded because we know that the Region consists of Circles, Boxes and/or Ellipses, all of which have this property. */ if( !astGetBounded( this->unc ) ) astNegate( this->unc ); /* If the base Frame in the uncertainty Region is the same as the base Frame in the Region being dumped, then we do no need to include the FrameSet in the dump of the uncertainty Region. Since the current Frame in the uncertainty Region always corresponds to the base Frame of its parent Region, we only need to check if the base->current Mapping in the uncertainty Region's FrameSet is a UnitMap or not (after simplification). If it is, set the RegionFS attribute of the uncertainty Region to zero (i.e. false). This will cause the FrameSet to be omitted from the Dump. */ map2 = astGetMapping( this->unc->frameset, AST__BASE, AST__CURRENT ); smap = astSimplify( map2 ); if( astIsAUnitMap( smap ) ) astSetRegionFS( this->unc, 0 ); /* Re-centre the uncertainty Region at the first position in the PointSet associated with the Region structure (if any). */ if( this->points ) { ptr_reg = astGetPoints( this->points ); astRegCentre( this->unc, NULL, ptr_reg, 0, AST__CURRENT ); } /* Set a flag indicating that the uncertainty in the Region has changed. */ changed = 1; /* Free resources */ map2 = astAnnul( map2 ); smap = astAnnul( smap ); } frm = astAnnul( frm ); fs2 = astAnnul( fs2 ); map = astAnnul( map ); /* Report error if conversion between Frames is not possible. */ } else if( astOK ) { astError( AST__BADIN, "astSetUnc(%s): Bad %d dimensional " "uncertainty Frame (%s %s) supplied.", status, astGetClass(this), astGetNaxes(unc), astGetDomain(unc), astGetTitle(unc) ); astError( AST__NCPIN, "Cannot convert it to the Frame of the " "new %s.", status, astGetClass( this ) ); } /* Report an error if it is not of a usable class. */ } else if( unc && astOK ){ astError( AST__BADIN, "astSetUnc(%s): Bad uncertainty shape " "(%s) supplied.", status, astGetClass( this ), astGetClass(unc) ); astError( AST__NCPIN, "The uncertainty Region must be an instance of " "a centro-symetric subclass of Region (e.g. Box, Circle, " "Ellipse, etc)." , status); } /* If the uncertainty in the Region has changed, indicate that any cached information in the Region is now out of date. */ if( changed ) astResetCache( this ); } static void ShowMesh( AstRegion *this, int format, const char *ttl, int *status ){ /* *++ * Name: c astShowMesh f AST_SHOWMESH * Purpose: * Display a mesh of points covering the surface of a Region. * Type: * Public virtual function. * Synopsis: c #include "region.h" c void astShowMesh( AstRegion *this, int format, const char *ttl ) f CALL AST_SHOWMESH( THIS, FORMAT, TTL, STATUS ) * Class Membership: * Region method. * Description: c This function f This routine * writes a table to standard output containing the axis values at a * mesh of points covering the surface of the supplied Region. Each row * of output contains a tab-separated list of axis values, one for * each axis in the Frame encapsulated by the Region. The number of * points in the mesh is determined by the MeshSize attribute. * * The table is preceded by a given title string, and followed by a * single line containing the word "ENDMESH". * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c format f FORMAT = LOGICAL (Given) * A boolean value indicating if the displayed axis values should * be formatted according to the Format attribute associated with * the Frame's axis. Otherwise, they are displayed as simple * floating point values. c ttl f TTL = CHARACTER * ( * ) (Given) * A title to display before displaying the first position. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstPointSet *ps; /* PointSet holding mesh */ char *buffer = NULL; /* Buffer for line output text */ char buf[ 40 ]; /* Buffer for floating poitn value */ double **ptr; /* Pointers to the mesh data */ int i; /* Axis index */ int j; /* Position index */ int nax; /* Number of axes */ int nc; /* Number of characters in buffer */ int np; /* Number of axis values per position */ /* Check the inherited status. */ if( !astOK ) return; /* Get a PointSet holding the mesh */ ps = astRegMesh( this ); if( ps ) { /* Get the number of axis values per position, and the number of positions. */ nax = astGetNcoord( ps ); np = astGetNpoint( ps ); /* Get a pointer to the mesh data, and check it can be used. */ ptr = astGetPoints( ps ); if( ptr ) { /* Display the title. */ if( ttl ) printf( "\n%s\n\n", ttl ); /* Loop round all positions. */ for( j = 0; j < np; j++ ) { /* Reset the current buffer length to zero. */ nc = 0; /* Loop round all axes */ for( i = 0; i < nax; i++ ){ /* If the axis value is bad, append " in the end of the output buffer. */ if( ptr[ i ][ j ] == AST__BAD ){ buffer = astAppendString( buffer, &nc, "" ); /* Otherwise, if required, append the formatted value to the end of the buffer. */ } else if( format ){ buffer = astAppendString( buffer, &nc, astFormat( this, i, ptr[ i ][ j ] ) ); /* Otherwise, append the floating point value to the end of the buffer. */ } else { sprintf( buf, "%g", ptr[ i ][ j ] ); buffer = astAppendString( buffer, &nc, buf ); } /* Add a separating tab to the end of the buffer. */ buffer = astAppendString( buffer, &nc, "\t" ); } /* Display the line buffer. */ printf( "%s\n", buffer ); } } /* Print out a marker for th eend of the list. */ printf( "ENDMESH\n\n" ); /* Release resources. */ ps = astAnnul( ps ); buffer = astFree( buffer ); } } static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { /* * Name: * Simplify * Purpose: * Simplify the Mapping represented by a Region. * Type: * Private function. * Synopsis: * #include "region.h" * AstMapping *Simplify( AstMapping *this, int *status ) * Class Membership: * Region method (over-rides the astSimplify method inherited * from the Frame class). * Description: * This function simplifies the encapsulated FrameSet and any * uncertainty Region in the supplied Region. This is different to * the Simplify method in the parent Frame class which always returns * a UnitMap. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the simplified Region. A cloned pointer to the * supplied Region will be returned if no simplication could be * performed. * Notes: * - This implementation just simplifies the encapsulated FrameSet * and uncertainty Region. Sub-classes should usually provide their own * implementation which invokes this implemetation, and then continues to * check for further simplifications (such as fitting a new region to the * current Frame). * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *bfrm; /* Pointer to "this" baseFrame */ AstFrameSet *fs; /* Pointer to encapsulated FrameSet */ AstMapping *map; /* Base->current Mapping for "this" */ AstMapping *result; /* Result pointer to return */ AstPointSet *pset1; /* Base Frame centre position */ AstPointSet *pset2; /* Current Frame centre position */ AstRegion *new; /* Pointer to simplified Region */ AstRegion *sunc; /* Simplified uncertainty Region */ AstRegion *this; /* Pointer to original Region structure */ AstRegion *unc; /* Original uncertainty Region */ double **ptr1; /* Pointer to axis values in "pset1" */ double *cen; /* Original centre of uncertainty Region */ double *lbnd; /* Lower bounds of "this" bounding box */ double *orig_cen; /* Original centre for uncertainty Region */ double *s1_lbnd; /* Lower bounds of "unc" when centred at lbnd */ double *s1_ubnd; /* Upper bounds of "unc" when centred at lbnd */ double *s2_lbnd; /* Lower bounds of "unc" when centred at ubnd */ double *s2_ubnd; /* Upper bounds of "unc" when centred at ubnd */ double *ubnd; /* Upper bounds of "this" bounding box */ double delta; /* Half width of test box */ double w1; /* Width of "s1" bounding box */ double w2; /* Width of "s2" bounding box */ int ic; /* Axis index */ int naxb; /* No. of base Frame axes in "this" */ int nin; /* Number of base Frame axes in "this" */ int nout; /* Number of current Frame axes in "this" */ int ok; /* Can we use the simplified uncertainty? */ int simpler; /* Has some simplication taken place? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_mapping; /* Take a deep copy of the supplied Region. This is so that the returned pointer will have a diferent value to the supplied pointer if any simplication takes place. */ new = astCopy( this ); /* Simplify the encapsulated FrameSet, and note if any simplification took place. */ fs = astSimplify( new->frameset ); simpler = ( fs != new->frameset ); /* If so, annull the existing FrameSet and use the simpler FrameSet. */ if( simpler ) { (void) astAnnul( new->frameset ); new->frameset = astClone( fs ); } fs = astAnnul( fs ); /* If the Region has default uncertainty, we simplify the uncertainty Region simply by deleting it. It will be regenerated when needed, using the simplified Region. */ if( new->defunc ) new->defunc = astAnnul( new->defunc ); /* If the Region's uncertainty was supplied explicitly, try simplifying the unncertainty Region. */ if( astTestUnc( new ) ){ /* Obtain the Region's uncertainty. */ unc = astGetUncFrm( new, AST__BASE ); /* Get the base->current Mapping from "this". */ map = astGetMapping( this->frameset, AST__BASE, AST__CURRENT ); /* If it has different numbers of inputs and outputs (e.g. a PermMap used to take a slice through a Region), we need to ensure that the uncertainty Region is centred on the slice. */ nin = astGetNin( map ); nout = astGetNout( map ); if( nin != nout ) { /* Get the current centre of the uncertainty Region in its current Frame (the same as the base Frame of "this"). */ cen = astRegCentre( unc, NULL, NULL, 0, AST__CURRENT ); /* Store it in a PointSet so it can be transformed. */ pset1 = astPointSet( 1, nin, "", status ); ptr1 = astGetPoints( pset1 ); if( astOK ) for( ic = 0; ic < nin; ic++ ) ptr1[ ic ][ 0 ] = cen[ ic ]; /* Transform into the curent Frame of "this", and then back into the base Frame. */ pset2 = astTransform( map, pset1, 1, NULL ); (void) astTransform( map, pset2, 0, pset1 ); /* Re-centre the uncertainty Region at this position. */ astRegCentre( unc, NULL, ptr1, 0, AST__CURRENT ); /* Free resources. */ cen = astFree( cen ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); } /* Free resources. */ map = astAnnul( map ); /* Try simplifying the uncertainty. Only proceed if the uncertainty can be simplified. */ sunc = astSimplify( unc ); if( sunc != unc ) { /* If the uncertainty can be simplified it means that the base->current Mapping in the uncertainty Region is sufficiently linear to allow the uncertainty shape to retain its form when transformed from the base to the current Frane. But this has only been tested at the current centre position in the uncertainty Region. The uncertainty Region should describe the whole of "this" Region, and so we need to check that the simplified uncertainty does not change as we move it around within "this" Region. To do this, we re-centre the uncertainty region at opposite corners of a large test box, and then we find the bounding box of the re-centred uncertainty Region. If this uncertainty bounding box changes from corner to corner of the test box, then we do not simplify the uncertainty Region. If "this" is bounded, we use the bounding box of "this" as the test box. Otherwise we use a box 100 times the size of the uncertainty Region. */ /* Note the original base Frame centre of the simplified uncertainty Region. */ orig_cen = astRegCentre( sunc, NULL, NULL, 0, AST__BASE ); /* Allocate memory to hold the bounds of the test box. */ naxb = astGetNin( this->frameset ); lbnd = astMalloc( sizeof( double )*(size_t)naxb ); ubnd = astMalloc( sizeof( double )*(size_t)naxb ); /* If possible, get the base Frame bounding box of "this" and use it as the test box. */ if( astGetBounded( this ) ) { astRegBaseBox( this, lbnd, ubnd ); /* Otherwise, store the bounds of a box which is 100 times the size of the uncertainty region, centred on the current centre of the uncertainty region (we know all uncertainty regions are bounded). */ } else { astGetRegionBounds( sunc, lbnd, ubnd ); for( ic = 0; ic < naxb; ic++ ) { delta = 0.5*fabs( ubnd[ ic ] - lbnd[ ic ] ); lbnd[ ic ] = orig_cen[ ic ] - delta; ubnd[ ic ] = orig_cen[ ic ] + delta; } } /* Re-centre it at the lower bounds of the test box. This is in the base Frame of "this" which is the same as the current Frame of "sunc". */ astRegCentre( sunc, lbnd, NULL, 0, AST__CURRENT ); /* Get the bounding box of the re-centred uncertainty Region, within its current Frame, which is the same as the base Frame of "this". */ s1_lbnd = astMalloc( sizeof( double )*(size_t)naxb ); s1_ubnd = astMalloc( sizeof( double )*(size_t)naxb ); astGetRegionBounds( sunc, s1_lbnd, s1_ubnd ); /* Now re-centre the uncertainty Region at the upper bounds of the test box. */ astRegCentre( sunc, ubnd, NULL, 0, AST__CURRENT ); /* Get the bounding box of the re-centred uncertainty Region. */ s2_lbnd = astMalloc( sizeof( double )*(size_t)naxb ); s2_ubnd = astMalloc( sizeof( double )*(size_t)naxb ); astGetRegionBounds( sunc, s2_lbnd, s2_ubnd ); /* Get a pointer to the base Frame of "this". */ bfrm = astGetFrame( this->frameset, AST__BASE ); /* The "ok" flag is initialised to indicate that the simplified uncertainty Region should not be used. */ ok = 0; /* Check pointers can be referenced safely */ if( astOK ) { /* Now indicate that the simplified uncertainty Region should be used. */ ok = 1; /* Loop round all axes of the base Frame of "this". */ for( ic = 0; ic < naxb; ic++ ) { /* Get the width of the two bounding boxes on this axis. */ w1 = s1_ubnd[ ic ] - s1_lbnd[ ic ]; w2 = s2_ubnd[ ic ] - s2_lbnd[ ic ]; /* If these differ by more than 0.1% then we determine that the simplified uncertainty Region varies in size across the bounding box of "this", and so we do not use the simplified uncertainty Region. The figure of 0.1% is arbitrary. */ if( fabs( w1 - w2 ) > 0.005*( fabs( w1 ) + fabs( w2 ) ) ) { ok = 0; break; } } } /* Reinstate the original base Frame centre of the simplified uncertainty Region. */ astRegCentre( sunc, orig_cen, NULL, 0, AST__BASE ); /* Free resources. */ orig_cen = astFree( orig_cen ); lbnd = astFree( lbnd ); ubnd = astFree( ubnd ); s1_lbnd = astFree( s1_lbnd ); s1_ubnd = astFree( s1_ubnd ); s2_lbnd = astFree( s2_lbnd ); s2_ubnd = astFree( s2_ubnd ); bfrm = astAnnul( bfrm ); /* If we can use the simplified uncertainty Region, indicate that we have performed some simplification, and store the new uncertainty Region. */ if( ok ) { simpler = 1; astSetUnc( new, sunc ); } } /* Free resources */ unc = astAnnul( unc ); sunc = astAnnul( sunc ); } /* If any simplification could be performed, return the new Region. Otherwise, return a clone of the supplied pointer. */ if( simpler ){ result = (AstMapping *) new; } else { new = astAnnul( new ); result = astClone( this ); } /* If an error occurred, annul the returned pointer. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static int SubFrame( AstFrame *this_frame, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * SubFrame * Purpose: * Select axes from a Region and convert to the new coordinate system. * Type: * Private function. * Synopsis: * #include "region.h" * int SubFrame( AstFrame *target, AstFrame *template, int result_naxes, * const int *target_axes, const int *template_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * Region member function (over-rides the protected astSubFrame * method inherited from the Frame class). * Description: * This function selects a requested sub-set (or super-set) of the * axes from the current Frame of a "target" Region and creates a * new Frame with copies of the selected axes assembled in the * requested order. It then optionally overlays the attributes of a * "template" Frame on to the result. It returns both the resulting * Frame and a Mapping that describes how to convert between the * coordinate systems described by the current Frame of the target * Region and the result Frame. If necessary, this Mapping takes * account of any differences in the Frames' attributes due to the * influence of the template. * Parameters: * target * Pointer to the target Region, from whose current Frame the * axes are to be selected. * template * Pointer to the template Frame, from which new attributes for * the result Frame are to be obtained. Optionally, this may be * NULL, in which case no overlaying of template attributes will * be performed. * result_naxes * Number of axes to be selected from the target Region. This * number may be greater than or less than the number of axes in * the Region's current Frame (or equal). * target_axes * Pointer to an array of int with result_naxes elements, giving * a list of the (zero-based) axis indices of the axes to be * selected from the current Frame of the target Region. The * order in which these are given determines the order in which * the axes appear in the result Frame. If any of the values in * this array is set to -1, the corresponding result axis will * not be derived from the target Region, but will be assigned * default attributes instead. * template_axes * Pointer to an array of int with result_naxes elements. This * should contain a list of the template axes (given as * zero-based axis indices) with which the axes of the result * Frame are to be associated. This array determines which axes * are used when overlaying axis-dependent attributes of the * template on to the result. If any element of this array is * set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not * used and a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned * Mapping. The forward transformation of this Mapping will * describe how to convert coordinates from the coordinate * system described by the current Frame of the target Region * to that described by the result Frame. The inverse * transformation will convert in the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if coordinate conversion is * possible between the current Frame of the target Region and * the result Frame. Otherwise zero is returned and *map and * *result are returned as NULL (but this will not in itself result * in an error condition). In general, coordinate conversion should * always be possible if no template Frame is supplied but may not * always be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to Region's current Frame */ int match; /* Result to be returned */ /* Initialise. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Invoke the parent astSubFrame method on the Frame represented by the region. */ fr = astGetFrame( ((AstRegion *) this_frame)->frameset, AST__CURRENT ); match = astSubFrame( fr, template, result_naxes, target_axes, template_axes, map, result ); fr = astAnnul( fr ); /* Return the result. */ return match; } static AstSystemType SystemCode( AstFrame *this_frame, const char *system, int *status ) { /* * Name: * SystemCode * Purpose: * Convert a string into a coordinate system type code. * Type: * Private function. * Synopsis: * #include "region.h" * AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) * Class Membership: * Region member function (over-rides the protected astSystemCode * method inherited from the Frame class). * Description: * This function converts a string used for the external description of * a coordinate system into a Frame coordinate system type code (System * attribute value). It is the inverse of the astSystemString function. * Parameters: * this * Pointer to the Frame. * system * Pointer to a constant null-terminated string containing the * external description of the coordinate system. * status * Pointer to the inherited status variable. * Returned Value: * The System type code. * Notes: * - A value of AST__BADSYSTEM is returned if the coordinate system * description was not recognised. This does not produce an error. * - A value of AST__BADSYSTEM is also returned if this function * is invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ AstSystemType result; /* Result value to return */ AstFrame *fr; /* Pointer to FrameSet's current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke the astSystemCode method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astSystemCode( fr, system ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BADSYSTEM; /* Return the result. */ return result; } static const char *SystemString( AstFrame *this_frame, AstSystemType system, int *status ) { /* * Name: * SystemString * Purpose: * Convert a coordinate system type code into a string. * Type: * Private function. * Synopsis: * #include "region.h" * const char *SystemString( AstFrame *this, AstSystemType system, int *status ) * Class Membership: * Region member function (over-rides the protected astSystemString * method inherited from the Frame class). * Description: * This function converts a Frame coordinate system type code * (System attribute value) into a string suitable for use as an * external representation of the coordinate system type. * Parameters: * this * Pointer to the Frame. * system * The coordinate system type code. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the coordinate system * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to FrameSet's current Frame */ AstRegion *this; /* Pointer to the Region structure */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke the astSystemString method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astSystemString( fr, system ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = NULL; /* Return the result pointer. */ return result; } static int RegTrace( AstRegion *this, int n, double *dist, double **ptr, int *status ){ /* *+ * Name: * astRegTrace * Purpose: * Return requested positions on the boundary of a 2D Region. * Type: * Protected function. * Synopsis: * #include "region.h" * int astRegTrace( AstRegion *this, int n, double *dist, double **ptr ); * Class Membership: * Region virtual function * Description: * This function returns positions on the boundary of the supplied * Region, if possible. The required positions are indicated by a * supplied list of scalar parameter values in the range zero to one. * Zero corresponds to some arbitrary starting point on the boundary, * and one corresponds to the end (which for a closed region will be * the same place as the start). * Parameters: * this * Pointer to the Region. * n * The number of positions to return. If this is zero, the function * returns without action (but the returned function value still * indicates if the method is supported or not). * dist * Pointer to an array of "n" scalar parameter values in the range * 0 to 1.0. * ptr * A pointer to an array of pointers. The number of elements in * this array should equal tthe number of axes in the Frame spanned * by the Region. Each element of the array should be a pointer to * an array of "n" doubles, in which to return the "n" values for * the corresponding axis. The contents of the arrays are unchanged * if the supplied Region belongs to a class that does not * implement this method. * Returned Value: * Non-zero if the astRegTrace method is implemented by the class * of Region supplied, and zero if not. *- */ /* Concrete sub-classes of Region must over-ride this method. */ return 0; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a Region. * Type: * Private function. * Synopsis: * #include "region.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Region member function (over-rides the astTestAttrib protected * method inherited from the Frame class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a Region's attributes. * Parameters: * this * Pointer to the Region. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstRegion *this; /* Pointer to the Region structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* Check the attribute name and test the appropriate attribute. */ /* We first handle attributes that apply to the Region as a whole (rather than to the encapsulated FrameSet). */ /* Negated. */ /* -------- */ if ( !strcmp( attrib, "negated" ) ) { result = astTestNegated( this ); /* Closed. */ /* ------- */ } else if ( !strcmp( attrib, "closed" ) ) { result = astTestClosed( this ); /* FillFactor */ /* ---------- */ } else if ( !strcmp( attrib, "fillfactor" ) ) { result = astTestFillFactor( this ); /* MeshSize */ /* -------- */ } else if ( !strcmp( attrib, "meshsize" ) ) { result = astTestMeshSize( this ); /* Adaptive */ /* -------- */ } else if ( !strcmp( attrib, "adaptive" ) ) { result = astTestAdaptive( this ); /* Now do attributes inherited from parent classes. This is so that the attribute test will not be passed on to the encpasulated FrameSet below. */ /* ID. */ /* --- */ } else if ( !strcmp( attrib, "id" ) ) { result = astTestID( this ); /* Ident. */ /* ------ */ } else if ( !strcmp( attrib, "ident" ) ) { result = astTestIdent( this ); /* Invert. */ /* ------- */ } else if ( !strcmp( attrib, "invert" ) ) { result = astTestInvert( this ); /* Report. */ /* ------- */ } else if ( !strcmp( attrib, "report" ) ) { result = astTestReport( this ); /* If the name is not recognised, test if it matches any of the read-only attributes of this class. If it does, then return zero. */ } else if ( !strcmp( attrib, "class" ) || !strcmp( attrib, "nin" ) || !strcmp( attrib, "nobject" ) || !strcmp( attrib, "bounded" ) || !strcmp( attrib, "nout" ) || !strcmp( attrib, "refcount" ) || !strcmp( attrib, "tranforward" ) || !strcmp( attrib, "traninverse" ) ) { result = 0; /* Pass unrecognised attributes on to the Region's encapsulated FrameSet for further interpretation. Do not pass on FrameSet attributes since we pretend to the outside world that the encapsulated FrameSet is actually a Frame. */ } else if ( strcmp( attrib, "base" ) && strcmp( attrib, "current" ) && strcmp( attrib, "nframe" ) ) { result = astTestAttrib( this->frameset, attrib ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } double *astRegTranPoint_( AstRegion *this, double *in, int np, int forward, int *status ){ /* *+ * Name: * astRegTranPoint * Purpose: * Transform points between the base and current Frames in a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * double *astRegTranPoint( AstRegion *this, double *in, int np, int forward ) * Class Membership: * Region member function * Description: * This function transforms one or more points between the base and * current Frames of the FrameSet encapsulated by the supplied Region. * Parameters: * this * The Region pointer. * in * Pointer to a 1-d array holding the axis values to be transformed. * If "forward" is non-zero, the number of axis values supplied for * each position should equal the number of axes in the base Frame * of the FrameSet encapsulated by "this". If "forward" is zero, the * number of axis values supplied for each position should equal the * number of axes in the current Frame of the FrameSet encapsulated by * "this". All the axis values for a position should be in adjacent * elements of the array. * np * The number of points supplied in "in". * forward * If non-zero, the supplied points are assumed to refer to the base * Frame of the encapsulated FrameSet, and they are transformed to the * current Frame. If zero, the supplied points are assumed to refer to * the current Frame of the encapsulated FrameSet, and they are * transformed to the base Frame. * Returned Value: * Pointer to a new dynamically allocated array holding the * transformed axis values. If "forward" is non-zero, the number of axis * values for each position will be equal the number of axes in the * current Frame of the FrameSet encapsulated by "this". If "forward" is * zero, the number of axis values for each position will be equal to the * number of axes in the base Frame of the FrameSet encapsulated by "this". * All the axis values for a position will be in adjacent elements of the * array. The array should be freed using astFree when no longer needed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables: */ AstMapping *map; AstPointSet *pset_in; AstPointSet *pset_out; double **ptr_in; double **ptr_out; double *p; double *result; int ic; int ip; int naxin; int naxout; /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the required Mapping. */ if( forward ) { map = astGetMapping( this->frameset, AST__BASE, AST__CURRENT ); } else { map = astGetMapping( this->frameset, AST__CURRENT, AST__BASE ); } /* Get the number of axis values per input and per output point. */ naxin = astGetNin( map ); naxout = astGetNout( map ); /* Create a pointSet holding the supplied axis values. */ pset_in = astPointSet( np, naxin, "", status ); /* Get pointers to the memory used to store axis values within this PointSet. */ ptr_in = astGetPoints( pset_in ); /* Allocate the output array. */ result = astMalloc( sizeof( double )*(size_t)( naxout*np ) ); /* Check the pointers can be used. */ if( astOK ) { /* Store the supplied axis values in the PointSet memory. */ p = in; for( ip = 0; ip < np; ip++ ) { for( ic = 0; ic < naxin; ic++ ) ptr_in[ ic ][ ip ] = *(p++); } /* Transform the PointSet. */ pset_out = astTransform( map, pset_in, 1, NULL ); /* Get a pointer to the memory in the transformed PointSet. */ ptr_out = astGetPoints( pset_out ); if( pset_out && astStatus == AST__INTER ) { p = in; for( ip = 0; ip < np; ip++ ) { for( ic = 0; ic < naxin; ic++ ) printf("%.*g\n", DBL_DIG, *(p++) ); } } if( astOK ) { /* Store the resulting axis values in the output array. */ p = result; for( ip = 0; ip < np; ip++ ) { for( ic = 0; ic < naxout; ic++ ) *(p++) = ptr_out[ ic ][ ip ]; } } /* Free resources. */ pset_out = astAnnul( pset_out ); } pset_in = astAnnul( pset_in ); map = astAnnul( map ); /* Return NULL if anything went wrong. */ if( !astOK ) result = astAnnul( result ); /* Return the result.*/ return result; } static AstPointSet *RegTransform( AstRegion *this, AstPointSet *in, int forward, AstPointSet *out, AstFrame **frm, int *status ) { /* *+ * Name: * astRegTransform * Purpose: * Transform a set of points using the encapsulated FrameSet. * Type: * Protected function. * Synopsis: * #include "region.h" * AstPointSet *astRegTransform( AstRegion *this, AstPointSet *in, * int forward, AstPointSet *out, * AstFrameSet **frm ) * Class Membership: * Region virtual function * Description: * This function takes a Region and a set of points encapsulated * in a PointSet, and applies either the forward or inverse * coordinate transformation represented by the encapsulated FrameSet. * It also returned a pointer to either the current or base Frame in * the FrameSet. * Parameters: * this * Pointer to the Region. * in * Pointer to the PointSet holding the input coordinate data. If * NULL then the "points" PointSet within the supplied Region * ("this") is used. * forward * A non-zero value indicates that the forward coordinate transformation * (from base to current) should be applied, while a zero value requests * the inverse transformation (from current to base). * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * frm * Location at which to return a pointer to a Frame. If "forward" * is non-zero, the current Frame in the encapsulated FrameSet will * be returned. Otherwise, the base Frame is returned. The returned * pointer should be annulled when no longer needed. May be NULL if * no pointer is needed. * Returned Value: * Pointer to the output (possibly new) PointSet. If "out" is NULL, * the returned pointer will be a clone of "in" if the Mapping is a * UnitMap. If "out" is not NULL, then the supplied "out" PointSet will * be used and returned. * Notes: * - An error will result if the Region supplied does not define * the requested coordinate transformation (either forward or * inverse). * - The number of coordinate values per point in the input * PointSet must match the number of input coordinates for the * Region being applied (or number of output coordinates if the * inverse transformation is requested). This will be equal to the * number of axes in the Region's base Frame (or the current * Frame for the inverse transformation). * - If an output PointSet is supplied, it must have space for * sufficient number of points and coordinate values per point to * accommodate the result (e.g. the number of Region output * coordinates, or number of input coordinates if the inverse * transformation is requested). Any excess space will be ignored. * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstMapping *smap; /* Pointer to simplified Mapping */ AstPointSet *result; /* Pointer value to return */ /* Initialise */ if( frm ) *frm = NULL; /* Check the global error status. */ if ( !astOK ) return NULL; /* If no input PointSet was provided, use the PointSet in the Region. */ if( !in ) { if( this->points ) { in = this->points; } else { astError( AST__INTER, "astRegTransform(%s): No PointSet supplied " "and the supplied %s has no PointSet (internal AST " "programming error)", status, astGetClass( this ),astGetClass( this ) ); } } /* Get the simplified Mapping from base to current Frame. */ smap = astRegMapping( this ); /* If it is a UnitMap, return a clone of the input PointSet unless an explicit output PointSet has been supplied. */ if( astIsAUnitMap( smap ) && !out ) { result = astClone( in ); /* Otherwise use the Mapping to transform the supplied positions. */ } else { result = astTransform( smap, in, forward, out ); } /* Return a pointer to the appropriate Frame. */ if( frm ) *frm = astGetFrame( this->frameset, forward ? AST__CURRENT : AST__BASE ); /* Release resources. */ smap = astAnnul( smap ); /* Return a pointer to the output PointSet. */ return result; } static int Unformat( AstFrame *this_frame, int axis, const char *string, double *value, int *status ) { /* * Name: * Unformat * Purpose: * Read a formatted coordinate value for a Region axis. * Type: * Private function. * Synopsis: * #include "region.h" * int Unformat( AstFrame *this, int axis, const char *string, * double *value, int *status ) * Class Membership: * Region member function (over-rides the public astUnformat * method inherited from the Frame class). * Description: * This function reads a formatted coordinate value for a Region * axis (supplied as a string) and returns the equivalent numerical * value as a double. It also returns the number of characters read * from the string. * Parameters: * this * Pointer to the Region. * axis * The number of the Region axis for which the coordinate * value is to be read (axis numbering starts at zero for the * first axis). * string * Pointer to a constant null-terminated string containing the * formatted coordinate value. * value * Pointer to a double in which the coordinate value read will be * returned. * status * Pointer to the inherited status variable. * Returned Value: * The number of characters read from the string to obtain the * coordinate value. * Notes: * - Any white space at the beginning of the string will be * skipped, as also will any trailing white space following the * coordinate value read. The function's return value will reflect * this. * - A function value of zero (and no coordinate value) will be * returned, without error, if the string supplied does not contain * a suitably formatted value. * - The string "" is recognised as a special case and will * generate the value AST__BAD, without error. The test for this * string is case-insensitive and permits embedded white space. * - A function result of zero will be returned and no coordinate * value will be returned via the "value" pointer if this function * is invoked with the global error status set, or if it should * fail for any reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ double coord; /* Coordinate value read */ int nc; /* Number of characters read */ /* Initialise. */ nc = 0; /* Check the global error status. */ if ( !astOK ) return nc; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astUnformat" ); /* Obtain a pointer to the Region's current Frame and invoke the astUnformat method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); nc = astUnformat( fr, axis, string, &coord ); fr = astAnnul( fr ); /* If an error occurred, clear the number of characters read. */ if ( !astOK ) { nc = 0; /* Otherwise, if characters were read, return the coordinate value. */ } else if ( nc ) { *value = coord; } /* Return the number of characters read. */ return nc; } static int ValidateAxis( AstFrame *this_frame, int axis, int fwd, const char *method, int *status ) { /* * Name: * ValidateAxis * Purpose: * Validate and permute a Region's axis index. * Type: * Private function. * Synopsis: * #include "region.h" * int ValidateAxis( AstFrame *this, int axis, int fwd, const char *method, * int *status ) * Class Membership: * Region member function (over-rides the protected * astValidateAxis method inherited from the Frame class). * Description: * This function checks the validity of an index (zero-based) which * is to be used to address one of the coordinate axes of the * current Frame in a Region. If the index is valid, it is * permuted using the axis permutation array associated with the * Region's current Frame and the (zero-based) permuted axis * index is returned. This gives the index the axis had when the * Frame was first created. If the axis index supplied is not * valid, an error is reported and the global error status is set. * Parameters: * this * Pointer to the Region. * axis * The axis index (zero-based) to be checked. To be valid, it * must lie between zero and (naxes-1) inclusive, where "naxes" * is the number of coordinate axes associated with the * Region's current Frame. * fwd * If non-zero, the suppplied axis index is assumed to be an * "external" axis index, and the corresponding "internal" axis index * is returned as the function value. Otherwise, the suppplied axis * index is assumed to be an "internal" axis index, and the * corresponding "external" axis index is returned as the function * value. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The permuted axis index - either "internal" or "external" as * specified by "fwd". * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ int naxes; /* Number of Region axes */ int result; /* Permuted axis index */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_frame; /* Determine the number of Region axes. */ naxes = astGetNaxes( this ); if ( astOK ) { /* If the Region has no axes, report an error (convert to 1-based axis numbering for the benefit of the public interface). */ if ( naxes == 0 ) { astError( AST__AXIIN, "%s(%s): Invalid attempt to use an axis index " "(%d) for a %s which has no axes.", status, method, astGetClass( this ), axis + 1, astGetClass( this ) ); /* Otherwise, check the axis index for validity and report an error if it is not valid (again, convert to 1-based axis numbering). */ } else if ( ( axis < 0 ) || ( axis >= naxes ) ) { astError( AST__AXIIN, "%s(%s): Axis index (%d) invalid - it should " "be in the range 1 to %d.", status, method, astGetClass( this ), axis + 1, naxes ); /* If the axis index was valid, obtain a pointer to the Region's current Frame and invoke this Frame's astValidateAxis method to obtain the permuted axis index. Annul the Frame pointer afterwards. */ } else { fr = astGetFrame( this->frameset, AST__CURRENT ); result = astValidateAxis( fr, axis, fwd, "astValidateAxis" ); fr = astAnnul( fr ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static void ValidateAxisSelection( AstFrame *this_frame, int naxes, const int *axes, const char *method, int *status ) { /* * Name: * ValidateAxisSelection * Purpose: * Check that a set of axes selected from a Frame is valid. * Type: * Private function. * Synopsis: * #include "region.h" * void ValidateAxisSelection( AstFrame *this, int naxes, * const int *axes, const char *method, int *status ) * Class Membership: * Region member function (over-rides the protected astValidateAxisSelection * method inherited from the Frame class). * Description: * This function checks the validity of an array of (zero-based) * axis indices that specify a set of axes to be selected from a * Frame. To be valid, no axis should be selected more than * once. In assessing this, any axis indices that do not refer to * valid Frame axes (e.g. are set to -1) are ignored. * * If the axis selection is valid, this function returns without further * action. Otherwise, an error is reported and the global error status is * set. * Parameters: * this * Pointer to the Frame. * naxes * The number of axes to be selected (may be zero). * axes * Pointer to an array of int with naxes elements that contains the * (zero based) axis indices to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis selection. This method name is used * solely for constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke this Frame's astValidateAxisSelection method. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); astValidateAxisSelection( fr, naxes, axes, method ); fr = astAnnul( fr ); } static int ValidateSystem( AstFrame *this_frame, AstSystemType system, const char *method, int *status ) { /* * Name: * ValidateSystem * Purpose: * Validate a value for a Frame's System attribute. * Type: * Private function. * Synopsis: * #include "region.h" * int ValidateSystem( AstFrame *this, AstSystemType system, * const char *method, int *status ) * Class Membership: * Region member function (over-rides the protected astValidateSystem * method inherited from the Frame class). * Description: * This function checks the validity of the supplied system value. * If the value is valid, it is returned unchanged. Otherwise, an * error is reported and a value of AST__BADSYSTEM is returned. * Parameters: * this * Pointer to the Frame. * system * The system value to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The validated system value. * Notes: * - A value of AST_BADSYSTEM will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstSystemType result; /* Validated system value */ AstFrame *fr; /* Pointer to FrameSet's current Frame */ AstRegion *this; /* Pointer to the Region structure */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the FrameSet structure. */ this = (AstRegion *) this_frame; /* Obtain a pointer to the Region's encapsulated Frame and invoke the astValidateSystem method for this Frame. Annul the Frame pointer afterwards. */ fr = astGetFrame( this->frameset, AST__CURRENT ); result = astValidateSystem( this, system, method ); fr = astAnnul( fr ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BADSYSTEM; /* Return the result. */ return result; } /* Region Attributes. */ /* -------------------- */ /* *att++ * Name: * Adaptive * Purpose: * Should the area adapt to changes in the coordinate system? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * The coordinate system represented by a Region may be changed by * assigning new values to attributes such as System, Unit, etc. * For instance, a Region representing an area on the sky in ICRS * coordinates may have its System attribute changed so that it * represents (say) Galactic coordinates instead of ICRS. This * attribute controls what happens when the coordinate system * represented by a Region is changed in this way. * * If Adaptive is non-zero (the default), then area represented by the * Region adapts to the new coordinate system. That is, the numerical * values which define the area represented by the Region are changed * by mapping them from the old coordinate system into the new coordinate * system. Thus the Region continues to represent the same physical * area. * * If Adaptive is zero, then area represented by the Region does not adapt * to the new coordinate system. That is, the numerical values which * define the area represented by the Region are left unchanged. Thus * the physical area represented by the Region will usually change. * * As an example, consider a Region describe a range of wavelength from * 2000 Angstrom to 4000 Angstrom. If the Unit attribute for the Region * is changed from Angstrom to "nm" (nanometre), what happens depends * on the setting of Adaptive. If Adaptive is non-zero, the Mapping * from the old to the new coordinate system is found. In this case it * is a simple scaling by a factor of 0.1 (since 1 Angstrom is 0.1 nm). * This Mapping is then used to modify the numerical values within the * Region, changing 2000 to 200 and 4000 to 400. Thus the modified * region represents 200 nm to 400 nm, the same physical space as * the original 2000 Angstrom to 4000 Angstrom. However, if Adaptive * had been zero, then the numerical values would not have been changed, * resulting in the final Region representing 2000 nm to 4000 nm. * * Setting Adaptive to zero can be necessary if you want correct * inaccurate attribute settings in an existing Region. For instance, * when creating a Region you may not know what Epoch value to use, so * you would leave Epoch unset resulting in some default value being used. * If at some later point in the application, the correct Epoch value * is determined, you could assign the correct value to the Epoch * attribute. However, you would first need to set Adaptive temporarily * to zero, because otherwise the area represented by the Region would * be Mapped from the spurious default Epoch to the new correct Epoch, * which is not what is required. * Applicability: * Region * All Regions have this attribute. *att-- */ /* This is a boolean value (0 or 1) with a value of -INT_MAX when undefined but yielding a default of 1. */ astMAKE_CLEAR(Region,Adaptive,adaptive,-INT_MAX) astMAKE_GET(Region,Adaptive,int,1,( ( this->adaptive == -INT_MAX ) ? 1 : this->adaptive )) astMAKE_SET(Region,Adaptive,int,adaptive,( value != 0 )) astMAKE_TEST(Region,Adaptive,( this->adaptive != -INT_MAX )) /* *att++ * Name: * Negated * Purpose: * Region negation flag. * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls whether a Region represents the "inside" or * the "outside" of the area which was supplied when the Region was * created. If the attribute value is zero (the default), the Region * represents the inside of the original area. However, if it is non-zero, * it represents the outside of the original area. The value of this * attribute may be toggled using the c astNegate function. f AST_NEGATE routine. * Note, whether the boundary is considered to be inside the Region or * not is controlled by the Closed attribute. Changing the value of * the Negated attribute does not change the value of the Closed attribute. * Thus, if Region is closed, then the boundary of the Region will be * inside the Region, whatever the setting of the Negated attribute. * Applicability: * Region * All Regions have this attribute. *att-- */ /* This is a boolean value (0 or 1) with a value of -INT_MAX when undefined but yielding a default of zero. */ astMAKE_CLEAR(Region,Negated,negated,(astResetCache(this),-INT_MAX)) astMAKE_GET(Region,Negated,int,0,( ( this->negated == -INT_MAX ) ? 0 : this->negated )) astMAKE_SET(Region,Negated,int,negated,(astResetCache(this),( value != 0 ))) astMAKE_TEST(Region,Negated,( this->negated != -INT_MAX )) /* *att++ * Name: * Bounded * Purpose: * Is the Region bounded? * Type: * Public attribute. * Synopsis: * Integer (boolean), read-only. * Description: * This is a read-only attribute indicating if the Region is bounded. * A Region is bounded if it is contained entirely within some * finite-size bounding box. * Applicability: * Region * All Regions have this attribute. *att-- */ /* *att+ * Name: * RegionFS * Purpose: * Should Region FrameSet be dumped? * Type: * Protected attribute. * Synopsis: * Integer (boolean). * Description: * This attribute indicates whether the FrameSet encapsulated by the * Region should be included in the dump produced by the Dump function. * * If set to a non-zero value (the default), the FrameSet in the Region * will always be included in the dump as usual. If set to zero, the * FrameSet will only be included in the dump if the Mapping from base * to current Frame is not a UnitMap. If the base->current Mapping is * a UnitMap, the FrameSet is omitted from the dump. If the dump is * subsequently used to re-create the Region, the new Region will have a * default FrameSet containing a single default Frame with the appropriate * number of axes. * * This facility is indended to reduce the size of textual dumps of * Regions in situations where the Frame to which the Region refers can * be implied by the context in which the Region is used. This is * often the case when a Region is encapsulated within another Region. * In such cases the current Frame of the encapsulated Region will * usually be equivalent to the base Frame of the parent Region * structure, and so can be re-instated (by calling the astSetRegFS * method) even if the FrameSet is omitted from the dump of the * encapsulated Region. Note if the base->current Mapping in the FrameSet * in the encapsulated Region is not a UnitMap, then we should always * dump the FrameSet regardless of the setting of RegionFS. This is because * the parent Region structure will not know how to convert the PointSet * stored in the encapsulated Region into its own base Frame if the * FrameSet is not available. * Applicability: * Region * All Regions have this attribute. *att- */ /* This is a boolean value (0 or 1) with a value of -INT_MAX when undefined but yielding a default of one. */ astMAKE_CLEAR(Region,RegionFS,regionfs,-INT_MAX) astMAKE_TEST(Region,RegionFS,( this->regionfs != -INT_MAX )) astMAKE_SET(Region,RegionFS,int,regionfs,( value != 0 )) astMAKE_GET(Region,RegionFS,int,1,( ( this->regionfs == -INT_MAX ) ? 1 : this->regionfs )) /* *att++ * Name: * FillFactor * Purpose: * Fraction of the Region which is of interest. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute indicates the fraction of the Region which is of * interest. AST does not use this attribute internally for any purpose. * Typically, it could be used to indicate the fraction of the Region for * which data is available. * * The supplied value must be in the range 0.0 to 1.0, and the default * value is 1.0 (except as noted below). * Applicability: * Region * All Regions have this attribute. * CmpRegion * The default FillFactor for a CmpRegion is the FillFactor of its * first component Region. * Prism * The default FillFactor for a Prism is the product of the * FillFactors of its two component Regions. * Stc * The default FillFactor for an Stc is the FillFactor of its * encapsulated Region. *att-- */ astMAKE_CLEAR(Region,FillFactor,fillfactor,AST__BAD) astMAKE_GET(Region,FillFactor,double,1.0,( ( this->fillfactor == AST__BAD ) ? 1.0 : this->fillfactor )) astMAKE_TEST(Region,FillFactor,( this->fillfactor != AST__BAD )) astMAKE_SET(Region,FillFactor,double,fillfactor,((value<0.0||value>1.0)?( astError(AST__ATSER,"astSetFillFactor(%s): Invalid value (%g) supplied " "for attribute FillFactor.", status,astGetClass(this),value), astError(AST__ATSER,"FillFactor values should be in the range 0.0 to 1.0", status), this->fillfactor):value)) /* *att++ * Name: * MeshSize * Purpose: * Number of points used to represent the boundary of a Region. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute controls how many points are used when creating a * mesh of points covering the boundary or volume of a Region. Such a * mesh is returned by the c astGetRegionMesh f AST_GETREGIONMESH * method. The boundary mesh is also used when testing for overlap * between two Regions: each point in the bomdary mesh of the first * Region is checked to see if it is inside or outside the second Region. * Thus, the reliability of the overlap check depends on the value assigned * to this attribute. If the value used is very low, it is possible for * overlaps to go unnoticed. High values produce more reliable results, but * can result in the overlap test being very slow. The default value is 200 * for two dimensional Regions and 2000 for three or more dimensional * Regions (this attribute is not used for 1-dimensional regions since the * boundary of a simple 1-d Region can only ever have two points). A * value of five is used if the supplied value is less than five. * Applicability: * Region * All Regions have this attribute. * CmpRegion * The default MeshSize for a CmpRegion is the MeshSize of its * first component Region. * Stc * The default MeshSize for an Stc is the MeshSize of its * encapsulated Region. *att-- */ /* If the value of MeshSize is set or cleared, annul the PointSet used to cache a mesh of base Frame boundary points. This will force a new PointSet to be created next time it is needed. See function RegMesh. */ astMAKE_CLEAR(Region,MeshSize,meshsize,(astResetCache(this),-INT_MAX)) astMAKE_SET(Region,MeshSize,int,meshsize,(astResetCache(this),( value > 5 ? value : 5 ))) astMAKE_TEST(Region,MeshSize,( this->meshsize != -INT_MAX )) astMAKE_GET(Region,MeshSize,int,0,( ( this->meshsize == -INT_MAX)?((astGetNaxes(this)==1)?2:((astGetNaxes(this)==2)?200:2000)): this->meshsize )) /* *att++ * Name: * Closed * Purpose: * Should the boundary be considered to be inside the region? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls whether points on the boundary of a Region * are considered to be inside or outside the region. If the attribute * value is non-zero (the default), points on the boundary are considered * to be inside the region (that is, the Region is "closed"). However, * if the attribute value is zero, points on the bounary are considered * to be outside the region. * Applicability: * Region * All Regions have this attribute. * PointList * The value of the Closed attribute is ignored by PointList regions. * If the PointList region has not been negated, then it is always * assumed to be closed. If the PointList region has been negated, then * it is always assumed to be open. This is required since points * have zero volume and therefore consist entirely of boundary. * CmpRegion * The default Closed value for a CmpRegion is the Closed value of its * first component Region. * Stc * The default Closed value for an Stc is the Closed value of its * encapsulated Region. *att-- */ /* This is a boolean value (0 or 1) with a value of -INT_MAX when undefined but yielding a default of 1. */ astMAKE_CLEAR(Region,Closed,closed,(astResetCache(this),-INT_MAX)) astMAKE_GET(Region,Closed,int,1,( ( this->closed == -INT_MAX ) ? 1 : this->closed )) astMAKE_SET(Region,Closed,int,closed,(astResetCache(this),( value != 0 ))) astMAKE_TEST(Region,Closed,( this->closed != -INT_MAX )) /* Access to attributes of the encapsulated Frame. */ /* ----------------------------------------------- */ /* Use the macros defined at the start of this file to implement private member functions that give access to the attributes of the encapsulated Frame of a Region and its axes. These functions over-ride the attribute access methods inherited from the Frame class. */ /* Clear, Get, Set and Test axis-independent Frame attributes. */ MAKE_CLEAR(Digits) MAKE_CLEAR(Domain) MAKE_CLEAR(MatchEnd) MAKE_CLEAR(MaxAxes) MAKE_CLEAR(MinAxes) MAKE_CLEAR(Permute) MAKE_CLEAR(PreserveAxes) MAKE_CLEAR(Title) MAKE_GET(Digits,int) MAKE_GET(Domain,const char *) MAKE_GET(MatchEnd,int) MAKE_GET(MaxAxes,int) MAKE_GET(MinAxes,int) MAKE_GET(Permute,int) MAKE_GET(PreserveAxes,int) MAKE_GET(Title,const char *) MAKE_SET(Digits,int,I) MAKE_SET(Domain,const char *,C) MAKE_SET(MatchEnd,int,I) MAKE_SET(MaxAxes,int,I) MAKE_SET(MinAxes,int,I) MAKE_SET(Permute,int,I) MAKE_SET(PreserveAxes,int,I) MAKE_SET(Title,const char *,C) MAKE_TEST(Digits) MAKE_TEST(Domain) MAKE_TEST(MatchEnd) MAKE_TEST(MaxAxes) MAKE_TEST(MinAxes) MAKE_TEST(Permute) MAKE_TEST(PreserveAxes) MAKE_TEST(Title) MAKE_GET(ActiveUnit,int) MAKE_SET(ActiveUnit,int,I) MAKE_TEST(ActiveUnit) MAKE_GET(System,AstSystemType) MAKE_SET_SYSTEM(System) MAKE_TEST(System) MAKE_CLEAR(System) MAKE_GET(AlignSystem,AstSystemType) MAKE_SET_SYSTEM(AlignSystem) MAKE_TEST(AlignSystem) MAKE_CLEAR(AlignSystem) MAKE_GET(Epoch,double) MAKE_SET(Epoch,double,D) MAKE_TEST(Epoch) MAKE_CLEAR(Epoch) MAKE_GET(ObsLon,double) MAKE_SET(ObsLon,double,D) MAKE_TEST(ObsLon) MAKE_CLEAR(ObsLon) MAKE_GET(ObsLat,double) MAKE_SET(ObsLat,double,D) MAKE_TEST(ObsLat) MAKE_CLEAR(ObsLat) MAKE_GET(ObsAlt,double) MAKE_SET(ObsAlt,double,D) MAKE_TEST(ObsAlt) MAKE_CLEAR(ObsAlt) /* Clear, Get, Set and Test axis-dependent Frame attributes. */ MAKE_CLEAR_AXIS(Direction) MAKE_CLEAR_AXIS(Format) MAKE_CLEAR_AXIS(Label) MAKE_CLEAR_AXIS(Symbol) MAKE_CLEAR_AXIS(Unit) MAKE_GET_AXIS(Direction,int) MAKE_GET_AXIS(Format,const char *) MAKE_GET_AXIS(Label,const char *) MAKE_GET_AXIS(Symbol,const char *) MAKE_GET_AXIS(Unit,const char *) MAKE_SET_AXIS(Direction,int,I) MAKE_SET_AXIS(Format,const char *,C) MAKE_SET_AXIS(Label,const char *,C) MAKE_SET_AXIS(Symbol,const char *,C) MAKE_SET_AXIS(Unit,const char *,C) MAKE_TEST_AXIS(Direction) MAKE_TEST_AXIS(Format) MAKE_TEST_AXIS(Label) MAKE_TEST_AXIS(Symbol) MAKE_TEST_AXIS(Unit) MAKE_GET_AXIS(Bottom,double) MAKE_SET_AXIS(Bottom,double,D) MAKE_TEST_AXIS(Bottom) MAKE_CLEAR_AXIS(Bottom) MAKE_GET_AXIS(Top,double) MAKE_SET_AXIS(Top,double,D) MAKE_TEST_AXIS(Top) MAKE_CLEAR_AXIS(Top) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Region objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Region objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstRegion *in; /* Pointer to input Region */ AstRegion *out; /* Pointer to output Region */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output Regions. */ in = (AstRegion *) objin; out = (AstRegion *) objout; /* For safety, first clear any references to the input memory from the output Region. */ out->basemesh = NULL; out->basegrid = NULL; out->frameset = NULL; out->points = NULL; out->unc = NULL; out->negation = NULL; out->defunc = NULL; /* Now copy each of the above structures. */ out->frameset = astCopy( in->frameset ); if( in->points ) out->points = astCopy( in->points ); if( in->basemesh ) out->basemesh = astCopy( in->basemesh ); if( in->basegrid ) out->basegrid = astCopy( in->basegrid ); if( in->unc ) out->unc = astCopy( in->unc ); if( in->negation ) out->negation = astCopy( in->negation ); if( in->defunc ) out->defunc = astCopy( in->defunc ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Region objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Region objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstRegion *this; /* Pointer to Region */ /* Obtain a pointer to the Region structure. */ this = (AstRegion *) obj; /* Annul all resources. */ this->frameset = astAnnul( this->frameset ); if( this->points ) this->points = astAnnul( this->points ); if( this->basemesh ) this->basemesh = astAnnul( this->basemesh ); if( this->basegrid ) this->basegrid = astAnnul( this->basegrid ); if( this->unc ) this->unc = astAnnul( this->unc ); if( this->negation ) this->negation = astAnnul( this->negation ); if( this->defunc ) this->defunc = astAnnul( this->defunc ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Region objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Region class to an output Channel. * Parameters: * this * Pointer to the Region whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define KEY_LEN 50 /* Maximum length of a keyword */ #define COM_LEN 50 /* Maximum length of a comment */ /* Local Variables: */ AstFrame *fr; /* Pointer to the current Frame */ AstMapping *smap; /* Base->current Mapping */ AstRegion *this; /* Pointer to the Region structure */ AstRegion *unc; /* Pointer to the uncertainty Region */ double dval; /* Floating point attribute value */ int ival; /* Integer attribute value */ int set; /* Attribute value set? */ int unit; /* Base->current is unitmap? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Region structure. */ this = (AstRegion *) this_object; /* Write out values representing the instance variables for the Region class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Negated. */ /* -------- */ set = TestNegated( this, status ); ival = set ? GetNegated( this, status ) : astGetNegated( this ); astWriteInt( channel, "Negate", (ival != 0), 0, ival, ival ? "Region negated" : "Region not negated" ); /* FillFactor */ /* ---------- */ set = TestFillFactor( this, status ); dval = set ? GetFillFactor( this, status ) : astGetFillFactor( this ); astWriteDouble( channel, "Fill", set, 0, dval,"Region fill factor" ); /* MeshSize. */ /* --------- */ set = TestMeshSize( this, status ); ival = set ? GetMeshSize( this, status ) : astGetMeshSize( this ); astWriteInt( channel, "MeshSz", set, 0, ival, "No. of points used to represent boundary" ); /* Closed. */ /* ------- */ set = TestClosed( this, status ); ival = set ? GetClosed( this, status ) : astGetClosed( this ); astWriteInt( channel, "Closed", set, 0, ival, ival ? "Boundary is inside" : "Boundary is outside" ); /* Adaptive */ /* -------- */ set = TestAdaptive( this, status ); ival = set ? GetAdaptive( this, status ) : astGetAdaptive( this ); astWriteInt( channel, "Adapt", (ival != 0), 0, ival, ival ? "Region adapts to coord sys changes" : "Region does not adapt to coord sys changes" ); /* FrameSet */ /* -------- */ /* If the vertices are the same in both base and current Frames (i.e. if the Frames are connected by a UnitMap), then just dump the current Frame (unless the RegionFS attribute is zero, in which case the current Frame can be determined from the higher level context of the Region and so does not need to be dumped- e.g. if the Region is contained within another Region the parent Region will define the current Frame). Otherwise, dump the whole FrameSet. */ ival = astGetRegionFS( this ); smap = astRegMapping( this ); if( ( unit = astIsAUnitMap( smap ) ) ){ set = 0; if( ival ) { fr = astGetFrame( this->frameset, AST__CURRENT ); astWriteObject( channel, "Frm", 1, 1, fr, "Coordinate system" ); fr = astAnnul( fr ); } } else { set = ( ival == 0 ); astWriteObject( channel, "FrmSet", 1, 1, this->frameset, "Original & current coordinate systems" ); } /* Annul the Mapping pointers */ smap = astAnnul( smap ); /* RegionFS */ /* -------- */ astWriteInt( channel, "RegFS", set, 0, ival, ival ? "Include Frame in dump" : "Do not include Frame in dump" ); /* Points */ /* ------ */ if( this->points ) { astWriteObject( channel, "Points", 1, 1, this->points, "Points defining the shape" ); /* If the FrameSet was not included in the dump, then the loaded will use the PointSet to determine the number of axes in the frame spanned by the Region. If there is no PointSet, then we must explicitly include an item giving the number of axes.*/ } else { astWriteInt( channel, "RegAxes", 1, 1, astGetNaxes( this ), "Number of axes spanned by the Region" ); } /* Uncertainty */ /* ----------- */ /* Only dump the uncertinaty Region if required. */ if( astTestUnc( this ) ) { unc = astGetUncFrm( this, AST__BASE ); astWriteObject( channel, "Unc", 1, 1, unc, "Region defining positional uncertainties." ); unc = astAnnul( unc ); } /* Undefine macros local to this function. */ #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsARegion and astCheckRegion functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Region,Frame) astMAKE_CHECK(Region) AstRegion *astInitRegion_( void *mem, size_t size, int init, AstRegionVtab *vtab, const char *name, AstFrame *frame, AstPointSet *pset, AstRegion *unc, int *status ){ /* *+ * Name: * astInitRegion * Purpose: * Initialise a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *astInitRegion( void *mem, size_t size, int init, * AstRegionVtab *vtab, const char *name, * AstFrame *frame, AstpointSet *pset, * AstRegion *unc ) * Class Membership: * Region initialiser. * Description: * This function is provided for use by class implementations to * initialise a new Region object. It allocates memory (if * necessary) to accommodate the Region plus any additional data * associated with the derived class. It then initialises a * Region structure at the start of this memory. If the "init" * flag is set, it also initialises the contents of a virtual * function table for a Region at the start of the memory passed * via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Region is to be * created. This must be of sufficient size to accommodate the * Region data (sizeof(Region)) plus any data used by the * derived class. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Region (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Region structure, so a valid value must be * supplied even if not required for allocating memory. * init * A logical flag indicating if the Region's virtual function * table is to be initialised. If this value is non-zero, the * virtual function table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be * associated with the new Region. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * frame * Pointer to the encapsulated Frame. A deep copy of this Frame is * taken. This means that subsequent changes to the supplied Frame * will have no effect on the new Region. * pset * A PointSet holding the points which define the Region. These * positions should refer to the given Frame. May be NULL. * unc * A pointer to a Region which specifies the uncertainty in the * supplied positions (all points on the boundary of the new Region * being initialised are assumed to have the same uncertainty). A NULL * pointer can be supplied, in which case default uncertainties equal to * 1.0E-6 of the dimensions of the new Region's bounding box are used. * If an uncertainty Region is supplied, it must be of a class for * which all instances are centro-symetric (e.g. Box, Circle, Ellipse, * etc.) or be a Prism containing centro-symetric component Regions. * Its encapsulated Frame must be related to the Frame supplied for * parameter "frame" (i.e. astConvert should be able to find a Mapping * between them). Two positions in the "frame" Frame are considered to be * co-incident if their uncertainty Regions overlap. The centre of the * supplied uncertainty Region is immaterial since it will be re-centred * on the point being tested before use. A deep copy is taken of the * supplied Region. * Returned Value: * A pointer to the new Region. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstFrame *f0; /* Frame to use */ AstRegion *new; /* Pointer to new Region */ int nax; /* No. of axes in supplied Frame */ int ncoord; /* Coords per point */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if( init ) astInitRegionVtab( vtab, name ); /* Note the number of axes in the supplied Frame. */ nax = astGetNaxes( frame ); /* Check the pointset if supplied. */ if( pset ) { /* Note the number of axes per point in the supplied PointSet */ ncoord = astGetNcoord( pset ); /* If OK, check that the number of coordinates per point matches the number of axes in the Frame. Report an error if these numbers do not match. */ if ( astOK && ( ncoord != nax ) ) { astError( AST__NCPIN, "astInitRegion(%s): Bad number of coordinate " "values per point (%d).", status, name, ncoord ); astError( AST__NCPIN, "The %s given requires %d coordinate value(s) " "for each point.", status, astGetClass( frame ), nax ); } } /* Initialise a Frame structure (the parent class) as the first component within the Region structure, allocating memory if necessary. Give this Frame zero axes as the Frame information will be specified by the encapsulated FrameSet. */ new = (AstRegion *) astInitFrame( mem, size, 0, (AstFrameVtab *) vtab, name, 0 ); if ( astOK ) { /* Initialise the Region data. */ /* ----------------------------- */ new->frameset = NULL; new->points = NULL; new->unc = NULL; new->meshsize = -INT_MAX; new->adaptive = -INT_MAX; new->basemesh = NULL; new->basegrid = NULL; new->negated = -INT_MAX; new->closed = -INT_MAX; new->regionfs = -INT_MAX; new->fillfactor = AST__BAD; new->defunc = NULL; new->nomap = 0; new->negation = NULL; /* If the supplied Frame is a Region, gets its encapsulated Frame. If a FrameSet was supplied, use its current Frame, otherwise use the supplied Frame. */ if( astIsARegion( frame ) ) { f0 = astGetFrame( ((AstRegion *) frame)->frameset, AST__CURRENT ); } else if( astIsAFrameSet( frame ) ) { f0 = astGetFrame( (AstFrameSet *) frame, AST__CURRENT ); } else { f0 = astClone( frame ); } /* Store a clone of the supplied PointSet pointer. */ new->points = pset ? astClone( pset ) : NULL; #ifdef DEBUG if( pset ) { double **ptr; double lim; int ii,jj, np; ptr = astGetPoints( pset ); np = astGetNpoint( pset ); lim = sqrt( DBL_MAX ); for( ii = 0; astOK && ii < ncoord; ii++ ) { for( jj = 0; jj < np; jj++ ) { if( fabs( ptr[ ii ][ jj ] ) > lim ) { if( !strcmp( name, "Interval" ) ) { if( ptr[ ii ][ jj ] != AST__BAD && ptr[ ii ][ jj ] != DBL_MAX && ptr[ ii ][ jj ] != -DBL_MAX ) { astError( AST__INTER, "astInitRegion(%s): suspicious " "axis value (%g) supplied.", status, name, ptr[ ii ][ jj ] ); break; } } else { astError( AST__INTER, "astInitRegion(%s): suspicious " "axis value (%g) supplied.", status, name, ptr[ ii ][ jj ] ); break; } } } } } #endif /* Form a FrameSet consisting of two copies of the supplied Frame connected together by a UnitMap, and store in the Region structure. We use the private SetRegFS rather than the protected astSetRegFS because this initialiser may be being called from a subclass which over-rides astSetRegFS. If this were the case, then the implementation of astSetRegFS provided by the subclass may access information within the subclass structure which has not yet been initialised. */ SetRegFS( new, f0, status ); f0 = astAnnul( f0 ); /* Store any uncertainty Region. Use the private SetUnc rather than astSetUnc to avoid subclass implementations using subclass data which has not yet been initialised. */ SetUnc( new, unc, status ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstRegion *astLoadRegion_( void *mem, size_t size, AstRegionVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadRegion * Purpose: * Load a Region. * Type: * Protected function. * Synopsis: * #include "region.h" * AstRegion *astLoadRegion( void *mem, size_t size, * AstRegionVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * Region loader. * Description: * This function is provided to load a new Region using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Region structure in this memory, using data read from the * input Channel. * Parameters: * mem * A pointer to the memory into which the Region is to be * loaded. This must be of sufficient size to accommodate the * Region data (sizeof(Region)) plus any data used by * derived classes. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Region (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Region structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstRegion) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Region. If this is NULL, a pointer * to the (static) virtual function table for the Region class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Region" is used instead. * Returned Value: * A pointer to the new Region. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstFrame *f1; /* Base Frame for encapsulated FrameSet */ AstRegion *new; /* Pointer to the new Region */ int nax; /* No. of axes in Frame */ int naxpt; /* No. of axes in per point */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Region. In this case the Region belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstRegion ); vtab = &class_vtab; name = "Region"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitRegionVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Region. */ new = astLoadFrame( mem, size, (AstFrameVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Region" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Negated */ /* ------- */ new->negated = astReadInt( channel, "negate", -INT_MAX ); if ( TestNegated( new, status ) ) SetNegated( new, new->negated, status ); /* FillFactor */ /* ---------- */ new->fillfactor = astReadDouble( channel, "fill", AST__BAD ); if ( TestFillFactor( new, status ) ) SetFillFactor( new, new->fillfactor, status ); /* MeshSize */ /* -------- */ new->meshsize = astReadInt( channel, "meshsz", -INT_MAX ); if ( TestMeshSize( new, status ) ) SetMeshSize( new, new->meshsize, status ); /* Closed */ /* ------ */ new->closed = astReadInt( channel, "closed", -INT_MAX ); if ( TestClosed( new, status ) ) SetClosed( new, new->closed, status ); /* Adaptive */ /* -------- */ new->adaptive = astReadInt( channel, "adapt", -INT_MAX ); if ( TestAdaptive( new, status ) ) SetAdaptive( new, new->adaptive, status ); /* Points */ /* ------ */ new->points = astReadObject( channel, "points", NULL ); /* If some points were found, ensure that they are in a PointSet and get the number of axis values per point. */ if( new->points ){ if( astIsAPointSet( new->points) ) { naxpt = astGetNcoord( new->points ); } else { naxpt = 0; astError( AST__REGIN, "astLoadRegion(%s): Corrupt %s specifies points " "using a %s (should be a PointSet).", status, astGetClass( new ), astGetClass( new ), astGetClass( new->points ) ); } /* If no PointSet was loaded, attempt to determine the number of axes spanned by the Region by reading the RegAxes value. */ } else { naxpt = astReadInt( channel, "regaxes", 0 ); } /* Uncertainty */ /* ----------- */ new->unc = astReadObject( channel, "unc", NULL ); new->defunc = NULL; /* FrameSet */ /* -------- */ /* First see if the dump contains a single Frame. If so, create a FrameSet from it and a copy of itself, using a UnitMap to connect the two. */ new->nomap = 0; new->frameset = NULL; f1 = astReadObject( channel, "frm", NULL ); if( f1 ) { new->regionfs = 1; nax = astGetNaxes( f1 ); astSetRegFS( new, f1 ); f1 = astAnnul( f1 ); /* If no Frame was found in the dump, look for a FrameSet. */ } else { new->frameset = astReadObject( channel, "frmset", NULL ); if( new->frameset ) { nax = astGetNaxes( new->frameset ); /* If a FrameSet was found, the value of the RegionFS attribute is still unknown and so we must read it from an attribute as normal. */ new->regionfs = astReadInt( channel, "regfs", 1 ); if ( TestRegionFS( new, status ) ) SetRegionFS( new, new->regionfs, status ); } else { nax = 0; } } /* If neither a Frame nor a FrameSet was found, create a default FrameSet and set the RegionFS attribute false, to indicate that the FrameSet should not be used. */ if( !new->frameset ){ nax = naxpt ? naxpt : 1; f1 = astFrame( nax, "", status ); new->frameset = astFrameSet( f1, "", status ); astSetIdent( new->frameset, DUMMY_FS ); f1 = astAnnul( f1 ); new->regionfs = 0; } /* Report an error if the number of axis values per point in the pointset is incorrect. */ if ( astOK && new->points && ( naxpt != nax ) ) { astError( AST__REGIN, "astLoadRegion(%s): Corrupt %s contains " " incorrect number of coordinate values per point (%d).", status, astGetClass( new ), astGetClass( new ), naxpt ); astError( AST__REGIN, "The %s requires %d coordinate value(s) " "for each point.", status, astGetClass( new ), nax ); } /* Initialise other fields which are used as caches for values derived from the attributes set above. */ new->basemesh = NULL; new->basegrid = NULL; /* If an error occurred, clean up by deleting the new Region. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Region pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astRegClearAttrib_( AstRegion *this, const char *attrib, char **base_attrib, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Region,RegClearAttrib))( this, attrib, base_attrib, status ); } void astRegSetAttrib_( AstRegion *this, const char *setting, char **base_setting, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Region,RegSetAttrib))( this, setting, base_setting, status ); } void astNegate_( AstRegion *this, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,Negate))( this, status ); } AstFrame *astGetRegionFrame_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetRegionFrame))( this, status ); } AstFrameSet *astGetRegionFrameSet_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetRegionFrameSet))( this, status ); } AstRegion *astMapRegion_( AstRegion *this, AstMapping *map, AstFrame *frame, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,MapRegion))( this, map, frame, status ); } int astOverlap_( AstRegion *this, AstRegion *that, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Region,Overlap))( this, that, status ); } int astOverlapX_( AstRegion *that, AstRegion *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(that,Region,OverlapX))( that, this, status ); } AstFrame *astRegFrame_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegFrame))( this, status ); } AstRegion *astRegBasePick_( AstRegion *this, int naxes, const int *axes, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegBasePick))( this, naxes, axes, status ); } AstPointSet *astBTransform_( AstRegion *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Region,BTransform))( this, in, forward, out, status ); } AstPointSet *astRegTransform_( AstRegion *this, AstPointSet *in, int forward, AstPointSet *out, AstFrame **frm, int *status ) { if( frm ) *frm = NULL; if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegTransform))( this, in, forward, out, frm, status ); } int astRegPins_( AstRegion *this, AstPointSet *pset, AstRegion *unc, int **mask, int *status ){ if( mask ) *mask = NULL; if ( !astOK ) return 0; return (**astMEMBER(this,Region,RegPins))( this, pset, unc, mask, status ); } AstMapping *astRegMapping_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegMapping))( this, status ); } int astRegDummyFS_( AstRegion *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Region,RegDummyFS))( this, status ); } int astGetBounded_( AstRegion *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Region,GetBounded))( this, status ); } int astTestUnc_( AstRegion *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Region,TestUnc))( this, status ); } void astClearUnc_( AstRegion *this, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,ClearUnc))( this, status ); } void astRegBaseBox_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,RegBaseBox))( this, lbnd, ubnd, status ); } void astRegBaseBox2_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,RegBaseBox2))( this, lbnd, ubnd, status ); } void astResetCache_( AstRegion *this, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,ResetCache))( this, status ); } int astRegTrace_( AstRegion *this, int n, double *dist, double **ptr, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Region,RegTrace))( this, n, dist, ptr, status ); } void astGetRegionBounds_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,GetRegionBounds))( this, lbnd, ubnd, status ); } void astGetRegionMesh_( AstRegion *this, int surface, int maxpoint, int maxcoord, int *npoint, double *points, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,GetRegionMesh))( this, surface, maxpoint, maxcoord, npoint, points, status ); } void astGetRegionPoints_( AstRegion *this, int maxpoint, int maxcoord, int *npoint, double *points, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,GetRegionPoints))( this, maxpoint, maxcoord, npoint, points, status ); } void astShowMesh_( AstRegion *this, int format, const char *ttl, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,ShowMesh))( this, format,ttl, status ); } void astGetRegionBounds2_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,GetRegionBounds2))( this, lbnd, ubnd, status ); } void astRegOverlay_( AstRegion *this, AstRegion *that, int unc, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,RegOverlay))( this, that, unc, status ); } AstPointSet *astRegGrid_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegGrid))( this, status ); } AstPointSet *astRegMesh_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegMesh))( this, status ); } double *astRegCentre_( AstRegion *this, double *cen, double **ptr, int index, int ifrm, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegCentre))( this, cen, ptr, index, ifrm, status ); } AstRegion *astGetNegation_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetNegation))( this, status ); } AstRegion *astGetUncFrm_( AstRegion *this, int ifrm, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetUncFrm))( this, ifrm, status ); } AstRegion *astGetDefUnc_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetDefUnc))( this, status ); } AstRegion *astGetUnc_( AstRegion *this, int def, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetUnc))( this, def, status ); } void astSetUnc_( AstRegion *this, AstRegion *unc, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,SetUnc))( this, unc, status ); } AstFrameSet *astGetRegFS_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,GetRegFS))( this, status ); } void astSetRegFS_( AstRegion *this, AstFrame *frm, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Region,SetRegFS))( this, frm, status ); } AstPointSet *astRegBaseMesh_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegBaseMesh))( this, status ); } AstRegion **astRegSplit_( AstRegion *this, int *nlist, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegSplit))( this, nlist, status ); } AstPointSet *astRegBaseGrid_( AstRegion *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,RegBaseGrid))( this, status ); } AstPointSet *astBndBaseMesh_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,BndBaseMesh))( this, lbnd, ubnd, status ); } AstPointSet *astBndMesh_( AstRegion *this, double *lbnd, double *ubnd, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Region,BndMesh))( this, lbnd, ubnd, status ); } #define MAKE_MASK_(X,Xtype) \ int astMask##X##_( AstRegion *this, AstMapping *map, int inside, int ndim, \ const int lbnd[], const int ubnd[], Xtype in[], \ Xtype val, int *status ) { \ if ( !astOK ) return 0; \ return (**astMEMBER(this,Region,Mask##X))( this, map, inside, ndim, lbnd, \ ubnd, in, val, status ); \ } #if HAVE_LONG_DOUBLE /* Not normally implemented */ MAKE_MASK_(LD,long double) #endif MAKE_MASK_(D,double) MAKE_MASK_(F,float) MAKE_MASK_(L,long int) MAKE_MASK_(UL,unsigned long int) MAKE_MASK_(I,int) MAKE_MASK_(UI,unsigned int) MAKE_MASK_(S,short int) MAKE_MASK_(US,unsigned short int) MAKE_MASK_(B,signed char) MAKE_MASK_(UB,unsigned char) #undef MAKE_MASK_ /* Special public interface functions. */ /* =================================== */ /* These provide the public interface to certain special functions whose public interface cannot be handled using macros (such as astINVOKE) alone. In general, they are named after the corresponding protected version of the function, but with "Id" appended to the name. */ /* Public Interface Function Prototypes. */ /* ------------------------------------- */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ /* Special interface function implementations. */ /* ------------------------------------------- */ AstRegion *astMapRegionId_( AstRegion *this, AstMapping *map, AstFrame *frame, int *status ) { /* *++ * Name: c astMapRegion f AST_MAPREGION * Purpose: * Transform a Region into a new Frame using a given Mapping. * Type: * Public virtual function. * Synopsis: c #include "region.h" c AstRegion *astMapRegion( AstRegion *this, AstMapping *map, c AstFrame *frame ) f RESULT = AST_MAPREGION( THIS, MAP, FRAME, STATUS ) * Class Membership: * Region method. * Description: * This function returns a pointer to a new Region which corresponds to * supplied Region described by some other specified coordinate system. A * Mapping is supplied which transforms positions between the old and new * coordinate systems. The new Region may not be of the same class as * the original region. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Region. c map f MAP = INTEGER (Given) * Pointer to a Mapping which transforms positions from the * coordinate system represented by the supplied Region to the * coordinate system specified by c "frame". f FRAME. * The supplied Mapping should define both forward and inverse * transformations, and these transformations should form a genuine * inverse pair. That is, transforming a position using the forward * transformation and then using the inverse transformation should * produce the original input position. Some Mapping classes (such * as PermMap, MathMap, SphMap) can result in Mappings for which this * is not true. c frame f FRAME = INTEGER (Given) * Pointer to a Frame describing the coordinate system in which * the new Region is required. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astMapRegion() f AST_MAPREGION = INTEGER * A pointer to a new Region. This Region will represent the area * within the coordinate system specified by c "frame" f FRAME * which corresponds to the supplied Region. * Notes: * - The uncertainty associated with the supplied Region is modified * using the supplied Mapping. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - The only difference between this public interface and the protected * astMapRegion interface is that this implementation additionally * simplifies the returned Region. The protected implementation does * not do this since doing so can lead to infinite recursion because * it is sometimes necessary for Simplify to call astMapRegion. */ /* Local Variables: */ AstRegion *new; /* Pointer to new Region */ AstRegion *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the protected astMapRegion function. */ new = astMapRegion( this, map, frame ); /* Simplify the resulting Region. */ result = astSimplify( new ); /* Free resources. */ new = astAnnul( new ); /* If not OK, annul the returned pointer. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } ./ast-7.3.3/grf_pgplot.c0000644000175000017500000013472312262533650013463 0ustar olesoles/* * Name: * grf_pgplot.c * Purpose: * Implement the grf module using the PGPLOT graphics system. * Description: * This file implements the low level 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 modules to support alternative graphics systems. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * RFWS: R.F. Warren-Smith (Starlink) * History: * 27-JUN-1996 (DSB): * Original version. * 13-NOV-1996 (DSB): * Use C wrappers for PGPLOT functions. * 15-NOV-1996 (RFWS): * Merged the C interface to PGPLOT into this file so that the * interface functions can be static. * 7-OCT-1997 (DSB): * Corrected astGText and astGTxExt, by including a check for * reversed axes. Previously, the up-vector was used as supplied * even if the axes had been reversed. * 15-OCT-1997 (DSB): * o Corrected astGText and astGTxExt to take account of non-equal * scales on the two axes. * o Modified astGTxExt so that it includes any leading or trailing * spaces in the returned box. * o Added astGAxScale. * 28-OCT-1998 (DSB): * o Changed interpretation of the Width attribute from inches, to * a multiple of a small line width. * o Wrapper for pgplot F77 subroutine PGQVSZ added. * 30-JAN-2004 (DSB): * o Added GCap * o Renamed GAxScale as GScales * 4-MAR-2011 (DSB): * Added astGBBuf and astGEBuf. */ /* Macros */ /* ====== */ #define MXSTRLEN 80 /* String length at which truncation starts within pgqtxt and pgptxt. */ /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* C to FORTRAN interface functions */ #include "pointset.h" /* Defines AST__BAD */ #include "memory.h" /* Memory allocation facilities */ #include "error.h" /* Error reporting facilities */ #include "grf.h" /* Interface to this module */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include /* Constants. */ /* ========== */ #define R2D 57.29578 /* Radians to degrees factor */ /* Function Prototypes. */ /* ==================== */ /* These define a local C interface to the PGPLOT library. */ static void ccpgline(int n, float xpts[], float ypts[] ); static void ccpgpt(int n, float xpts[], float ypts[], int symbol); static void ccpgptxt(float x, float y, float angle, float fjust, char *text ); static void ccpgqcf(int *cf); static void ccpgqch(float *ch); static void ccpgqci(int *ci); static void ccpglen(int units, char *text, float *xl, float *yl); static void ccpgqcs(int units, float *xch, float *ych); static void ccpgqls(int *ls); static void ccpgqlw(int *lw); static void ccpgqtbg(int *tbci); static void ccpgqtxt(float x, float y, float angle, float fjust, char *text, float xbox[], float ybox[]); static void ccpgqvp(int units, float *x1, float *x2, float *y1, float *y2); static void ccpgqvsz(int units, float *x1, float *x2, float *y1, float *y2); static void ccpgqwin(float *x1, float *x2, float *y1, float *y2); static void ccpgscf(int cf); static void ccpgsch(float ch); static void ccpgsci(int ci); static void ccpgsls(int ls); static void ccpgslw(int lw); static void ccpgstbg(int tbci); static void ccpgupdt( void ); static void ccpgbbuf( void ); static void ccpgebuf( void ); /* These describe the native Fortran interface to the PGPLOT library. The macros used come from the "f77.h" include file. */ F77_SUBROUTINE(pgline)( INTEGER(n), REAL_ARRAY(x), REAL_ARRAY(y) ); F77_SUBROUTINE(pgpt)( INTEGER(n), REAL_ARRAY(x), REAL_ARRAY(y), INTEGER(TYPE) ); F77_SUBROUTINE(pgptxt)( REAL(x), REAL(y), REAL(angle), REAL(fjust), CHARACTER(text) TRAIL(text) ); F77_SUBROUTINE(pgqcf)( INTEGER(ival) ); F77_SUBROUTINE(pgqch)( REAL(rval) ); F77_SUBROUTINE(pgqci)( INTEGER(ival) ); F77_SUBROUTINE(pgqcs)( INTEGER(units), REAL(chv), REAL(chh) ); F77_SUBROUTINE(pglen)( INTEGER(units), CHARACTER(text), REAL(xl), REAL(yl) TRAIL(text) ); F77_SUBROUTINE(pgqls)( INTEGER(ival) ); F77_SUBROUTINE(pgqlw)( INTEGER(ival) ); F77_SUBROUTINE(pgqtbg)( INTEGER(tbg) ); F77_SUBROUTINE(pgqtxt)( REAL(x), REAL(y), REAL(angle), REAL(fjust), CHARACTER(text), REAL_ARRAY(xbox), REAL_ARRAY(ybox) TRAIL(text) ); F77_SUBROUTINE(pgqvp)( INTEGER(units), REAL(vx1), REAL(vx2), REAL(vy1), REAL(vy2) ); 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(pgsls)( INTEGER(ival) ); F77_SUBROUTINE(pgslw)( INTEGER(ival) ); F77_SUBROUTINE(pgstbg)( INTEGER(tbg) ); F77_SUBROUTINE(pgupdt)( ); F77_SUBROUTINE(pgbbuf)( ); F77_SUBROUTINE(pgebuf)( ); /* Externally visible functions. */ /* ============================= */ /* These implement the "grf" interface in terms of the local C interface to PGPLOT. */ int astGBBuf( void ){ /* *+ * Name: * astGBBuf * Purpose: * Start a new graphics buffering context. * Synopsis: * #include "grf.h" * int astGBBuf( void ) * Description: * This function begins saving graphical output commands in an * internal buffer; the commands are held until a matching astGEBuf * call (or until the buffer is emptied by astGFlush). This can * greatly improve the efficiency of some graphics systems. astGBBuf * increments an internal counter, while astGEBuf decrements this * counter and flushes the buffer to the output device when the * counter drops to zero. astGBBuf and astGEBuf calls should always * be paired. * Parameters: * None. * Returned Value: * A value of 0 is returned if an error occurs, and 1 is returned * otherwise. *- */ ccpgbbuf(); return 1; } int astGEBuf( void ){ /* *+ * Name: * astGEBuf * Purpose: * End a graphics buffering context. * Synopsis: * #include "grf.h" * int astGEBuf( void ) * Description: * This function marks the end of a batch of graphical output begun * with the last call of astGBBuf. astGBBuf and astGEBUF calls should * always be paired. Each call to astGBBuf increments a counter, while * each call to astGEBuf decrements the counter. When the counter * reaches 0, the batch of output is written on the output device. * Parameters: * None. * Returned Value: * A value of 0 is returned if an error occurs, and 1 is returned * otherwise. *- */ ccpgebuf(); return 1; } int astGFlush( void ){ /* *+ * Name: * astGFlush * Purpose: * Flush all pending graphics to the output device. * Synopsis: * #include "grf.h" * int astGFlush( 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 astGCap( int cap, int value ){ /* *+ * Name: * astGCap * Purpose: * Indicate if this grf module has a given capability. * Synopsis: * #include "grf.h" * int astGCap( int cap, int value ) * Description: * This function is called by the AST Plot class to determine if the * grf 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 grf.h: * * GRF__SCALES: This function should return a non-zero value if * it implements the astGScales function, and zero otherwise. The * supplied "value" argument should be ignored. * * GRF__MJUST: This function should return a non-zero value if * the astGText and astGTxExt functions recognise "M" as a * character in the justification string. If the first character of * a justification string is "M", then the text should be justified * with the given reference point at the bottom of the bounding box. * This is different to "B" justification, which requests that the * reference point be put on the baseline of the text, since some * characters hang down below the baseline. If the astGText or * astGTxExt function cannot differentiate between "M" and "B", * then this function should return zero, in which case "M" * justification will never be requested by Plot. The supplied * "value" argument should be ignored. * * GRF__ESC: This function should return a non-zero value if the * astGText and astGTxExt 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 astGText and astGTxExt. Otherwise, "value" * indicates whether astGText and astGTxExt should interpret escape * sequences in subsequent calls. If "value" is non-zero then * escape sequences should be interpreted by astGText and * astGTxExt. 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 astGAttr 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. *- */ int result = 0; if( cap == GRF__SCALES ) result = 1; return result; } int astGLine( int n, const float *x, const float *y ){ /* *+ * Name: * astGLine * Purpose: * Draw a polyline (i.e. a set of connected lines). * Synopsis: * #include "grf.h" * int astGLine( int n, const float *x, const float *y ) * 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. * 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 2, or if a NULL pointer is * given for either "x" or "y". *- */ if( n > 1 && x && y ) ccpgline( n, (float *) x, (float *) y ); return 1; } int astGMark( int n, const float *x, const float *y, int type ){ /* *+ * Name: * astGMark * Purpose: * Draw a set of markers. * Synopsis: * #include "grf.h" * int astGMark( int n, const float *x, const float *y, int type ) * Description: * This function displays markers at the given positions. * 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. * type * An integer which can be used to indicate the type of marker symbol * required. * 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 either "x" or "y". *- */ if( n > 0 && x && y ) ccpgpt( n, (float *) x, (float *) y, type ); return 1; } int astGText( const char *text, float x, float y, const char *just, float upx, float upy ){ /* *+ * Name: * astGText * Purpose: * Draw a character string. * Synopsis: * #include "grf.h" * int astGText( const char *text, float x, float y, const char *just, * float upx, float upy ) * Description: * This function displays a character string at a given position * using a specified justification and up-vector. * Parameters: * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * Returned Value: * A value of 0 is returned if an error occurs, and 1 is returned * otherwise. * Notes: * - Any graphics within the rotated box enclosing the text are erased. * - A NULL value for "just" causes a value of "CC" to be used. * - Both "upx" and "upy" being zero causes an error. * - Any unrecognised character in "just" causes an error. *- */ /* Local Variables: */ char lj[ 2 ]; float uplen, xbox[ 4 ], ybox[ 4 ]; float angle, fjust, hu, test, alpha, beta; int i, tbg; /* Check that there is something to draw. */ if( text && text[ 0 ] != 0 ){ /* Fill in any missing parts of the justification string. */ if( just ){ if( just[ 0 ] == 'T' || just[ 0 ] == 'C' || just[ 0 ] == 'B' ){ lj[ 0 ] = just[ 0 ]; } else { astError( AST__GRFER, "astGText: Justification string '%s' is " "invalid.", just ); return 0; } if( just[ 1 ] == 'L' || just[ 1 ] == 'C' || just[ 1 ] == 'R' ){ lj[ 1 ] = just[ 1 ]; } else { astError( AST__GRFER, "astGText: Justification string '%s' " "is invalid.", just ); return 0; } } else { lj[ 0 ] = 'C'; lj[ 1 ] = 'C'; } /* Find the conversion factors between increment in world coordinate axes, and the corresponding increments in millimetres ( Xmm = alpha*Xworld, Ymm = beta*Yworld ). */ if( !astGScales( &alpha, &beta ) ) return 0; /* If either axis is reversed, reverse the supplied up-vector components so that they refer to the world-coordinates axes. */ if( alpha < 0.0 ) upx = -upx; if( beta < 0.0 ) upy = -upy; /* Get the angle between the text base-line and horizontal. */ angle = atan2( -(double) upx*alpha, (double) upy*beta )*R2D; /* Get the fractional horizontal justification as needed by PGPLOT. */ if( lj[ 1 ] == 'L' ) { fjust = 0.0; } else if( lj[ 1 ] == 'R' ) { fjust = 1.0; } else { fjust = 0.5; } /* Unless the requested justification is "Bottom", we need to adjust the supplied reference position before we use it with PGPLOT because PGPLOT assumes "Bottom" justification. */ if( lj[0] != 'B' ) { /* Get the bounding box of the string. Note, only the size of the box is significant here, not its position. Also note, leading and trailing spaces are not included in the bounding box. */ ccpgqtxt( x, y, angle, fjust, (char *) text, xbox, ybox ); /* Normalise the up-vector in world coordinates. */ uplen = sqrt( (double) (upx*upx + upy*upy) ); if( uplen > 0.0 ){ upx /= uplen; upy /= uplen; } else { astError( AST__GRFER, "astGText: Zero length up-vector supplied."); return 0; } /* Find the height of the text above the base-line. Note, the PGPLOT manual is not clear about the order of the corners returned by pgqtxt, so we have to find the largest distance between the corners in the direction of the supplied up-vector. */ hu = 0.0; for( i = 0; i < 4; i++ ){ test = upx*( xbox[ i ] - x ) + upy*( ybox[ i ] - y ); if( test > hu ) hu = test; } /* Adjust the vertical position of the reference point, since PGPLOT requires it to be at the bottom of the text. */ if( lj[ 0 ] == 'T' ){ x -= upx*hu; y -= upy*hu; } else if( lj[ 0 ] == 'C' ){ x -= 0.5*upx*hu; y -= 0.5*upy*hu; } } /* Display the text, erasing any graphics. */ ccpgqtbg( &tbg ); ccpgstbg( 0 ); ccpgptxt( x, y, angle, fjust, (char *) text ); ccpgstbg( tbg ); } /* Return. */ return 1; } int astGScales( float *alpha, float *beta ){ /* *+ * Name: * astGScales * Purpose: * Get the axis scales. * Synopsis: * #include "grf.h" * int astGScales( float *alpha, float *beta ) * Description: * This function returns two values (one for each axis) which scale * increments on the corresponding axis into a "normal" coordinate * system in which: * 1 - The axes have equal scale in terms of (for instance) * millimetres per unit distance. * 2 - X values increase from left to right. * 3 - Y values increase from bottom to top. * Parameters: * alpha * A pointer to the location at which to return the scale for the * X axis (i.e. Xnorm = alpha*Xworld). * beta * A pointer to the location at which to return the scale for the * Y axis (i.e. Ynorm = beta*Yworld). * Returned Value: * A value of 0 is returned if an error occurs, and 1 is returned * otherwise. *- */ /* Local Variables: */ float nx1, nx2, ny1, ny2, wx1, wx2, wy1, wy2; int ret; /* Find the conversion factors between increment in world coordinate axes, and the corresponding increments in millimetres ( Xmm = alpha*Xworld, Ymm = beta*Yworld ). */ ccpgqvp( 2, &nx1, &nx2, &ny1, &ny2 ); ccpgqwin( &wx1, &wx2, &wy1, &wy2 ); if( wx2 != wx1 && wy2 != wy1 && nx2 != nx1 && ny2 != ny1 ) { *alpha= ( nx2 - nx1 ) / ( wx2 - wx1 ); *beta = ( ny2 - ny1 ) / ( wy2 - wy1 ); ret = 1; } else { astError( AST__GRFER, "astGScales: The graphics window or viewport has zero size." ); ret = 0; } return ret; } int astGTxExt( const char *text, float x, float y, const char *just, float upx, float upy, float *xb, float *yb ){ /* *+ * Name: * astGTxExt * Purpose: * Get the extent of a character string. * Synopsis: * #include "grf.h" * int astGTxExt( const char *text, float x, float y, const char *just, * float upx, float upy, float *xb, float *yb ) * Description: * This function returns the corners of a box which would enclose the * supplied character string if it were displayed using astGText. * * The returned box INCLUDES any leading or trailing spaces. * Parameters: * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * 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. * 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 (in world coordinates) * starting at the bottom left. * - A NULL value for "just" causes a value of "CC" to be used. * - Both "upx" and "upy" being zero causes an error. * - Any unrecognised character in "just" causes an error. * - Zero is returned for all bounds of the box if an error occurs. *- */ /* Local Variables: */ char lj[ 2 ]; float udx, udy, vdx, vdy, vx, vy, uplen, xbox[ 4 ], ybox[ 4 ], uxu, uyu, uxd, uyd, ux, uy; float angle, width, test, xl, yl; float alpha, beta, xc, yc, hu, hd, a, b; int i; /* Initialise the returned values to indicate no box available. */ for( i = 0; i < 4; i++ ){ xb[ i ] = 0.0; yb[ i ] = 0.0; } /* Check that there is something to draw. */ if( text && text[ 0 ] != 0 ){ /* Fill in any missing parts of the justification string. */ if( just ){ if( just[ 0 ] == 'T' || just[ 0 ] == 'C' || just[ 0 ] == 'B' ){ lj[ 0 ] = just[ 0 ]; } else { astError( AST__GRFER, "astGTxExt: Justification string '%s' is " "invalid.", just ); return 0; } if( just[ 1 ] == 'L' || just[ 1 ] == 'C' || just[ 1 ] == 'R' ){ lj[ 1 ] = just[ 1 ]; } else { astError( AST__GRFER, "astGTxExt: Justification string '%s' is " "invalid.", just ); return 0; } } else { lj[ 0 ] = 'C'; lj[ 1 ] = 'C'; } /* Find the conversion factors between increment in world coordinate axes, and the corresponding increments in millimetres ( Xmm = alpha*Xworld, Ymm = beta*Yworld ). */ if( !astGScales( &alpha, &beta ) ) return 0; /* If either axis is reversed, reverse the supplied up-vector components so that they refer to the world-coordinates axes. */ if( alpha < 0.0 ) upx = -upx; if( beta < 0.0 ) upy = -upy; /* Convert the up-vector into millimetres. */ ux = alpha*upx; uy = beta*upy; /* Normalise the up-vector to a length of 1 millimetre. */ uplen = sqrt( (double) (ux*ux + uy*uy) ); if( uplen > 0.0 ){ ux /= uplen; uy /= uplen; } else { astError( AST__GRFER, "astGText: Zero length up-vector supplied."); return 0; } /* Form the base-line vector by rotating the up-vector by 90 degrees clockwise. */ vx = uy; vy = -ux; /* Get the angle between the text base-line and horizontal. */ angle = atan2( (double) vy, (double) vx )*R2D; /* Get the bounding box of the string drawn with its bottom left corner at the origin. */ ccpgqtxt( 0.0, 0.0, angle, 0.0, (char *) text, xbox, ybox ); /* Convert the returned bounding box world coordinates into millimetres. */ for( i = 0; i < 4; i++ ){ xbox[ i ] *= alpha; ybox[ i ] *= beta; } /* Find the height of the bounding box, in millimetres. Note, the PGPLOT manual is not clear about the order of the corners returned by pgqtxt, so we have to find the largest distance between the corners in the direction of the supplied up-vector. The reference point is on the text base-line which is not usually at the bottom of the bounding box (some letters - like "y" - extend below the base-line). Find the distance from the base-line to the top (hu) and bottom (hd) of the bounding box. */ hu = -FLT_MAX; hd = FLT_MAX; for( i = 0; i < 4; i++ ){ test = ux*xbox[ i ] + uy*ybox[ i ]; if( test > hu ) hu = test; if( test < hd ) hd = test; } /* Get an up and a down vector scaled to the height/depth of the bounding box above/below the text base-line . */ uxu = ux*hu; uyu = uy*hu; uxd = ux*hd; uyd = uy*hd; /* The bounding box returned by pgqtxt does not include any leading or trailing spaces. We need to include such spaces in the returned box. To do this we get the length of the text string in millimetres using pglen instead of using the bounding box returned by pgqtxt. */ ccpglen( 2, (char *) text, &xl, &yl ); /* The abolute width of the string in millimetres may depend on the up-vector. The values returned by pglen are for horizontal and vertical text. Find the width using the supplied up-vector. */ a = uy*xl; b = ux*yl; width = sqrt( a*a + b*b ); /* The pglen function returns a value which is slightly smaller than the area cleared to hold the text when written using pgptxt. Increase the text width so that it is about equal to the area cleared. */ width += 0.2*hu; /* Scale the base-line vector so that its length is equal to the width of the bounding box (including spaces). */ vx *= width; vy *= width; /* Convert the base-line vector back into world coordinates. */ vx /= alpha; vy /= beta; /* Convert the up and down vectors into world coordinates. */ uxu /= alpha; uyu /= beta; uxd /= alpha; uyd /= beta; /* Find the coordinates at the centre of the bounding box in world coordinates. */ xc = x; yc = y; if( lj[0] == 'B' ) { xc += 0.5*uxu; yc += 0.5*uyu; } else if( lj[0] == 'T' ) { xc -= 0.5*uxu; yc -= 0.5*uyu; } if( lj[1] == 'L' ) { xc += 0.5*vx; yc += 0.5*vy; } else if( lj[1] == 'R' ) { xc -= 0.5*vx; yc -= 0.5*vy; } /* Get the corners of the bounding box. */ vdx = 0.5*vx; vdy = 0.5*vy; udx = 0.5*uxu; udy = 0.5*uyu; /* Bottom left corner... */ xb[ 0 ] = xc - vdx - udx + uxd; yb[ 0 ] = yc - vdy - udy + uyd; /* Bottom right corner... */ xb[ 1 ] = xc + vdx - udx + uxd; yb[ 1 ] = yc + vdy - udy + uyd; /* Top right corner... */ xb[ 2 ] = xc + vdx + udx; yb[ 2 ] = yc + vdy + udy; /* Top left corner... */ xb[ 3 ] = xc - vdx + udx; yb[ 3 ] = yc - vdy + udy; } /* Return. */ return 1; } int astGQch( float *chv, float *chh ){ /* *+ * Name: * astGQch * Purpose: * Return the character height in world coordinates. * Synopsis: * #include "grf.h" * int astGQch( float *chv, float *chh ) * Description: * This function returns the heights of characters drawn vertically and * horizontally in world coordinates. * Parameters: * chv * A pointer to the double which is to receive the height of * characters drawn with a vertical baseline . This will be an * increment in the X axis. * chh * A pointer to the double which is to receive the height of * characters drawn with a horizontal baseline. This will be an * increment in the Y axis. * Returned Value: * A value of 0 is returned if an error occurs, and 1 is returned * otherwise. *- */ /* Local Variables: */ float vx1,vx2,vy1,vy2,wx1,wx2,wy1,wy2; /* Get the character height in normalised device coordinates */ ccpgqcs( 0, chv, chh ); /* Get the bounds of the PGPLOT viewport in normalised device coordinates. */ ccpgqvp( 0, &vx1, &vx2, &vy1, &vy2 ); /* Get the bounds of the PGPLOT window in world coordinates. */ ccpgqwin( &wx1, &wx2, &wy1, &wy2 ); /* Convert the text height from normalised device coordinates into world coordinates for vertical text. Print an error message if the viewport has zero size. */ if( vx1 != vx2 ){ *chv *= ( wx2 - wx1 )/( vx2 - vx1 ); } else { astError( AST__GRFER, "astGQch: The graphics viewport has zero size " "in the X direction."); return 0; } /* Convert the text height from normalised device coordinates into world coordinates for horizontal text. Print an error message if the viewport has zero size. */ if( vy1 != vy2 ){ *chh *= ( wy2 - wy1 )/( vy2 - vy1 ); } else { astError( AST__GRFER, "astGQch: The graphics viewport has zero size " "in the Y direction."); return 0; } /* Return. */ return 1; } int astGAttr( int attr, double value, double *old_value, int prim ){ /* *+ * Name: * astGAttr * Purpose: * Enquire or set a graphics attribute value. * Synopsis: * #include "grf.h" * int int astGAttr( int attr, double value, double *old_value, int prim ) * Description: * This function returns the current value of a specified 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 grf.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, "astGAttr: Unknown graphics attribute '%d' " "requested.", attr ); return 0; } /* Return. */ return 1; } /* Local Functions. */ /* ================ */ /* These implement the local C interface to PGPLOT in terms of its native Fortran interface. Only those PGPLOT functions used within this module are included. */ 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 ccpgpt(int n, float xpts[], float ypts[], int symbol){ F77_INTEGER_TYPE N; F77_REAL_TYPE *XX; F77_REAL_TYPE *YY; F77_INTEGER_TYPE SYMBOL; 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; SYMBOL = (F77_INTEGER_TYPE) symbol; F77_CALL(pgpt)( INTEGER_ARG(&N), REAL_ARRAY_ARG(XX), REAL_ARRAY_ARG(YY), INTEGER_ARG(&SYMBOL) ); XX = (F77_REAL_TYPE *) astFree( (void *) XX ); YY = (F77_REAL_TYPE *) astFree( (void *) YY ); } } static void ccpgptxt(float x, float y, float angle, float fjust, char *text ){ F77_REAL_TYPE X; F77_REAL_TYPE Y; F77_REAL_TYPE ANGLE; F77_REAL_TYPE FJUST; DECLARE_CHARACTER(LTEXT,MXSTRLEN); int ftext_length; X = (F77_REAL_TYPE) x; Y = (F77_REAL_TYPE) y; ANGLE = (F77_REAL_TYPE) angle; FJUST = (F77_REAL_TYPE) fjust; ftext_length = strlen( text ); if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; astStringExport( text, LTEXT, ftext_length ); F77_CALL(pgptxt)( REAL_ARG(&X), REAL_ARG(&Y), REAL_ARG(&ANGLE), REAL_ARG(&FJUST), CHARACTER_ARG(LTEXT) TRAIL_ARG(ftext) ); } static void ccpgqtxt(float x, float y, float angle, float fjust, char *text, float xbox[], float ybox[]){ F77_REAL_TYPE X; F77_REAL_TYPE Y; F77_REAL_TYPE ANGLE; F77_REAL_TYPE FJUST; DECLARE_CHARACTER(LTEXT,MXSTRLEN); F77_REAL_TYPE XBOX[ 4 ]; F77_REAL_TYPE YBOX[ 4 ]; int i; int ftext_length; X = (F77_REAL_TYPE) x; Y = (F77_REAL_TYPE) y; ANGLE = (F77_REAL_TYPE) angle; FJUST = (F77_REAL_TYPE) fjust; ftext_length = strlen( text ); if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; astStringExport( text, LTEXT, ftext_length ); F77_CALL(pgqtxt)( REAL_ARG(&X), REAL_ARG(&Y), REAL_ARG(&ANGLE), REAL_ARG(&FJUST), CHARACTER_ARG(LTEXT), REAL_ARRAY_ARG(XBOX), REAL_ARRAY_ARG(YBOX) TRAIL_ARG(ftext) ); for( i = 0; i < 4; i++ ){ xbox[ i ] = (float) XBOX[ i ]; ybox[ i ] = (float) YBOX[ i ]; } } static void ccpgqtbg(int *tbci){ F77_INTEGER_TYPE TBCI; F77_CALL(pgqtbg)( INTEGER_ARG(&TBCI) ); *tbci = (int) TBCI; } static void ccpgstbg(int tbci){ F77_INTEGER_TYPE TBCI; TBCI = (F77_INTEGER_TYPE) tbci; F77_CALL(pgstbg)( INTEGER_ARG(&TBCI) ); } static void ccpgqcs(int units, float *xch, float *ych){ F77_INTEGER_TYPE UNITS; F77_REAL_TYPE XCH; F77_REAL_TYPE YCH; UNITS = (F77_INTEGER_TYPE) units; F77_CALL(pgqcs)( INTEGER_ARG(&UNITS), REAL_ARG(&XCH), REAL_ARG(&YCH) ); *xch = (float) XCH; *ych = (float) YCH; } static void ccpglen(int units, char *text, float *xl, float *yl ){ F77_INTEGER_TYPE UNITS; F77_REAL_TYPE XL; F77_REAL_TYPE YL; DECLARE_CHARACTER(LTEXT,MXSTRLEN); int ftext_length; UNITS = (F77_INTEGER_TYPE) units; ftext_length = strlen( text ); if( ftext_length > LTEXT_length ) ftext_length = LTEXT_length; astStringExport( text, LTEXT, ftext_length ); F77_CALL(pglen)( INTEGER_ARG(&UNITS), CHARACTER_ARG(LTEXT), REAL_ARG(&XL), REAL_ARG(&YL) TRAIL_ARG(ftext) ); *xl = (float) XL; *yl = (float) YL; } static void ccpgqvp(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(pgqvp)( 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; } 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; } 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 ccpgqls(int *ls){ F77_INTEGER_TYPE LS; F77_CALL(pgqls)( INTEGER_ARG(&LS) ); *ls = (int) LS; } static void ccpgsls(int ls){ F77_INTEGER_TYPE LS; LS = (F77_INTEGER_TYPE) ls; F77_CALL(pgsls)( INTEGER_ARG(&LS) ); } static void ccpgqlw(int *lw){ F77_INTEGER_TYPE LW; F77_CALL(pgqlw)( INTEGER_ARG(&LW) ); *lw = (int) LW; } static void ccpgslw(int lw){ F77_INTEGER_TYPE LW; LW = (F77_INTEGER_TYPE) lw; F77_CALL(pgslw)( INTEGER_ARG(&LW) ); } static void ccpgqch(float *ch){ F77_REAL_TYPE CH; F77_CALL(pgqch)( REAL_ARG(&CH) ); *ch = (float) CH; } static void ccpgsch(float ch){ F77_REAL_TYPE CH; CH = (F77_REAL_TYPE) ch; F77_CALL(pgsch)( REAL_ARG(&CH) ); } static void ccpgqcf(int *cf){ F77_INTEGER_TYPE CF; F77_CALL(pgqcf)( INTEGER_ARG(&CF) ); *cf = (int) CF; } static void ccpgscf(int cf){ F77_INTEGER_TYPE CF; CF = (F77_INTEGER_TYPE) cf; F77_CALL(pgscf)( INTEGER_ARG(&CF) ); } static void ccpgqci(int *ci){ F77_INTEGER_TYPE CI; F77_CALL(pgqci)( INTEGER_ARG(&CI) ); *ci = (int) CI; } static void ccpgsci(int ci){ F77_INTEGER_TYPE CI; CI = (F77_INTEGER_TYPE) ci; F77_CALL(pgsci)( INTEGER_ARG(&ci) ); } static void ccpgupdt( void ){ F77_CALL(pgupdt)(); } static void ccpgbbuf( void ){ F77_CALL(pgbbuf)(); } static void ccpgebuf( void ){ F77_CALL(pgebuf)(); } ./ast-7.3.3/channel.h0000644000175000017500000006672412262533650012742 0ustar olesoles/* *+ * Name: * channel.h * Type: * C include file. * Purpose: * Define the interface to the Channel class. * Invocation: * #include "channel.h" * Description: * This include file defines the interface to the Channel class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * A Channel is the basic form of AST I/O channel, through which * Objects may be written and later read back. It causes I/O to * take place using a textual format via standard input and * standard output. * * Writing to a Channel will result in a textual representation of * an Object being produced on standard output. Reading from a * Channel will causes a textual description of an Object to be * read from standard input, and that Object to be * re-created. Channel I/O is stream based, and multiple objects * may be written or read in succession through the same Channel. A * null Object pointer is returned if there is no more input to * read. * Inheritance: * The Channel class inherits from the Object class. * Attributes Over-Ridden: * None. * New Attributes Defined: * Comment (integer) * A boolean value (0 or 1) which controls whether comments are * to be included in textual output generated by a Channel. If * this value is non-zero (the default), then comments will be * included. If it is zero, comments will be omitted. * Full (integer) * A three-state flag (taking values -1, 0 or +1) which controls * the amount of information included in textual output * generated by a Channel. If this value is zero (the default), * then a modest amount of non-essential but useful information * will be included along with the output. If Full is negative, * all non-essential information will be suppressed, while if it * is positive, the output will include the maximum amount of * information about the Object being written. * Skip (integer) * A boolean value which indicates whether the Objects being * read through a Channel are inter-mixed with other external * data. If this value is zero (the default), then the source of * input data is expected to contain descriptions of AST Objects * and comments and nothing else (if anything else is read, an * error will result). If Skip is non-zero, then any non-Object * data encountered between Objects will simply be skipped over * in order to reach the next Object. * Methods Over-Ridden: * Public: * None. * * Protected: * astClearAttrib * Clear an attribute value for a Mapping. * astGetAttrib * Get an attribute value for a Mapping. * astSetAttrib * Set an attribute value for a Mapping. * astTestAttrib * Test if an attribute value has been set for a Mapping. * New Methods Defined: * Public: * astRead * Read an Object from a Channel. * astWrite * Write an Object to a Channel. * * Protected: * astClearComment * Clear the Comment attribute for a Channel. * astClearFull * Clear the Full attribute for a Channel. * astClearSkip * Clear the Skip attribute for a Channel. * astGetComment * Get the value of the Comment attribute for a Channel. * astGetFull * Get the value of the Full attribute for a Channel. * astGetNextData * Read the next item of data from a data source. * astGetNextText * Read the next line of input text from a data source. * astGetSkip * Get the value of the Skip attribute for a Channel. * astPutNextText * Write a line of output text to a data sink. * astReadClassData * Read values from a data source for a class loader. * astReadDouble * Read a double value as part of loading a class. * astReadInt * Read an int value as part of loading a class. * astReadObject * Read a (sub)Object as part of loading a class. * astReadString * Read a string value as part of loading a class. * astSetComment * Set the value of the Comment attribute for a Channel. * astSetFull * Set the value of the Full attribute for a Channel. * astSetSkip * Set the value of the Skip attribute for a Channel. * astTestComment * Test whether a value has been set for the Comment attribute of a * Channel. * astTestFull * Test whether a value has been set for the Full attribute of a * Channel. * astTestSkip * Test whether a value has been set for the Skip attribute of a * Channel. * astWriteBegin * Write a "Begin" data item to a data sink. * astWriteDouble * Write a double value to a data sink. * astWriteEnd * Write an "End" data item to a data sink. * astWriteInt * Write an integer value to a data sink. * astWriteIsA * Write an "IsA" data item to a data sink. * astWriteObject * Write an Object as a value to a data sink. * astWriteString * Write a string value to a data sink. * Other Class Functions: * Public: * astChannel * Create a Channel. * astChannelFor * Create a Channel from a foreign language interface. * astIsAChannel * Test class membership. * * Protected: * astCheckChannel * Validate class membership. * astInitChannel * Initialise a Channel. * astInitChannelVtab * Initialise the virtual function table for the Channel class. * astLoadChannel * Load a Channel. * Type Definitions: * Public: * AstChannel * Channel object type. * * Protected: * AstChannelVtab * Channel virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 12-AUG-1996 (RFWS): * Original version. * 12-DEC-1996 (RFWS): * Added the astChannelFor function. * 11-NOV-2002 (DSB): * Added astWriteInvocations. * 8-JAN-2003 (DSB): * Added protected astInitAxisVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ /* Note that the usual setting of the CHANNEL_INCLUDED flag, which prevents this file being included more than once, must be deferred until after including the "object.h" file. This is because "object.h" needs to include the present interface definition (as a form of "forward reference") in order to have access to I/O Channels itself. */ #if !defined( CHANNEL_INCLUDED ) #define CHANNEL_INCLUDED /* C header files. */ /* --------------- */ #include /* Macros */ /* ====== */ /* Define constants used to size global arrays in this module. */ #define AST__CHANNEL_GETATTRIB_BUFF_LEN 50 /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* The astWarnings function returns a KeyMap pointer, but we cannot include keymap.h here to define the AstKeyMap type since keymap.h itself include sthis file. So we make a temporary declaration which will be replaced by the full one when the keymap.h file is included. */ struct AstKeyMap; /* Channel structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstChannel { /* Attributes inherited from the parent class. */ AstObject object; /* Parent class structure */ /* Attributes specific to objects in this class. */ const char *(* source)( void ); /* Pointer to source function */ char *(* source_wrap)( const char *(*)(void), int * ); /* Source wrapper function pointer */ void (* sink)( const char * ); /* Pointer to sink function */ void (* sink_wrap)( void (*)( const char *), const char *, int * ); /* Sink wrapper function pointer */ int comment; /* Output comments? */ int full; /* Set max/normal/min information level */ int skip; /* Skip data between Objects? */ int indent; /* Indentation increment in astWrite output */ int report_level; /* Skip data between Objects? */ int strict; /* Report unexpected data items? */ void *data; /* Data to pass to source/sink functions */ char **warnings; /* Array of warning strings */ int nwarn; /* Size of warnings array */ FILE *fd_in; /* Descriptor for source text file */ char *fn_in; /* Full path for source text file */ FILE *fd_out; /* Descriptor for sink text file */ char *fn_out; /* Full path for sink text file */ } AstChannel; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstChannelVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstObjectVtab object_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ struct AstKeyMap *(* Warnings)( AstChannel *, int * ); AstObject *(* Read)( AstChannel *, int * ); AstObject *(* ReadObject)( AstChannel *, const char *, AstObject *, int * ); char *(* GetNextText)( AstChannel *, int * ); char *(* ReadString)( AstChannel *, const char *, const char *, int * ); double (* ReadDouble)( AstChannel *, const char *, double, int * ); int (* GetComment)( AstChannel *, int * ); int (* GetFull)( AstChannel *, int * ); int (* GetStrict)( AstChannel *, int * ); int (* ReadInt)( AstChannel *, const char *, int, int * ); int (* TestComment)( AstChannel *, int * ); int (* TestFull)( AstChannel *, int * ); int (* TestStrict)( AstChannel *, int * ); int (* Write)( AstChannel *, AstObject *, int * ); void (* AddWarning)( AstChannel *, int, const char *, const char *, int * ); void (* ClearComment)( AstChannel *, int * ); void (* ClearFull)( AstChannel *, int * ); void (* ClearStrict)( AstChannel *, int * ); void (* GetNextData)( AstChannel *, int, char **, char **, int * ); void (* PutChannelData)( AstChannel *, void *, int * ); void (* PutNextText)( AstChannel *, const char *, int * ); void (* ReadClassData)( AstChannel *, const char *, int * ); void (* SetComment)( AstChannel *, int, int * ); void (* SetFull)( AstChannel *, int, int * ); void (* SetStrict)( AstChannel *, int, int * ); void (* WriteBegin)( AstChannel *, const char *, const char *, int * ); void (* WriteDouble)( AstChannel *, const char *, int, int, double, const char *, int * ); void (* WriteEnd)( AstChannel *, const char *, int * ); void (* WriteInt)( AstChannel *, const char *, int, int, int, const char *, int * ); void (* WriteIsA)( AstChannel *, const char *, const char *, int * ); void (* WriteObject)( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); void (* WriteString)( AstChannel *, const char *, int, int, const char *, const char *, int * ); int (* GetSkip)( AstChannel *, int * ); int (* TestSkip)( AstChannel *, int * ); void (* ClearSkip)( AstChannel *, int * ); void (* SetSkip)( AstChannel *, int, int * ); int (* GetReportLevel)( AstChannel *, int * ); int (* TestReportLevel)( AstChannel *, int * ); void (* ClearReportLevel)( AstChannel *, int * ); void (* SetReportLevel)( AstChannel *, int, int * ); int (* GetIndent)( AstChannel *, int * ); int (* TestIndent)( AstChannel *, int * ); void (* ClearIndent)( AstChannel *, int * ); void (* SetIndent)( AstChannel *, int, int * ); const char *(* GetSourceFile)( AstChannel *, int * ); int (* TestSourceFile)( AstChannel *, int * ); void (* ClearSourceFile)( AstChannel *, int * ); void (* SetSourceFile)( AstChannel *, const char *, int * ); const char *(* GetSinkFile)( AstChannel *, int * ); int (* TestSinkFile)( AstChannel *, int * ); void (* ClearSinkFile)( AstChannel *, int * ); void (* SetSinkFile)( AstChannel *, const char *, int * ); } AstChannelVtab; /* Define a private structure type used to store linked lists of name-value associations. */ typedef struct AstChannelValue { struct AstChannelValue *flink; /* Link to next element */ struct AstChannelValue *blink; /* Link to previous element */ char *name; /* Pointer to name string */ union { /* Holds pointer to value */ char *string; /* Pointer to string value */ AstObject *object; /* Pointer to Object value */ } ptr; int is_object; /* Whether value is an Object (else string) */ } AstChannelValue; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstChannelGlobals { AstChannelVtab Class_Vtab; int Class_Init; int AstReadClassData_Msg; char GetAttrib_Buff[ AST__CHANNEL_GETATTRIB_BUFF_LEN + 1 ]; int Items_Written; int Current_Indent; int Nest; int Nwrite_Invoc; char **Object_Class; AstChannelValue **Values_List; char **Values_Class; int *Values_OK; int *End_Of_Object; void *Channel_Data; } AstChannelGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Channel) /* Check class membership */ astPROTO_ISA(Channel) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstChannel *astChannel_( const char *(*)( void ), void (*)( const char * ), const char *, int *, ...); #else AstChannel *astChannelId_( const char *(*)( void ), void (*)( const char * ), const char *, ... )__attribute__((format(printf,3,4))); AstChannel *astChannelForId_( const char *(*)( void ), char *(*)( const char *(*)( void ), int * ), void (*)( const char * ), void (*)( void (*)( const char * ), const char *, int * ), const char *, ... ); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstChannel *astInitChannel_( void *, size_t, int, AstChannelVtab *, const char *, const char *(*)( void ), char *(*)( const char *(*)( void ), int * ), void (*)( const char * ), void (*)( void (*)( const char * ), const char *, int * ), int * ); /* Vtab initialiser. */ void astInitChannelVtab_( AstChannelVtab *, const char *, int * ); /* Loader. */ AstChannel *astLoadChannel_( void *, size_t, AstChannelVtab *, const char *, AstChannel *channel, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitChannelGlobals_( AstChannelGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ AstObject *astRead_( AstChannel *, int * ); int astWrite_( AstChannel *, AstObject *, int * ); void astPutChannelData_( AstChannel *, void *, int * ); void *astChannelData_( void ); struct AstKeyMap *astWarnings_( AstChannel *, int * ); char *astSourceWrap_( const char *(*)( void ), int * ); void astSinkWrap_( void (*)( const char * ), const char *, int * ); # if defined(astCLASS) /* Protected */ void astStoreChannelData_( AstChannel *, int * ); AstObject *astReadObject_( AstChannel *, const char *, AstObject *, int * ); char *astGetNextText_( AstChannel *, int * ); char *astReadString_( AstChannel *, const char *, const char *, int * ); double astReadDouble_( AstChannel *, const char *, double, int * ); int astGetComment_( AstChannel *, int * ); int astGetFull_( AstChannel *, int * ); int astGetStrict_( AstChannel *, int * ); int astReadInt_( AstChannel *, const char *, int, int * ); int astTestComment_( AstChannel *, int * ); int astTestFull_( AstChannel *, int * ); int astTestStrict_( AstChannel *, int * ); void astAddWarning_( void *, int, const char *, const char *, int *, ... )__attribute__((format(printf,3,6))); void astClearComment_( AstChannel *, int * ); void astClearFull_( AstChannel *, int * ); void astClearStrict_( AstChannel *, int * ); void astGetNextData_( AstChannel *, int, char **, char **, int * ); void astPutNextText_( AstChannel *, const char *, int * ); void astReadClassData_( AstChannel *, const char *, int * ); void astSetComment_( AstChannel *, int, int * ); void astSetFull_( AstChannel *, int, int * ); void astSetStrict_( AstChannel *, int, int * ); void astWriteBegin_( AstChannel *, const char *, const char *, int * ); void astWriteDouble_( AstChannel *, const char *, int, int, double, const char *, int * ); void astWriteEnd_( AstChannel *, const char *, int * ); void astWriteInt_( AstChannel *, const char *, int, int, int, const char *, int * ); int astWriteInvocations_( int * ); void astWriteIsA_( AstChannel *, const char *, const char *, int * ); void astWriteObject_( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); void astWriteString_( AstChannel *, const char *, int, int, const char *, const char *, int * ); int astGetSkip_( AstChannel *, int * ); int astTestSkip_( AstChannel *, int * ); void astClearSkip_( AstChannel *, int * ); void astSetSkip_( AstChannel *, int, int * ); int astGetReportLevel_( AstChannel *, int * ); int astTestReportLevel_( AstChannel *, int * ); void astClearReportLevel_( AstChannel *, int * ); void astSetReportLevel_( AstChannel *, int, int * ); int astGetIndent_( AstChannel *, int * ); int astTestIndent_( AstChannel *, int * ); void astClearIndent_( AstChannel *, int * ); void astSetIndent_( AstChannel *, int, int * ); const char *astGetSourceFile_( AstChannel *, int * ); int astTestSourceFile_( AstChannel *, int * ); void astClearSourceFile_( AstChannel *, int * ); void astSetSourceFile_( AstChannel *, const char *, int * ); const char *astGetSinkFile_( AstChannel *, int * ); int astTestSinkFile_( AstChannel *, int * ); void astClearSinkFile_( AstChannel *, int * ); void astSetSinkFile_( AstChannel *, const char *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckChannel(this) astINVOKE_CHECK(Channel,this,0) #define astVerifyChannel(this) astINVOKE_CHECK(Channel,this,1) /* Test class membership. */ #define astIsAChannel(this) astINVOKE_ISA(Channel,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astChannel astINVOKE(F,astChannel_) #else #define astChannel astINVOKE(F,astChannelId_) #define astChannelFor astINVOKE(F,astChannelForId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitChannel(mem,size,init,vtab,name,source,source_wrap,sink,sink_wrap) \ astINVOKE(O,astInitChannel_(mem,size,init,vtab,name,source,source_wrap,sink,sink_wrap,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitChannelVtab(vtab,name) astINVOKE(V,astInitChannelVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadChannel(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadChannel_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to member functions. */ /* ------------------------------- */ /* Here we make use of astCheckChannel to validate Channel pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astRead(this) \ astINVOKE(O,astRead_(astCheckChannel(this),STATUS_PTR)) #define astWrite(this,object) \ astINVOKE(V,astWrite_(astCheckChannel(this),astCheckObject(object),STATUS_PTR)) #define astPutChannelData(this,data) \ astINVOKE(V,astPutChannelData_(astCheckChannel(this),data,STATUS_PTR)) #define astWarnings(this) \ astINVOKE(O,astWarnings_(astCheckChannel(this),STATUS_PTR)) #define astSourceWrap astSourceWrap_ #define astSinkWrap astSinkWrap_ #define astChannelData astChannelData_() #if defined(astCLASS) /* Protected */ #define astAddWarning astAddWarning_ #define astStoreChannelData(this) \ astStoreChannelData_(astCheckChannel(this),STATUS_PTR) #define astClearComment(this) \ astINVOKE(V,astClearComment_(astCheckChannel(this),STATUS_PTR)) #define astClearFull(this) \ astINVOKE(V,astClearFull_(astCheckChannel(this),STATUS_PTR)) #define astClearStrict(this) \ astINVOKE(V,astClearStrict_(astCheckChannel(this),STATUS_PTR)) #define astGetComment(this) \ astINVOKE(V,astGetComment_(astCheckChannel(this),STATUS_PTR)) #define astGetFull(this) \ astINVOKE(V,astGetFull_(astCheckChannel(this),STATUS_PTR)) #define astGetNextData(this,begin,name,val) \ astINVOKE(V,astGetNextData_(astCheckChannel(this),begin,name,val,STATUS_PTR)) #define astGetNextText(this) \ astINVOKE(V,astGetNextText_(astCheckChannel(this),STATUS_PTR)) #define astGetStrict(this) \ astINVOKE(V,astGetStrict_(astCheckChannel(this),STATUS_PTR)) #define astPutNextText(this,line) \ astINVOKE(V,astPutNextText_(astCheckChannel(this),line,STATUS_PTR)) #define astReadClassData(this,class) \ astINVOKE(V,astReadClassData_(astCheckChannel(this),class,STATUS_PTR)) #define astReadDouble(this,name,def) \ astINVOKE(V,astReadDouble_(astCheckChannel(this),name,def,STATUS_PTR)) #define astReadInt(this,name,def) \ astINVOKE(V,astReadInt_(astCheckChannel(this),name,def,STATUS_PTR)) #define astReadObject(this,name,def) \ astINVOKE(O,astReadObject_(astCheckChannel(this),name,(def)?astCheckObject(def):NULL,STATUS_PTR)) #define astReadString(this,name,def) \ astINVOKE(V,astReadString_(astCheckChannel(this),name,def,STATUS_PTR)) #define astSetComment(this,value) \ astINVOKE(V,astSetComment_(astCheckChannel(this),value,STATUS_PTR)) #define astSetFull(this,value) \ astINVOKE(V,astSetFull_(astCheckChannel(this),value,STATUS_PTR)) #define astSetStrict(this,value) \ astINVOKE(V,astSetStrict_(astCheckChannel(this),value,STATUS_PTR)) #define astTestComment(this) \ astINVOKE(V,astTestComment_(astCheckChannel(this),STATUS_PTR)) #define astTestFull(this) \ astINVOKE(V,astTestFull_(astCheckChannel(this),STATUS_PTR)) #define astTestStrict(this) \ astINVOKE(V,astTestStrict_(astCheckChannel(this),STATUS_PTR)) #define astWriteBegin(this,class,comment) \ astINVOKE(V,astWriteBegin_(astCheckChannel(this),class,comment,STATUS_PTR)) #define astWriteDouble(this,name,set,helpful,value,comment) \ astINVOKE(V,astWriteDouble_(astCheckChannel(this),name,set,helpful,value,comment,STATUS_PTR)) #define astWriteEnd(this,class) \ astINVOKE(V,astWriteEnd_(astCheckChannel(this),class,STATUS_PTR)) #define astWriteInt(this,name,set,helpful,value,comment) \ astINVOKE(V,astWriteInt_(astCheckChannel(this),name,set,helpful,value,comment,STATUS_PTR)) #define astWriteIsA(this,class,comment) \ astINVOKE(V,astWriteIsA_(astCheckChannel(this),class,comment,STATUS_PTR)) #define astWriteObject(this,name,set,helpful,value,comment) \ astINVOKE(V,astWriteObject_(astCheckChannel(this),name,set,helpful,astCheckObject(value),comment,STATUS_PTR)) #define astWriteString(this,name,set,helpful,value,comment) \ astINVOKE(V,astWriteString_(astCheckChannel(this),name,set,helpful,value,comment,STATUS_PTR)) #define astWriteInvocations astWriteInvocations_(STATUS_PTR) #define astClearSkip(this) \ astINVOKE(V,astClearSkip_(astCheckChannel(this),STATUS_PTR)) #define astGetSkip(this) \ astINVOKE(V,astGetSkip_(astCheckChannel(this),STATUS_PTR)) #define astSetSkip(this,value) \ astINVOKE(V,astSetSkip_(astCheckChannel(this),value,STATUS_PTR)) #define astTestSkip(this) \ astINVOKE(V,astTestSkip_(astCheckChannel(this),STATUS_PTR)) #define astClearReportLevel(this) \ astINVOKE(V,astClearReportLevel_(astCheckChannel(this),STATUS_PTR)) #define astGetReportLevel(this) \ astINVOKE(V,astGetReportLevel_(astCheckChannel(this),STATUS_PTR)) #define astSetReportLevel(this,value) \ astINVOKE(V,astSetReportLevel_(astCheckChannel(this),value,STATUS_PTR)) #define astTestReportLevel(this) \ astINVOKE(V,astTestReportLevel_(astCheckChannel(this),STATUS_PTR)) #define astClearIndent(this) \ astINVOKE(V,astClearIndent_(astCheckChannel(this),STATUS_PTR)) #define astGetIndent(this) \ astINVOKE(V,astGetIndent_(astCheckChannel(this),STATUS_PTR)) #define astSetIndent(this,value) \ astINVOKE(V,astSetIndent_(astCheckChannel(this),value,STATUS_PTR)) #define astTestIndent(this) \ astINVOKE(V,astTestIndent_(astCheckChannel(this),STATUS_PTR)) #define astClearSourceFile(this) \ astINVOKE(V,astClearSourceFile_(astCheckChannel(this),STATUS_PTR)) #define astGetSourceFile(this) \ astINVOKE(V,astGetSourceFile_(astCheckChannel(this),STATUS_PTR)) #define astSetSourceFile(this,value) \ astINVOKE(V,astSetSourceFile_(astCheckChannel(this),value,STATUS_PTR)) #define astTestSourceFile(this) \ astINVOKE(V,astTestSourceFile_(astCheckChannel(this),STATUS_PTR)) #define astClearSinkFile(this) \ astINVOKE(V,astClearSinkFile_(astCheckChannel(this),STATUS_PTR)) #define astGetSinkFile(this) \ astINVOKE(V,astGetSinkFile_(astCheckChannel(this),STATUS_PTR)) #define astSetSinkFile(this,value) \ astINVOKE(V,astSetSinkFile_(astCheckChannel(this),value,STATUS_PTR)) #define astTestSinkFile(this) \ astINVOKE(V,astTestSinkFile_(astCheckChannel(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/fselectormap.c0000644000175000017500000000675112262533650014003 0ustar olesoles/* *+ * Name: * fselectormap.c * Purpose: * Define a FORTRAN 77 interface to the AST SelectorMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the SelectorMap class. * Routines Defined: * AST_ISASELECTORMAP * AST_SELECTORMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S.Berry (Starlink) * History: * 14-MAR-2006 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "selectormap.h" /* C interface to the SelectorMap class */ F77_LOGICAL_FUNCTION(ast_isaselectormap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astWatchSTATUS( astAt( "AST_ISASELECTORMAP", NULL, 0 ); RESULT = astIsASelectorMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_selectormap)( INTEGER(NREG), INTEGER_ARRAY(REGS), DOUBLE(BADVAL), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NREG) GENPTR_INTEGER_ARRAY(REGS) GENPTR_DOUBLE(BADVAL) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; AstObject **regs; astAt( "AST_SELECTORMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); regs = astMalloc( sizeof(AstObject *) * (*NREG) ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } for ( i = 0; i < *NREG; i++ ) { regs[ i ] = astI2P( REGS[ i ] ); } } RESULT = astP2I( astSelectorMap( *NREG, (void **) regs, *BADVAL, "%s", options ) ); astFree( regs ); astFree( options ); ) return RESULT; } ./ast-7.3.3/globals.c0000644000175000017500000001516012262533650012734 0ustar olesoles#if defined( THREAD_SAFE ) #define astCLASS #include "globals.h" #include "error.h" #include #include #include /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* Select the appropriate memory management functions. These will be the system's malloc, free and realloc unless AST was configured with the "--with-starmem" option, in which case they will be the starmem malloc, free and realloc. */ #ifdef HAVE_STAR_MEM_H # include # define MALLOC starMalloc # define FREE starFree # define REALLOC starRealloc #else # define MALLOC malloc # define FREE free # define REALLOC realloc #endif /* Module variables */ /* ================ */ /* A count of the number of thread-specific data structures created so far. Create a mutex to serialise access to this static variable. */ static int nthread = 0; static pthread_mutex_t nthread_mutex = PTHREAD_MUTEX_INITIALIZER; /* External variables visible throughout AST */ /* ========================================= */ /* Set a flag indicating that the thread-specific data key has not yet been created. */ pthread_once_t starlink_ast_globals_initialised = PTHREAD_ONCE_INIT; /* Declare the pthreads key that will be associated with the thread-specific data for each thread. */ pthread_key_t starlink_ast_globals_key; /* Declare the pthreads key that will be associated with the thread-specific status value for each thread. */ pthread_key_t starlink_ast_status_key; /* Function definitions: */ /* ===================== */ void astGlobalsCreateKey_( void ) { /* *+ * Name: * astGlobalsCreateKey_ * Purpose: * Create the thread specific data key used for accessing global data. * Type: * Protected function. * Synopsis: * #include "globals.h" * astGlobalsCreateKey_() * Description: * This function creates the thread-specific data key. It is called * once only by the pthread_once function, which is invoked via the * astGET_GLOBALS(this) macro by each AST function that requires access to * global data. * Returned Value: * Zero for success. *- */ /* Create the key used to access thread-specific global data values. Report an error if it fails. */ if( pthread_key_create( &starlink_ast_globals_key, NULL ) ) { fprintf( stderr, "ast: Failed to create Thread-Specific Data key" ); /* If succesful, create the key used to access the thread-specific status value. Report an error if it fails. */ } else if( pthread_key_create( &starlink_ast_status_key, NULL ) ) { fprintf( stderr, "ast: Failed to create Thread-Specific Status key" ); } } AstGlobals *astGlobalsInit_( void ) { /* *+ * Name: * astGlobalsInit * Purpose: * Create and initialise a structure holding thread-specific global * data values. * Type: * Protected function. * Synopsis: * #include "globals.h" * AstGlobals *astGlobalsInit; * Description: * This function allocates memory to hold thread-specific global data * for use throughout AST, and initialises it. * Returned Value: * Pointer to the structure holding global data values for the * currently executing thread. *- */ /* Local Variables: */ AstGlobals *globals; AstStatusBlock *status; /* Allocate memory to hold the global data values for the currently executing thread. Use malloc rather than astMalloc (the AST memory module uses global data managed by this module and so using astMalloc could put us into an infinite loop). */ globals = MALLOC( sizeof( AstGlobals ) ); if ( !globals ){ fprintf( stderr, "ast: Failed to allocate memory to hold AST " "global data values" ); /* Initialise the global data values. */ } else { /* Each thread has a unique integer identifier. */ pthread_mutex_lock( &nthread_mutex ); globals->thread_identifier = nthread++; pthread_mutex_unlock( &nthread_mutex ); #define INIT(class) astInit##class##Globals_( &(globals->class) ); INIT( Error ); INIT( Memory ); INIT( Object ); INIT( Axis ); INIT( Mapping ); INIT( Frame ); INIT( Channel ); INIT( CmpMap ); INIT( KeyMap ); INIT( FitsChan ); INIT( FitsTable ); INIT( CmpFrame ); INIT( DSBSpecFrame ); INIT( FrameSet ); INIT( LutMap ); INIT( MathMap ); INIT( PcdMap ); INIT( PointSet ); INIT( SkyAxis ); INIT( SkyFrame ); INIT( SlaMap ); INIT( SpecFrame ); INIT( SphMap ); INIT( TimeFrame ); INIT( WcsMap ); INIT( ZoomMap ); INIT( FluxFrame ); INIT( SpecFluxFrame ); INIT( GrismMap ); INIT( IntraMap ); INIT( Plot ); INIT( Plot3D ); INIT( Region ); INIT( Xml ); INIT( XmlChan ); INIT( Box ); INIT( Circle ); INIT( CmpRegion ); INIT( DssMap ); INIT( Ellipse ); INIT( Interval ); INIT( MatrixMap ); INIT( NormMap ); INIT( NullRegion ); INIT( PermMap ); INIT( PointList ); INIT( PolyMap ); INIT( Polygon ); INIT( Prism ); INIT( RateMap ); INIT( SelectorMap ); INIT( ShiftMap ); INIT( SpecMap ); INIT( Stc ); INIT( StcCatalogEntryLocation ); INIT( StcObsDataLocation ); INIT( SwitchMap ); INIT( Table ); INIT( TimeMap ); INIT( TranMap ); INIT( UnitMap ); INIT( WinMap ); INIT( StcResourceProfile ); INIT( StcSearchLocation ); INIT( StcsChan ); #undef INIT /* Save the pointer as the value of the starlink_ast_globals_key thread-specific data key. */ if( pthread_setspecific( starlink_ast_globals_key, globals ) ) { fprintf( stderr, "ast: Failed to store Thread-Specific Data pointer." ); /* We also take this opportunity to allocate and initialise the thread-specific status value. */ } else { status = MALLOC( sizeof( AstStatusBlock ) ); if( status ) { status->internal_status = 0; status->status_ptr = &( status->internal_status ); /* If succesful, store the pointer to this memory as the value of the status key for the currently executing thread. Report an error if this fails. */ if( pthread_setspecific( starlink_ast_status_key, status ) ) { fprintf( stderr, "ast: Failed to store Thread-Specific Status pointer." ); } } else { fprintf( stderr, "ast: Failed to allocate memory for Thread-Specific Status pointer." ); } } } /* Return a pointer to the data structure holding the global data values. */ return globals; } #endif ./ast-7.3.3/fstccatalogentrylocation.c0000644000175000017500000000730212262533650016415 0ustar olesoles/* *+ * Name: * fstccatalogentrylocation.c * Purpose: * Define a FORTRAN 77 interface to the AST StcCatalogEntryLocation class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the StcCatalogEntryLocation class. * Routines Defined: * AST_ISASTCCATALOGENTRYLOCATION * AST_STCCATALOGENTRYLOCATION * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-NOV-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "stccatalogentrylocation.h" /* C interface to the StcCatalogEntryLocation class */ F77_LOGICAL_FUNCTION(ast_isastccatalogentrylocation)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASTCCATALOGENTRYLOCATION", NULL, 0 ); astWatchSTATUS( RESULT = astIsAStcCatalogEntryLocation( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_stccatalogentrylocation)( INTEGER(REG), INTEGER(NCOORDS), INTEGER_ARRAY(COORDS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(REG) GENPTR_INTEGER(NCOORDS) GENPTR_CHARACTER(OPTIONS) GENPTR_INTEGER_ARRAY(COORDS) AstKeyMap **coords; F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_STCCATALOGENTRYLOCATION", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } /* Convert supplied integers to pointers. */ coords = astMalloc( sizeof( AstKeyMap * )*(size_t)( *NCOORDS )); if( astOK ) { for( i = 0; i < *NCOORDS; i++ ) { coords[ i ] = (AstKeyMap *) astMakePointer( astI2P( COORDS[ i ] )); } } RESULT = astP2I( astStcCatalogEntryLocation( astI2P( *REG ), *NCOORDS, coords, "%s", options ) ); astFree( coords ); astFree( options ); ) return RESULT; } ./ast-7.3.3/stcresourceprofile.h0000644000175000017500000001637012262533650015244 0ustar olesoles#if !defined( STCRESOURCEPROFILE_INCLUDED ) /* Include this file only once */ #define STCRESOURCEPROFILE_INCLUDED /* *+ * Name: * stcresourceprofile.h * Type: * C include file. * Purpose: * Define the interface to the StcResourceProfile class. * Invocation: * #include "stcresourceprofile.h" * Description: * This include file defines the interface to the StcResourceProfile class * and provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The StcResourceProfile class is a sub-class of Stc used to describe * the coverage of the datasets contained in some VO resource. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * Inheritance: * The StcResourceProfile class inherits from the Stc class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 26-NOV-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "stc.h" /* Coordinate stcs (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* StcResourceProfile structure. */ /* ----------------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstStcResourceProfile { /* Attributes inherited from the parent class. */ AstStc stc; /* Parent class structure */ } AstStcResourceProfile; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstStcResourceProfileVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstStcVtab stc_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ } AstStcResourceProfileVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstStcResourceProfileGlobals { AstStcResourceProfileVtab Class_Vtab; int Class_Init; } AstStcResourceProfileGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitStcResourceProfileGlobals_( AstStcResourceProfileGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(StcResourceProfile) /* Check class membership */ astPROTO_ISA(StcResourceProfile) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstStcResourceProfile *astStcResourceProfile_( void *, int, AstKeyMap **, const char *, int *, ...); #else AstStcResourceProfile *astStcResourceProfileId_( void *, int, AstKeyMap **, const char *, ... )__attribute__((format(printf,4,5))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstStcResourceProfile *astInitStcResourceProfile_( void *, size_t, int, AstStcResourceProfileVtab *, const char *, AstRegion *, int, AstKeyMap **, int * ); /* Vtab initialiser. */ void astInitStcResourceProfileVtab_( AstStcResourceProfileVtab *, const char *, int * ); /* Loader. */ AstStcResourceProfile *astLoadStcResourceProfile_( void *, size_t, AstStcResourceProfileVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckStcResourceProfile(this) astINVOKE_CHECK(StcResourceProfile,this,0) #define astVerifyStcResourceProfile(this) astINVOKE_CHECK(StcResourceProfile,this,1) /* Test class membership. */ #define astIsAStcResourceProfile(this) astINVOKE_ISA(StcResourceProfile,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astStcResourceProfile astINVOKE(F,astStcResourceProfile_) #else #define astStcResourceProfile astINVOKE(F,astStcResourceProfileId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitStcResourceProfile(mem,size,init,vtab,name,region,ncoords,coords) \ astINVOKE(O,astInitStcResourceProfile_(mem,size,init,vtab,name,region,ncoords,coords,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitStcResourceProfileVtab(vtab,name) astINVOKE(V,astInitStcResourceProfileVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadStcResourceProfile(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadStcResourceProfile_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckStcResourceProfile to validate StcResourceProfile pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #endif #endif ./ast-7.3.3/fbox.c0000644000175000017500000000643512262533650012254 0ustar olesoles/* *+ * Name: * fbox.c * Purpose: * Define a FORTRAN 77 interface to the AST Box class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Box class. * Routines Defined: * AST_ISABOX * AST_BOX * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-MAR-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "box.h" /* C interface to the Box class */ F77_LOGICAL_FUNCTION(ast_isabox)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISABOX", NULL, 0 ); astWatchSTATUS( RESULT = astIsABox( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_box)( INTEGER(FRAME), INTEGER(FORM), DOUBLE_ARRAY(POINT1), DOUBLE_ARRAY(POINT2), INTEGER(UNC), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_INTEGER(FORM) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE_ARRAY(POINT2) GENPTR_INTEGER(UNC) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_BOX", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astBox( astI2P( *FRAME ), *FORM, POINT1, POINT2, astI2P( *UNC ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/ferror.c0000644000175000017500000000345312262533650012612 0ustar olesoles/* *+ * Name: * ferror.c * Purpose: * Define a FORTRAN 77 interface to the AST Error module. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Error module. * Routines Defined: * None. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 15-JUL-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "error.h" /* C interface to the Error module */ /* At present there are no Fortran callable routines in this module. */ ./ast-7.3.3/axis.h0000644000175000017500000005606312262533650012271 0ustar olesoles#if !defined( AXIS_INCLUDED ) /* Include this file only once */ #define AXIS_INCLUDED /* *+ * Name: * axis.h * Type: * C include file. * Purpose: * Define the interface to the Axis class. * Invocation: * #include "axis.h" * Description: * This include file defines the interface to the Axis class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The Axis class implements the basic behaviour of a coordinate * axis, several of which may be assembled to represent a * coordinate system. * Inheritance: * The Axis class inherits from the Object class. * Attributes Over-Ridden: * None. * New Attributes Defined: * Bottom (double) * Lowest legal value for axis. * Digits (integer) * Specifies how many digits of precision are required by * default when a coordinate value for an Axis is formatted * (e.g. using the astAxisFormat method). The Digits value acts * as a default only and is over-ridden if a Format string is * specified explicitly (using the astSetAxisFormat method). The * default supplied by the Axis class for the Digits attribute * itself is 7. * Direction (integer) * Specifies how coordinate values for an Axis should be * displayed. By default, it has the value one, indicating that * they should be shown in the conventional sense * (i.e. increasing left to right for an abscissa and bottom to * top for an ordinate). If set to zero, this attribute * indicates that the direction should be reversed (as would * often be done for an astronomical magnitude or a right * ascension axis, for example). * Format (string) * Specifies the format to be used to display coordinate values * for an Axis (i.e. to convert them from binary to character * form). The interpretation of this string (e.g. by derived * classes) is left to the astAxisFormat method, but the Axis * class interprets this parameter as a C "printf" format string * which should be capable of formatting a single coordinate * value stored as a double (e.g. "%1.7G"). If no Format string * is set, the default supplied by the Axis class is based on * the value of the Digits attribute. * Label (string) * Specifies the label to be attached to an Axis when it is * represented in (e.g.) a graph. It is intended purely for * interpretation by human readers and not by software. The * default supplied by the Axis class is the string "Coordinate * Axis". * Symbol (string) * Specifies the symbol to be used to represent coordinate * values for an Axis in "short form", such as in algebraic * expressions where a full description of the Axis would be * inappropriate. Examples include "RA" and "Dec" (for Right * Ascension and Declination). The default supplied by the Axis * class is the string "x". * Top (double) * Highest legal value for axis. * Unit (string) * Describes the units used to represent coordinate values on an * Axis. The default supplied by the Axis class is an empty * string "". * Methods Over-Ridden: * Public: * None. * Protected: * astSetAttrib * Set an attribute value for an Axis. * New Methods Defined: * Public: * astAxisFormat * Format a coordinate value for an Axis. * astAxisNorm * Normalise an Axis coordinate value. * astAxisUnformat * Read a formatted coordinate value for an Axis. * Protected: * astAxisAbbrev * Abbreviate a formatted Axis value by skipping leading fields. * astAxisDistance * Find the distance between two axis values. * astAxisFields * Identify the fields within a formatted SkyAxis value. * astAxisGap * Find a "nice" gap for tabulating Axis values. * astAxisOffset * Add an increment onto a supplied axis value. * astAxisOverlay * Overlay the attributes of a template Axis on to another Axis. * astClearAxisDigits * Clear the Digits attribute for an Axis. * astClearAxisDirection * Clear the Direction attribute for an Axis. * astClearAxisFormat * Clear the Format attribute for an Axis. * astClearAxisLabel * Clear the Label attribute for an Axis. * astClearAxisSymbol * Clear the Symbol attribute for an Axis. * astClearAxisUnit * Clear the Unit attribute for an Axis. * astGetAxisDigits * Get the value of the Digits attribute for an Axis. * astGetAxisDirection * Get the value of the Direction attribute for an Axis. * astGetAxisFormat * Get a pointer to the Format attribute for an Axis. * astGetAxisLabel * Get a pointer to the Label attribute for an Axis. * astGetAxisSymbol * Get a pointer to the Symbol attribute for an Axis. * astGetAxisUnit * Get a pointer to the Unit attribute for an Axis. * astSetAxisDigits * Set the value of the Digits attribute for an Axis. * astSetAxisDirection * Set the value of the Direction attribute for an Axis. * astSetAxisFormat * Set the value of the Format attribute for an Axis. * astSetAxisLabel * Set the value of the Label attribute for an Axis. * astSetAxisSymbol * Set the value of the Symbol attribute for an Axis. * astSetAxisUnit * Set the value of the Unit attribute for an Axis. * astTestAxisDigits * Test whether a value has been set for the Digits attribute of an * Axis. * astTestAxisDirection * Test whether a value has been set for the Direction attribute of an * Axis. * astTestAxisFormat * Test whether a value has been set for the Format attribute of an * Axis. * astTestAxisLabel * Test whether a value has been set for the Label attribute of an * Axis. * astTestAxisSymbol * Test whether a value has been set for the Symbol attribute of an * Axis. * astTestAxisUnit * Test whether a value has been set for the Unit attribute of an * Axis. * Other Class Functions: * Public: * astAxis * Create an Axis. * astIsAAxis * Test class membership. * Protected: * astCheckAxis * Validate class membership. * astInitAxis * Initialise an Axis. * astLoadAxis * Load an Axis. * Macros: * None. * Type Definitions: * Public: * AstAxis * Axis object type. * Protected: * AstAxisVtab * Axis virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: B.S. Berry (Starlink) * History: * 1-MAR-1996 (RFWS): * Original version. * 25-APR-1996 (RFWS): * Made all attribute access functions protected. * 10-SEP-1996 (RFWS): * Added I/O facilities. * 11-SEP-1996 (RFWS): * Added astAxisGap (written by DSB). * 25-FEB-1998 (RFWS): * Added astAxisUnformat. * 29-AUG-2001 (DSB): * Added AxisDistance and AxisOffset. * 10-OCT-2002 (DSB): * Added Top and Bottom. * 8-JAN-2003 (DSB): * Added protected astInitAxisVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ #if defined(astCLASS) /* Protected */ #include "channel.h" #endif /* Macros */ /* ====== */ #if defined(astCLASS) #define AST__AXIS_GETDEFAULTFORMAT_BUFF_LEN 50 #define AST__AXIS_AXISFORMAT_BUFF_LEN 127 #define AST__AXIS_GETAXISNORMUNIT_BUFF_LEN 127 #define AST__AXIS_GETATTRIB_BUFF_LEN 50 #endif /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* Axis structure. */ /* --------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstAxis { /* Attributes inherited from the parent class. */ AstObject object; /* Parent class structure */ /* Attributes specific to objects in this class. */ char *label; /* Pointer to label string */ char *format; /* Pointer to format string */ char *symbol; /* Pointer to symbol string */ char *unit; /* Pointer to unit string */ int digits; /* Default digits of precision */ int direction; /* Plot in conventional direction? */ double top; /* Highest legal axis value */ double bottom; /* Lowest legal axis value */ } AstAxis; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstAxisVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstObjectVtab object_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ const char *(* AxisAbbrev)( AstAxis *, const char *, const char *, const char *, int * ); const char *(* AxisFormat)( AstAxis *, double, int * ); const char *(* GetAxisFormat)( AstAxis *, int * ); const char *(* GetAxisLabel)( AstAxis *, int * ); const char *(* GetAxisSymbol)( AstAxis *, int * ); const char *(* GetAxisUnit)( AstAxis *, int * ); const char *(* GetAxisNormUnit)( AstAxis *, int * ); double (* AxisGap)( AstAxis *, double, int *, int * ); double (* AxisDistance)( AstAxis *, double, double, int * ); double (* AxisOffset)( AstAxis *, double, double, int * ); int (* AxisIn)( AstAxis *, double, double, double, int, int * ); int (* AxisFields)( AstAxis *, const char *, const char *, int, char **, int *, double *, int * ); int (* AxisUnformat)( AstAxis *, const char *, double *, int * ); int (* GetAxisDigits)( AstAxis *, int * ); int (* GetAxisDirection)( AstAxis *, int * ); int (* TestAxisDigits)( AstAxis *, int * ); int (* TestAxisDirection)( AstAxis *, int * ); int (* TestAxisFormat)( AstAxis *, int * ); int (* TestAxisLabel)( AstAxis *, int * ); int (* TestAxisSymbol)( AstAxis *, int * ); int (* TestAxisUnit)( AstAxis *, int * ); int (* TestAxisNormUnit)( AstAxis *, int * ); void (* AxisNorm)( AstAxis *, double *, int * ); void (* AxisOverlay)( AstAxis *, AstAxis *, int * ); void (* ClearAxisDigits)( AstAxis *, int * ); void (* ClearAxisDirection)( AstAxis *, int * ); void (* ClearAxisFormat)( AstAxis *, int * ); void (* ClearAxisLabel)( AstAxis *, int * ); void (* ClearAxisSymbol)( AstAxis *, int * ); void (* ClearAxisUnit)( AstAxis *, int * ); void (* SetAxisDigits)( AstAxis *, int, int * ); void (* SetAxisDirection)( AstAxis *, int, int * ); void (* SetAxisFormat)( AstAxis *, const char *, int * ); void (* SetAxisLabel)( AstAxis *, const char *, int * ); void (* SetAxisSymbol)( AstAxis *, const char *, int * ); void (* SetAxisUnit)( AstAxis *, const char *, int * ); double (* GetAxisTop)( AstAxis *, int * ); int (* TestAxisTop)( AstAxis *, int * ); void (* ClearAxisTop)( AstAxis *, int * ); void (* SetAxisTop)( AstAxis *, double, int * ); double (* GetAxisBottom)( AstAxis *, int * ); int (* TestAxisBottom)( AstAxis *, int * ); void (* ClearAxisBottom)( AstAxis *, int * ); void (* SetAxisBottom)( AstAxis *, double, int * ); } AstAxisVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstAxisGlobals { AstAxisVtab Class_Vtab; int Class_Init; char GetDefaultFormat_Buff[ AST__AXIS_GETDEFAULTFORMAT_BUFF_LEN + 1 ]; char AxisFormat_Buff[ AST__AXIS_AXISFORMAT_BUFF_LEN + 1 ]; char GetAxisNormUnit_Buff[ AST__AXIS_GETAXISNORMUNIT_BUFF_LEN + 1 ]; char GetAttrib_Buff[ AST__AXIS_GETATTRIB_BUFF_LEN + 1 ]; } AstAxisGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Axis) /* Check class membership */ astPROTO_ISA(Axis) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstAxis *astAxis_( const char *, int *, ...); #else AstAxis *astAxisId_( const char *, ... )__attribute__((format(printf,1,2))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstAxis *astInitAxis_( void *, size_t, int, AstAxisVtab *, const char *, int * ); /* Vtab initialiser. */ void astInitAxisVtab_( AstAxisVtab *, const char *, int * ); /* Loader. */ AstAxis *astLoadAxis_( void *, size_t, AstAxisVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitAxisGlobals_( AstAxisGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ const char *astAxisFormat_( AstAxis *, double, int * ); int astAxisUnformat_( AstAxis *, const char *, double *, int * ); void astAxisNorm_( AstAxis *, double *, int * ); #if defined(astCLASS) /* Protected */ const char *astAxisAbbrev_( AstAxis *, const char *, const char *, const char *, int * ); const char *astGetAxisFormat_( AstAxis *, int * ); const char *astGetAxisLabel_( AstAxis *, int * ); const char *astGetAxisSymbol_( AstAxis *, int * ); const char *astGetAxisUnit_( AstAxis *, int * ); const char *astGetAxisNormUnit_( AstAxis *, int * ); double astAxisGap_( AstAxis *, double, int *, int * ); double astAxisDistance_( AstAxis *, double, double, int * ); double astAxisOffset_( AstAxis *, double, double, int * ); int astGetAxisDigits_( AstAxis *, int * ); int astGetAxisDirection_( AstAxis *, int * ); int astTestAxisDigits_( AstAxis *, int * ); int astTestAxisDirection_( AstAxis *, int * ); int astAxisFields_( AstAxis *, const char *, const char *, int, char **, int *, double *, int * ); int astAxisIn_( AstAxis *, double, double, double, int, int * ); int astTestAxisFormat_( AstAxis *, int * ); int astTestAxisLabel_( AstAxis *, int * ); int astTestAxisSymbol_( AstAxis *, int * ); int astTestAxisUnit_( AstAxis *, int * ); int astTestAxisNormUnit_( AstAxis *, int * ); void astAxisOverlay_( AstAxis *, AstAxis *, int * ); void astClearAxisDigits_( AstAxis *, int * ); void astClearAxisDirection_( AstAxis *, int * ); void astClearAxisFormat_( AstAxis *, int * ); void astClearAxisLabel_( AstAxis *, int * ); void astClearAxisSymbol_( AstAxis *, int * ); void astClearAxisUnit_( AstAxis *, int * ); void astSetAxisDigits_( AstAxis *, int, int * ); void astSetAxisDirection_( AstAxis *, int, int * ); void astSetAxisFormat_( AstAxis *, const char *, int * ); void astSetAxisLabel_( AstAxis *, const char *, int * ); void astSetAxisSymbol_( AstAxis *, const char *, int * ); void astSetAxisUnit_( AstAxis *, const char *, int * ); double astGetAxisTop_( AstAxis *, int * ); int astTestAxisTop_( AstAxis *, int * ); void astClearAxisTop_( AstAxis *, int * ); void astSetAxisTop_( AstAxis *, double, int * ); double astGetAxisBottom_( AstAxis *, int * ); int astTestAxisBottom_( AstAxis *, int * ); void astClearAxisBottom_( AstAxis *, int * ); void astSetAxisBottom_( AstAxis *, double, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckAxis(this) astINVOKE_CHECK(Axis,this,0) #define astVerifyAxis(this) astINVOKE_CHECK(Axis,this,1) /* Test class membership. */ #define astIsAAxis(this) astINVOKE_ISA(Axis,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astAxis astINVOKE(F,astAxis_) #else #define astAxis astINVOKE(F,astAxisId_) #endif #if defined(astCLASS) /* Protected. */ /* Initialiser. */ #define astInitAxis(mem,size,init,vtab,name) \ astINVOKE(O,astInitAxis_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitAxisVtab(vtab,name) astINVOKE(V,astInitAxisVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadAxis(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadAxis_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckAxis to validate Axis pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #define astAxisFormat(this,value) \ astINVOKE(V,astAxisFormat_(astCheckAxis(this),value,STATUS_PTR)) #define astAxisNorm(this,value) \ astINVOKE(V,astAxisNorm_(astCheckAxis(this),value,STATUS_PTR)) #define astAxisUnformat(this,string,value) \ astINVOKE(V,astAxisUnformat_(astCheckAxis(this),string,value,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astAxisAbbrev(this,fmt,str1,str2) \ astINVOKE(V,astAxisAbbrev_(astCheckAxis(this),fmt,str1,str2,STATUS_PTR)) #define astAxisGap(this,gap,ntick) \ astINVOKE(V,astAxisGap_(astCheckAxis(this),gap,ntick,STATUS_PTR)) #define astAxisFields(this,fmt,str,maxfld,fields,nc,val) \ astINVOKE(V,astAxisFields_(astCheckAxis(this),fmt,str,maxfld,fields,nc,val,STATUS_PTR)) #define astAxisIn(this,lo,hi,val,closed) \ astINVOKE(V,astAxisIn_(astCheckAxis(this),lo,hi,val,closed,STATUS_PTR)) #define astAxisDistance(this,v1,v2) \ astINVOKE(V,astAxisDistance_(astCheckAxis(this),v1,v2,STATUS_PTR)) #define astAxisOffset(this,v1,dist) \ astINVOKE(V,astAxisOffset_(astCheckAxis(this),v1,dist,STATUS_PTR)) #define astAxisOverlay(template,result) \ astINVOKE(V,astAxisOverlay_(astCheckAxis(template),astCheckAxis(result),STATUS_PTR)) #define astClearAxisDigits(this) \ astINVOKE(V,astClearAxisDigits_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisDirection(this) \ astINVOKE(V,astClearAxisDirection_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisFormat(this) \ astINVOKE(V,astClearAxisFormat_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisLabel(this) \ astINVOKE(V,astClearAxisLabel_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisSymbol(this) \ astINVOKE(V,astClearAxisSymbol_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisUnit(this) \ astINVOKE(V,astClearAxisUnit_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisDigits(this) \ astINVOKE(V,astGetAxisDigits_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisDirection(this) \ astINVOKE(V,astGetAxisDirection_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisFormat(this) \ astINVOKE(V,astGetAxisFormat_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisLabel(this) \ astINVOKE(V,astGetAxisLabel_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisSymbol(this) \ astINVOKE(V,astGetAxisSymbol_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisUnit(this) \ astINVOKE(V,astGetAxisUnit_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisNormUnit(this) \ astINVOKE(V,astGetAxisNormUnit_(astCheckAxis(this),STATUS_PTR)) #define astSetAxisDigits(this,digits) \ astINVOKE(V,astSetAxisDigits_(astCheckAxis(this),digits,STATUS_PTR)) #define astSetAxisDirection(this,direction) \ astINVOKE(V,astSetAxisDirection_(astCheckAxis(this),direction,STATUS_PTR)) #define astSetAxisFormat(this,format) \ astINVOKE(V,astSetAxisFormat_(astCheckAxis(this),format,STATUS_PTR)) #define astSetAxisLabel(this,label) \ astINVOKE(V,astSetAxisLabel_(astCheckAxis(this),label,STATUS_PTR)) #define astSetAxisSymbol(this,symbol) \ astINVOKE(V,astSetAxisSymbol_(astCheckAxis(this),symbol,STATUS_PTR)) #define astSetAxisUnit(this,unit) \ astINVOKE(V,astSetAxisUnit_(astCheckAxis(this),unit,STATUS_PTR)) #define astTestAxisDigits(this) \ astINVOKE(V,astTestAxisDigits_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisDirection(this) \ astINVOKE(V,astTestAxisDirection_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisFormat(this) \ astINVOKE(V,astTestAxisFormat_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisLabel(this) \ astINVOKE(V,astTestAxisLabel_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisSymbol(this) \ astINVOKE(V,astTestAxisSymbol_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisUnit(this) \ astINVOKE(V,astTestAxisUnit_(astCheckAxis(this),STATUS_PTR)) #define astTestAxisNormUnit(this) \ astINVOKE(V,astTestAxisNormUnit_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisTop(this) \ astINVOKE(V,astClearAxisTop_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisTop(this) \ astINVOKE(V,astGetAxisTop_(astCheckAxis(this),STATUS_PTR)) #define astSetAxisTop(this,top) \ astINVOKE(V,astSetAxisTop_(astCheckAxis(this),top,STATUS_PTR)) #define astTestAxisTop(this) \ astINVOKE(V,astTestAxisTop_(astCheckAxis(this),STATUS_PTR)) #define astClearAxisBottom(this) \ astINVOKE(V,astClearAxisBottom_(astCheckAxis(this),STATUS_PTR)) #define astGetAxisBottom(this) \ astINVOKE(V,astGetAxisBottom_(astCheckAxis(this),STATUS_PTR)) #define astSetAxisBottom(this,bottom) \ astINVOKE(V,astSetAxisBottom_(astCheckAxis(this),bottom,STATUS_PTR)) #define astTestAxisBottom(this) \ astINVOKE(V,astTestAxisBottom_(astCheckAxis(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/ffitstable.c0000644000175000017500000001635412262533650013442 0ustar olesoles/* *+ * Name: * ffitstable.c * Purpose: * Define a FORTRAN 77 interface to the AST FitsTable class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the FitsTable class. * Routines Defined: * AST_ISAFITSTABLE * AST_FITSTABLE * Copyright: * Copyright (C) 2010 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S.Berry (Starlink) * History: * 25-NOV-2010 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "ast_err.h" /* AST error codes */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "fitstable.h" /* C interface to the FitsTable class */ F77_LOGICAL_FUNCTION(ast_isafitstable)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astWatchSTATUS( astAt( "AST_ISAFITSTABLE", NULL, 0 ); RESULT = astIsAFitsTable( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_fitstable)( INTEGER(HEADER), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(HEADER) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_FITSTABLE", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astFitsTable( astI2P( *HEADER ), "%s", options ) ); astFree( options ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_gettableheader)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_INTEGER_TYPE(RESULT); astAt( "AST_GETTABLEHEADER", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astGetTableHeader( astI2P( *THIS ) ) ); ) return RESULT; } F77_SUBROUTINE(ast_puttableheader)( INTEGER(THIS), INTEGER(HEADER), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(HEADER) astAt( "AST_PUTTABLEHEADER", NULL, 0 ); astWatchSTATUS( astPutTableHeader( astI2P( *THIS ), astI2P( *HEADER ) ); ) } F77_INTEGER_FUNCTION(ast_columnnull)( INTEGER(THIS), CHARACTER(COLUMN), LOGICAL(SET), INTEGER(NEWVAL), LOGICAL(WASSET), LOGICAL(HASNULL), INTEGER(STATUS) TRAIL(COLUMN) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(COLUMN) GENPTR_LOGICAL(SET) GENPTR_INTEGER(NEWVAL) GENPTR_LOGICAL(WASSET) GENPTR_LOGICAL(HASNULL) F77_INTEGER_TYPE(RESULT); int wasset, hasnull; char *column; astAt( "AST_COLUMNNULL", NULL, 0 ); astWatchSTATUS( column = astString( COLUMN, COLUMN_length ); RESULT = astColumnNull( astI2P( *THIS ), column, F77_ISTRUE( *SET ) ? 1 : 0, *NEWVAL, &wasset, &hasnull ); *WASSET = wasset ? F77_TRUE : F77_FALSE; *HASNULL = hasnull ? F77_TRUE : F77_FALSE; astFree( column ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_columnsize)( INTEGER(THIS), CHARACTER(COLUMN), INTEGER(STATUS) TRAIL(COLUMN) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(COLUMN) F77_INTEGER_TYPE(RESULT); char *column; size_t result; astAt( "AST_COLUMNSIZE", NULL, 0 ); astWatchSTATUS( column = astString( COLUMN, COLUMN_length ); result = astColumnSize( astI2P( *THIS ), column ); astFree( column ); RESULT = result; if( (size_t) RESULT != result && astOK ) { astError( AST__BIGTAB, "AST_COLUMNSIZE(FitsTable): The number of bytes in the " "column is too large to fit in a Fortran INTEGER.", status ); } ) return RESULT; } F77_SUBROUTINE(ast_getcolumndata)( INTEGER(THIS), CHARACTER(COLUMN), REAL(RNULL), DOUBLE(DNULL), INTEGER(MXSIZE), BYTE_ARRAY(COLDATA), INTEGER(NELEM), INTEGER(STATUS) TRAIL(COLUMN) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(COLUMN) GENPTR_REAL(RNULL) GENPTR_DOUBLE(DNULL) GENPTR_INTEGER(MXSIZE) GENPTR_BYTE_ARRAY(COLDATA) GENPTR_INTEGER(NELEM) char *column; astAt( "AST_GETCOLUMNDATA", NULL, 0 ); astWatchSTATUS( column = astString( COLUMN, COLUMN_length ); astGetColumnData( astI2P( *THIS ), column, *RNULL, *DNULL, *MXSIZE, (void *) COLDATA, NELEM ); astFree( column ); ) } F77_SUBROUTINE(ast_putcolumndata)( INTEGER(THIS), CHARACTER(COLUMN), INTEGER(CLEN), INTEGER(SIZE), BYTE_ARRAY(COLDATA), INTEGER(STATUS) TRAIL(COLUMN) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(COLUMN) GENPTR_INTEGER(CLEN) GENPTR_INTEGER(SIZE) GENPTR_BYTE_ARRAY(COLDATA) char *column; astAt( "AST_PUTCOLUMNDATA", NULL, 0 ); astWatchSTATUS( column = astString( COLUMN, COLUMN_length ); astPutColumnData( astI2P( *THIS ), column, *CLEN, *SIZE, (void *) COLDATA ); astFree( column ); ) } ./ast-7.3.3/normmap.c0000644000175000017500000015510112262533650012762 0ustar olesoles/* *class++ * Name: * NormMap * Purpose: * Normalise coordinates using a supplied Frame. * Constructor Function: c astNormMap f AST_NORMMAP * Description: * The NormMap class implements a Mapping which normalises coordinate * values using the c astNorm function f AST_NORM routine * of a supplied Frame. The number of inputs and outputs of a NormMap * are both equal to the number of axes in the supplied Frame. * * The forward and inverse transformation of a NormMap are both * defined but are identical (that is, they do not form a real inverse * pair in that the inverse transformation does not undo the * normalisation, instead it reapplies it). However, the c astSimplify f AST_SIMPLIFY * function will replace neighbouring pairs of forward and inverse * NormMaps by a single UnitMap. * Inheritance: * The NormMap class inherits from the Mapping class. * Attributes: * The NormMap class does not define any new attributes beyond * those which are applicable to all Mappings. * Functions: c The NormMap class does not define any new functions beyond those f The NormMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 11-JUL-2005 (DSB): * Original version. * 23-AUG-2006 (DSB): * Override astEqual. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS NormMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "unitmap.h" /* Unit Mappings */ #include "normmap.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int *(* parent_mapsplit)( AstMapping *, int, const int *, AstMapping **, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(NormMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(NormMap,Class_Init) #define class_vtab astGLOBAL(NormMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstNormMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstNormMap *astNormMapId_( void *, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *RemoveRegions( AstMapping *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static double Rate( AstMapping *, double *, int, int, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two NormMaps are equivalent. * Type: * Private function. * Synopsis: * #include "normmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * NormMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two NormMaps are equivalent. * Parameters: * this * Pointer to the first Object (a NormMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the NormMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstNormMap *that; AstNormMap *this; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two NormMap structures. */ this = (AstNormMap *) this_object; that = (AstNormMap *) that_object; /* Check the second object is a NormMap. We know the first is a NormMap since we have arrived at this implementation of the virtual function. */ if( astIsANormMap( that ) ) { /* Check the Invert flags for the two NormMaps are equal. */ if( astGetInvert( this ) == astGetInvert( that ) ) { /* Check the two Frames are equal. */ if( astEqual( this->frame, that->frame ) ) { result = 1; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } void astInitNormMapVtab_( AstNormMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitNormMapVtab * Purpose: * Initialise a virtual function table for a NormMap. * Type: * Protected function. * Synopsis: * #include "normmap.h" * void astInitNormMapVtab( AstNormMapVtab *vtab, const char *name ) * Class Membership: * NormMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the NormMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsANormMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; mapping->RemoveRegions = RemoveRegions; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_transform = mapping->Transform; mapping->Transform = Transform; parent_mapsplit = mapping->MapSplit; mapping->MapSplit = MapSplit; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; mapping->MapSplit = MapSplit; mapping->Rate = Rate; /* Declare the copy constructor, destructor and class dump function. */ astSetDump( vtab, Dump, "NormMap", "Normalise axis values" ); astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * NormMap member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstNormMap *this; /* Pointer to NormMap structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the NormMap structure. */ this = (AstNormMap *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->frame, mode, extra, fail ); return result; } #endif static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a NormMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * NormMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated NormMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated NormMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated NormMap which is to be merged with * its neighbours. This should be a cloned copy of the NormMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * NormMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated NormMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *frm1; AstFrame *frm2; AstMapping *smap; AstNormMap *map; AstNormMap *nmap1; AstNormMap *nmap2; int cancel; int map_inv; int nax; int result; /* Initialise. */ result = -1; /* Check the inherited status. */ if ( !astOK ) return result; /* Initialisation to avoid compiler warnings. */ nax = 0; /* Get a pointer to this NormMap. */ map = (AstNormMap *) this; /* Temporarily set its Invert flag to the requested value. */ map_inv = astGetInvert( map ); astSetInvert( map, ( *invert_list )[ where ] ); /* First try to simplify the NormMap by simplifying its encapsulated Frame. */ smap = astSimplify( map->frame ); /* If any simplification took place, create a new NormMap with the simplified Frame. */ if( smap != (AstMapping *) map->frame ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) astNormMap( (AstFrame *) smap, "", status ); result = where; /* The only other simplication which can be performed is to cancel a NormMap with its own inverse in series. */ } else if( series ) { /* Indicate we have nothing to cancel with as yet. */ cancel = -1; /* First consider the lower neighbour. */ if( where > 0 && astIsANormMap( ( *map_list )[ where - 1 ] ) ) { /* Check the Invert flags are opposite */ if( ( *invert_list )[ where ] != ( *invert_list )[ where - 1 ] ) { nmap1 = map; nmap2 = (AstNormMap *) ( *map_list )[ where - 1 ]; /* Check the encapsulated Frames are equal. */ frm1 = nmap1->frame; frm2 = nmap2->frame; if( astEqual( frm1, frm2 ) ) cancel = where - 1; nax = astGetNout( nmap1 ); } } /* Likewise consider the upper neighbour. */ if( cancel == -1 && where + 1 < *nmap && astIsANormMap( ( *map_list )[ where + 1 ] ) ) { if( ( *invert_list )[ where ] != ( *invert_list )[ where + 1 ] ) { nmap1 = map; nmap2 = (AstNormMap *) ( *map_list )[ where + 1 ]; frm1 = nmap1->frame; frm2 = nmap2->frame; if( astEqual( frm1, frm2 ) ) cancel = where + 1; nax = astGetNin( nmap1 ); } } /* If we can cancel with a neightbour, do so. */ if( cancel != -1 ) { (void) astAnnul( ( *map_list )[ where ] ); (void) astAnnul( ( *map_list )[ cancel ] ); ( *map_list )[ where ] = (AstMapping *) astUnitMap( nax, "", status ); ( *invert_list )[ where ] = 0; ( *map_list )[ cancel ] = (AstMapping *) astUnitMap( nax, "", status ); ( *invert_list )[ cancel ] = 0; result = ( cancel < where ) ? cancel : where; } } /* Free resources. */ smap = astAnnul( smap ); /* Reset the original Invert attribute for the specified NormMap */ astSetInvert( map, map_inv ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * NormMap. * Type: * Private function. * Synopsis: * #include "normmap.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * NormMap method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing NormMap. This is only possible if the specified inputs * correspond to some subset of the NormMap outputs. That is, there * must exist a subset of the NormMap outputs for which each output * depends only on the selected NormMap inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied NormMap, then a NULL Mapping is returned. * Parameters: * this * Pointer to the NormMap to be split (the NormMap is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied NormMap, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied NormMap has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied NormMap. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ AstFrame *frm2; /* Pointer to new Frame */ AstNormMap *this; /* Pointer to NormMap structure */ int *result; /* Pointer to returned array */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the parent astMapSplit method to see if it can do the job. */ result = (*parent_mapsplit)( this_map, nin, in, map, status ); /* If not, we provide a special implementation here. */ if( !result ) { /* Get a pointer to the NormMap structure. */ this = (AstNormMap *) this_map; /* Pick the requried axes from the encapsulated Frame. */ frm2 = astPickAxes( this->frame, nin, in, NULL ); /* Create a new NormMap from this. */ *map = (AstMapping *) astNormMap( frm2, "", status ); /* The returned list of output axes is a copy the supplied list of input axes. */ result = astStore( NULL, in, sizeof( int )*(size_t) nin ); /* Free resources. */ frm2 = astAnnul( frm2 ); } /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){ /* * Name: * Rate * Purpose: * Calculate the rate of change of a Mapping output. * Type: * Private function. * Synopsis: * #include "normmap.h" * result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ) * Class Membership: * NormMap member function (overrides the astRate method inherited * from the Mapping class ). * Description: * This function returns the rate of change of a specified output of * the supplied Mapping with respect to a specified input, at a * specified input position. * Parameters: * this * Pointer to the Mapping to be applied. * at * The address of an array holding the axis values at the position * at which the rate of change is to be evaluated. The number of * elements in this array should equal the number of inputs to the * Mapping. * ax1 * The index of the Mapping output for which the rate of change is to * be found (output numbering starts at 0 for the first output). * ax2 * The index of the Mapping input which is to be varied in order to * find the rate of change (input numbering starts at 0 for the first * input). * status * Pointer to the inherited status variable. * Returned Value: * The rate of change of Mapping output "ax1" with respect to input * "ax2", evaluated at "at", or AST__BAD if the value cannot be * calculated. */ return ( ax1 == ax2 ) ? 1.0 : 0.0; } static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) { /* * Name: * RemoveRegions * Purpose: * Remove any Regions from a Mapping. * Type: * Private function. * Synopsis: * #include "normmap.h" * AstMapping *RemoveRegions( AstMapping *this, int *status ) * Class Membership: * NormMap method (over-rides the astRemoveRegions method inherited * from the Mapping class). * Description: * This function searches the supplied Mapping (which may be a * compound Mapping such as a CmpMap) for any component Mappings * that are instances of the AST Region class. It then creates a new * Mapping from which all Regions have been removed. If a Region * cannot simply be removed (for instance, if it is a component of a * parallel CmpMap), then it is replaced with an equivalent UnitMap * in the returned Mapping. * * The implementation provided by the NormMap class invokes the * astRemoveRegions method on the encapsulated Frame, and returns a * new NormMap containing the resulting Frame. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the modified mapping. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *newfrm; /* New component Frame */ AstMapping *result; /* Result pointer to return */ AstNormMap *new; /* Pointer to new MormMap */ AstNormMap *this; /* Pointer to NormMap structure */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the NormMap. */ this = (AstNormMap *) this_mapping; /* Invoke the astRemoveRegions method on the component Frame. */ newfrm = astRemoveRegions( this->frame ); /* If the Frame was not modified, just return a clone of the supplied pointer. */ if( this->frame == newfrm ) { result = astClone( this ); /* Otherwise, we need to create a new NormMap to return. We take a deep copy of the supplied NormMap and then modify the Frame so that we retain any extra information in the supplied NormMap. */ } else { new = astCopy( this ); (void) astAnnul( new->frame ); new->frame = astClone( newfrm ); result = (AstMapping *) new; } /* Free resources. */ newfrm = astAnnul( newfrm ); /* Annul the returned Mapping if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a NormMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "normmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * NormMap member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a NormMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required zoom * factor. * Parameters: * this * Pointer to the NormMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the NormMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstNormMap *map; /* Pointer to NormMap to be applied */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *work; /* Work space for a single point */ int coord; /* Loop counter for coordinates */ int ncoord_in; /* Number of coordinates per input point */ int npoint; /* Number of points */ int point; /* Loop counter for points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the NormMap. */ map = (AstNormMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ ncoord_in = astGetNcoord( in ); npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); work = astMalloc( sizeof( double )* ncoord_in ); /* Perform coordinate arithmetic. */ /* ------------------------------ */ if ( astOK ) { for ( point = 0; point < npoint; point++ ) { for ( coord = 0; coord < ncoord_in; coord++ ) { work[ coord ] = ptr_in[ coord ][ point ]; } astNorm( map->frame, work ); for ( coord = 0; coord < ncoord_in; coord++ ) { ptr_out[ coord ][ point ] = work[ coord ]; } } } /* Free resources */ work = astFree( work ); /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for NormMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for NormMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the * Frame within the NormMap. */ /* Local Variables: */ AstNormMap *in; /* Pointer to input NormMap */ AstNormMap *out; /* Pointer to output NormMap */ /* Check the global error status. */ if ( !astOK ) return; in = (AstNormMap *) objin; out = (AstNormMap *) objout; out->frame = astCopy( in->frame ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for NormMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for NormMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstNormMap *this; /* Pointer to NormMap */ this = (AstNormMap *) obj; this->frame = astAnnul( this->frame ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for NormMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the NormMap class to an output Channel. * Parameters: * this * Pointer to the NormMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstNormMap *this; /* Pointer to the NormMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the NormMap structure. */ this = (AstNormMap *) this_object; /* Write out values representing the instance variables for the NormMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* Frame. */ /* ------ */ astWriteObject( channel, "Frame", 1, 1, this->frame, "Frame defining the normalisation" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsANormMap and astCheckNormMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(NormMap,Mapping) astMAKE_CHECK(NormMap) AstNormMap *astNormMap_( void *frame_void, const char *options, int *status, ...) { /* *++ * Name: c astNormMap f AST_NORMMAP * Purpose: * Create a NormMap. * Type: * Public function. * Synopsis: c #include "normmap.h" c AstNormMap *astNormMap( AstFrame *frame, const char *options, ... ) f RESULT = AST_NORMMAP( FRAME, OPTIONS, STATUS ) * Class Membership: * NormMap constructor. * Description: * This function creates a new NormMap and optionally initialises its * attributes. * * A NormMap is a Mapping which normalises coordinate values using the c astNorm function f AST_NORM routine * of the supplied Frame. The number of inputs and outputs of a NormMap * are both equal to the number of axes in the supplied Frame. * * The forward and inverse transformation of a NormMap are both * defined but are identical (that is, they do not form a real inverse * pair in that the inverse transformation does not undo the * normalisation, instead it reapplies it). However, the c astSimplify f AST_SIMPLIFY * function will replace neighbouring pairs of forward and inverse * NormMaps by a single UnitMap. * Parameters: c frame f FRAME = INTEGER (Given) * A pointer to the Frame which is to be used to normalise the * supplied axis values. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new NormMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new NormMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astNormMap() f AST_NORMMAP = INTEGER * A pointer to the new NormMap. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* The Frame pointer */ AstNormMap *new; /* Pointer to new NormMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate pointers to the Frame structures provided. */ frame = astCheckFrame( frame_void ); /* Initialise the NormMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitNormMap( NULL, sizeof( AstNormMap ), !class_init, &class_vtab, "NormMap", frame ); if( astOK ) { /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new NormMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new NormMap. */ return new; } AstNormMap *astNormMapId_( void *frame_void, const char *options, ... ) { /* * Name: * astNormMapId_ * Purpose: * Create a NormMap. * Type: * Private function. * Synopsis: * #include "normmap.h" * AstNormMap *astNormMapId_( int ncoord, double zoom, * const char *options, ... ) * Class Membership: * NormMap constructor. * Description: * This function implements the external (public) interface to the * astNormMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astNormMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astNormMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astNormMap_. * Returned Value: * The ID value associated with the new NormMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* The Frame pointer */ AstNormMap *new; /* Pointer to new NormMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate pointers to the Frame structures provided. */ frame = astVerifyFrame( astMakePointer( frame_void ) ); /* Initialise the NormMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitNormMap( NULL, sizeof( AstNormMap ), !class_init, &class_vtab, "NormMap", frame ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new NormMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new NormMap. */ return astMakeId( new ); } AstNormMap *astInitNormMap_( void *mem, size_t size, int init, AstNormMapVtab *vtab, const char *name, AstFrame *frame, int *status ) { /* *+ * Name: * astInitNormMap * Purpose: * Initialise a NormMap. * Type: * Protected function. * Synopsis: * #include "normmap.h" * AstNormMap *astInitNormMap( void *mem, size_t size, int init, * AstNormMapVtab *vtab, const char *name, * AstFrame *frame ) * Class Membership: * NormMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new NormMap object. It allocates memory (if necessary) to accommodate * the NormMap plus any additional data associated with the derived class. * It then initialises a NormMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a NormMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the NormMap is to be initialised. * This must be of sufficient size to accommodate the NormMap data * (sizeof(NormMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the NormMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the NormMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the NormMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new NormMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * frame * The Frame to use to do the normalisations. * Returned Value: * A pointer to the new NormMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstNormMap *new; /* Pointer to new NormMap */ int ncoord; /* Number of input and output coords */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitNormMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Get the number of axes in the Frame. */ ncoord = astGetNaxes( frame ); /* Initialise a Mapping structure (the parent class) as the first component within the NormMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstNormMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, ncoord, ncoord, 1, 1 ); if ( astOK ) { /* Initialise the NormMap data. */ /* ---------------------------- */ /* Store a pointer to the Frame. */ new->frame = astClone( frame ); /* If an error occurred, clean up by deleting the new NormMap. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new NormMap. */ return new; } AstNormMap *astLoadNormMap_( void *mem, size_t size, AstNormMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadNormMap * Purpose: * Load a NormMap. * Type: * Protected function. * Synopsis: * #include "normmap.h" * AstNormMap *astLoadNormMap( void *mem, size_t size, * AstNormMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * NormMap loader. * Description: * This function is provided to load a new NormMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * NormMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a NormMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the NormMap is to be * loaded. This must be of sufficient size to accommodate the * NormMap data (sizeof(NormMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the NormMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the NormMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstNormMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new NormMap. If this is NULL, a pointer * to the (static) virtual function table for the NormMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "NormMap" is used instead. * Returned Value: * A pointer to the new NormMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstNormMap *new; /* Pointer to the new NormMap */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this NormMap. In this case the NormMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstNormMap ); vtab = &class_vtab; name = "NormMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitNormMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built NormMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "NormMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Frame. */ /* ------ */ new->frame = astReadObject( channel, "frame", NULL ); /* If an error occurred, clean up by deleting the new NormMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new NormMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/wcsmath.h0000644000175000017500000000413612262533650012765 0ustar olesoles/*============================================================================= * * WCSLIB - an implementation of the FITS WCS proposal. * Copyright (C) 1995-2002, Mark Calabretta * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library 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 Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street,Fifth Floor, Boston, MA 02110-1301, USA * * Correspondence concerning WCSLIB may be directed to: * Internet email: mcalabre@atnf.csiro.au * Postal address: Dr. Mark Calabretta, * Australia Telescope National Facility, * P.O. Box 76, * Epping, NSW, 2121, * AUSTRALIA * * Author: Mark Calabretta, Australia Telescope National Facility * $Id$ *============================================================================= * * This version of wcstrig.h is based on the version in wcslib-2.9, but has * been modified in the following ways by the Starlink project (e-mail: * ussc@star.rl.ac.uk): * - Changed the name of the WCSLIB_MATH macro to WCSLIB_MATH_INCLUDED *===========================================================================*/ #ifndef WCSLIB_MATH_INCLUDED #define WCSLIB_MATH_INCLUDED #ifdef PI #undef PI #endif #ifdef D2R #undef D2R #endif #ifdef R2D #undef R2D #endif #ifdef SQRT2 #undef SQRT2 #endif #ifdef SQRT2INV #undef SQRT2INV #endif #define PI 3.141592653589793238462643 #define D2R PI/180.0 #define R2D 180.0/PI #define SQRT2 1.4142135623730950488 #define SQRT2INV 1.0/SQRT2 #endif /* WCSLIB_MATH_INCLUDED */ ./ast-7.3.3/err_null.c0000644000175000017500000000631212262533650013132 0ustar olesoles/* * Name: * err_null.c * Purpose: * Implement the default "err" module. * Description: * This file implements the default "err" module for the AST * library. It is used to deliver error messages if no alternative * error delivery mechanism is provided. * * To provide an alternative mechanism, re-implement this module * and link your program against the resulting library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (STARLINK) * {enter_new_authors_here} * History: * 6-NOV-1996 (DSB): * Original version. * {enter_changes_here} */ /* Module Macros. */ /* ============== */ /* Define the astCLASS macro (even although this is not a class implementation). This indicates to header files that they should make "protected" symbols available. */ #define astCLASS /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "err.h" /* Interface to this module */ #include "error.h" /* Interface to the error module */ /* C header files. */ /* --------------- */ #include /* Function implementations. */ /* ========================= */ void astPutErr_( int status_value, const char *message ) { /* *+ * Name: * astPutErr * Purpose: * Deliver an error message. * Type: * Protected function. * Synopsis: * #include "err.h" * void astPutErr( int status_value, const char *message ) * Description: * This function delivers an error message and (optionally) an * accompanying status value to the user. It may be re-implemented * in order to deliver error messages in different ways, according * to the environment in which the AST library is being used. * Parameters: * status_value * The error status value. * message * A pointer to a null-terminated character string containing * the error message to be delivered. This should not contain * newline characters. * Notes: * - This function is documented as "protected" but, in fact, is * publicly accessible so that it may be re-implemented as * required. *- */ /* This is the default implementation. Simply write the message to standard error with a newline appended. Ignore the status value. */ int *status = astGetStatusPtr; (void) fprintf( stderr, "%s%s\n", astOK ? "!! " : "! ", message ); } ./ast-7.3.3/install-sh0000755000175000017500000002202112245363456013151 0ustar olesoles#!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: ./ast-7.3.3/fplot3d.c0000644000175000017500000000631312262533650012664 0ustar olesoles/* *+ * Name: * fplot3d.c * Purpose: * Define a FORTRAN 77 interface to the AST Plot3D class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Plot3D class. * Routines Defined: * AST_ISAPLOT3D * AST_PLOT3D * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 6-JUN-2007 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "plot3d.h" /* C interface to the Plot3D class */ F77_LOGICAL_FUNCTION(ast_isaplot3d)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAPLOT3D", NULL, 0 ); astWatchSTATUS( RESULT = astIsAPlot3D( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_plot3d)( INTEGER(FRAME), REAL_ARRAY(GRAPHBOX), DOUBLE_ARRAY(BASEBOX), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_REAL_ARRAY(GRAPHBOX) GENPTR_DOUBLE_ARRAY(BASEBOX) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_PLOT3D", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astPlot3D( astI2P( *FRAME ), GRAPHBOX, BASEBOX, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/winmap.c0000644000175000017500000045454012262533650012615 0ustar olesoles/* *class++ * Name: * WinMap * Purpose: * Map one window on to another by scaling and shifting each axis. * Constructor Function: c astWinMap f AST_WINMAP * Description: * A Winmap is a linear Mapping which transforms a rectangular * window in one coordinate system into a similar window in another * coordinate system by scaling and shifting each axis (the window * edges being parallel to the coordinate axes). * * A WinMap is specified by giving the coordinates of two opposite * corners (A and B) of the window in both the input and output * coordinate systems. * Inheritance: * The WinMap class inherits from the Mapping class. * Attributes: * The WinMap class does not define any new attributes beyond those * which are applicable to all Mappings. * Functions: c The WinMap class does not define any new functions beyond those f The WinMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * RFWS: R.F. Warren-Smith (Starlink) * History: * 23-OCT-1996 (DSB): * Original version. * 4-MAR-1997 (RFWS): * Tidied public prologues. * 11-MAR-1997 (DSB): * Added MapMerge method and associated bits. * 30-JUN-1997 (DSB): * Bug fixed which caused the MapMerge method to generate a * segmentation violation. * 24-MAR-1998 (RFWS): * Improved output format from Dump. * 9-APR-1998 (DSB): * MapMerge modified to allow merging of WinMaps with ZoomMaps and * and UnitMaps in parallel. * 4-SEP-1998 (DSB): * Improved MapMerge so that WinMaps can change places with a wider * range of PermMaps, allowing them to approach closer to a Mapping * with which they can merge. * 22-FEB-1999 (DSB): * Corrected logic of MapMerge method to avoid infinite looping. * 5-MAY-1999 (DSB): * More corrections to MapMerge: Cleared up errors in the use of the * supplied invert flags, and corrected logic for deciding which * neighbouring Mapping to swap with. * 16-JUL-1999 (DSB): * Fixed memory leaks in WinMat and MapMerge. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitWinMapVtab * method. * 8-SEP-2003 (DSB): * Allow WinMaps to swap with WcsMaps if possible. * 10-NOV-2003 (DSB): * Modified functions which swap a WinMap with another Mapping * (e.g. WinPerm, etc), to simplify the returned Mappings. * 23-APR-2004 (DSB): * Changes to simplification algorithm. * 1-SEP-2004 (DSB): * Ensure do1 and do2 are initialised before use in MapMerge. * 7-SEP-2005 (DSB): * Take account of the Invert flag when using the soom factor from * a ZoomMap. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 15-MAR-2006 (DSB): * Override astEqual. * 23-AUG-2006 (DSB): * Correct initialisation of "result" in the Equal function. * 19-JAN-2007 (DSB): * Fix memory leak. * 3-MAY-2013 (DSB): * Improve simplification by adding check for inverse pairs of * WinMaps in function WinWin. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS WinMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory management facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "matrixmap.h" /* Linear mappings */ #include "unitmap.h" /* Unit mappings */ #include "zoommap.h" /* Zoom mappings */ #include "permmap.h" /* Axis permutations */ #include "cmpmap.h" /* Compound mappings */ #include "wcsmap.h" /* Celestial projections */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "winmap.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(WinMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(WinMap,Class_Init) #define class_vtab astGLOBAL(WinMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstWinMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstWinMap *astWinMapId_( int, const double [], const double [], const double [], const double [], const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstWinMap *WinUnit( AstWinMap *, AstUnitMap *, int, int, int * ); static AstWinMap *WinWin( AstMapping *, AstMapping *, int, int, int, int * ); static AstWinMap *WinZoom( AstWinMap *, AstZoomMap *, int, int, int, int, int * ); static int GetObjSize( AstObject *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static double Rate( AstMapping *, double *, int, int, int * ); static int CanSwap( AstMapping *, AstMapping *, int, int, int *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetIsLinear( AstMapping *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int WinTerms( AstWinMap *, double **, double **, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void PermGet( AstPermMap *, int **, int **, double **, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void WinMat( AstMapping **, int *, int, int * ); static void WinPerm( AstMapping **, int *, int, int * ); static void WinWcs( AstMapping **, int *, int, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); /* Function Macros */ /* =============== */ /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Member functions. */ /* ================= */ static int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int *simpler, int *status ){ /* * Name: * CanSwap * Purpose: * Determine if two Mappings could be swapped. * Type: * Private function. * Synopsis: * #include "winmap.h" * int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2, * int *simpler, int *status ) * Class Membership: * WinMap member function * Description: * This function returns a flag indicating if the pair of supplied * Mappings could be replaced by an equivalent pair of Mappings from the * same classes as the supplied pair, but in reversed order. Each pair * of Mappings is considered to be compunded in series. The supplied * Mapings are not changed in any way. * Parameters: * map1 * The Mapping to be applied first. * map2 * The Mapping to be applied second. * inv1 * The invert flag to use with map1. A value of zero causes the forward * mapping to be used, and a non-zero value causes the inverse * mapping to be used. * inv2 * The invert flag to use with map2. * simpler * Addresss of a location at which to return a flag indicating if * the swapped Mappings would be intrinsically simpler than the * original Mappings. * status * Pointer to the inherited status variable. * Returned Value: * 1 if the Mappings could be swapped, 0 otherwise. * Notes: * - One of the supplied pair of Mappings must be a WinMap. * - A value of 0 is returned if the two Mappings could be merged into * a single Mapping. * - A value of 0 is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstMapping *nowin; /* Pointer to non-WinMap Mapping */ AstWinMap *win; /* Pointer to the WinMap */ const char *class1; /* Pointer to map1 class string */ const char *class2; /* Pointer to map2 class string */ const char *nowin_class; /* Pointer to non-WinMap class string */ double *consts; /* Pointer to constants array */ int *inperm; /* Pointer to input axis permutation array */ int *outperm; /* Pointer to output axis permutation array */ int axlat; /* Latitude axis in WcsMap */ int axlon; /* Longitude axis in WcsMap */ int i; /* Loop count */ int invert[ 2 ]; /* Original invert flags */ int nin; /* No. of input coordinates for the PermMap */ int nout; /* No. of output coordinates for the PermMap */ int ret; /* Returned flag */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise */ ret = 0; *simpler = 0; /* Temporarily set the Invert attributes of both Mappings to the supplied values. */ invert[ 0 ] = astGetInvert( map1 ); astSetInvert( map1, inv1 ); invert[ 1 ] = astGetInvert( map2 ); astSetInvert( map2, inv2 ); /* Get the classes of the two mappings. */ class1 = astGetClass( map1 ); class2 = astGetClass( map2 ); if( astOK ){ /* Get a pointer to the non-WinMap Mapping. */ if( !strcmp( class1, "WinMap" ) ){ nowin = map2; nowin_class = class2; win = (AstWinMap *) map1; } else { nowin = map1; nowin_class = class1; win = (AstWinMap *) map2; } /* If it is a MatrixMap, the Mappings can be swapped. */ if( !strcmp( nowin_class, "MatrixMap" ) ){ ret = 1; /* If it is a WcsMap, the Mappings can be swapped if the WinMap is equivalent to a unit transformation on the celestial axes of the WcsMap. */ } else if( !strcmp( nowin_class, "WcsMap" ) ){ /* Get the indices of the celestial coordinates inthe WcsMap. */ axlat = astGetWcsAxis( (AstWcsMap *) nowin, 1 ); axlon = astGetWcsAxis( (AstWcsMap *) nowin, 0 ); /* Check the shift and scale for these axes. */ ret = ( win->a[ axlon ] == 0.0 && win->b[ axlon ] == 1.0 && win->a[ axlat ] == 0.0 && win->b[ axlat ] == 1.0 ); /* If it is a PermMap, the Mappings can be swapped so long as all links between input and output axes in the PermMap are bi-directional. This does not preclude the existence of unconnected axes, which do not have links (bi-directional or otherwise). */ } else if( !strcmp( nowin_class, "PermMap" ) ){ /* Get the number of input and output coordinates. */ nin = astGetNin( nowin ); nout = astGetNout( nowin ); /* We need to know the axis permutation arrays and constants array for the PermMap. */ PermGet( (AstPermMap *) nowin, &outperm, &inperm, &consts, status ); if( astOK ) { /* Indicate we can swap with the PermMap. */ ret = 1; /* Check each output axis. If any links between axes are found which are not bi-directional, indicate that we cannot swap with the PermMap. */ for( i = 0; i < nout; i++ ){ if( outperm[ i ] >= 0 && outperm[ i ] < nin ) { if( inperm[ outperm[ i ] ] != i ) { ret = 0; break; } } } /* Check each input axis. If any links between axes are found which are not bi-directional, indicate that we cannot swap with the PermMap. */ for( i = 0; i < nin; i++ ){ if( inperm[ i ] >= 0 && inperm[ i ] < nout ) { if( outperm[ inperm[ i ] ] != i ) { ret = 0; break; } } } /* If we can swap with the PermMap, the swapped Mappings may be intrinsically simpler than the original mappings. */ if( ret ) { /* If the PermMap precedes the WinMap, this will be the case if the PermMap has more outputs than inputs. If the WinMap precedes the PermMap, this will be the case if the PermMap has more inputs than outputs. */ *simpler = ( nowin == map1 ) ? nout > nin : nin > nout; } /* Free the axis permutation and constants arrays. */ outperm = (int *) astFree( (void *) outperm ); inperm = (int *) astFree( (void *) inperm ); consts = (double *) astFree( (void *) consts ); } } } /* Re-instate the original settings of the Invert attributes for the supplied MatrixMaps. */ astSetInvert( map1, invert[ 0 ] ); astSetInvert( map2, invert[ 1 ] ); /* Return the answer. */ return astOK ? ret : 0; } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * WinMap member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * WinMap, so that the default value will subsequently be used. * Parameters: * this * Pointer to the WinMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstWinMap *this; /* Pointer to the WinMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) this_object; /* At the moment the WinMap class has no attributes, so pass it on to the parent method for further interpretation. */ (*parent_clearattrib)( this_object, attrib, status ); } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two WinMaps are equivalent. * Type: * Private function. * Synopsis: * #include "winmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * WinMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two WinMaps are equivalent. * Parameters: * this * Pointer to the first Object (a WinMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the WinMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *that; AstWinMap *this; double *a_that; double *a_this; double *b_that; double *b_this; int i; int nin; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two WinMap structures. */ this = (AstWinMap *) this_object; that = (AstWinMap *) that_object; /* Check the second object is a WinMap. We know the first is a WinMap since we have arrived at this implementation of the virtual function. */ if( astIsAWinMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); if( astGetNin( that ) == nin ) { /* Assume the WinMaps are equivalent. */ result = 1; /* Compare the shift and scale terms from both WinMaps ignoring the setting of the Invert flag for the moment. */ for( i = 0; i < nin; i++ ) { if( !EQUAL( this->a[ i ], that->a[ i ] ) || !EQUAL( this->b[ i ], that->b[ i ] ) ) { result = 0; break; } } /* If the scale and shifts are equal, check the Invert flags are equal. */ if( result ) { result= ( astGetInvert( this ) == astGetInvert( that ) ); /* If the scale and shifts differ, there is still a chance that the WinMaps may be equivalent if their Invert flags differ. */ } else if( astGetInvert( this ) != astGetInvert( that ) ) { /* Create copies of the scale and shift terms from the two WinMaps, taking into account the setting of the Invert attribute. Finding the inverted terms involves arithmetic which introduces rounding errors, so this test is not as reliable as the above direct comparison of terms. */ astWinTerms( this, &a_this, &b_this ); astWinTerms( that, &a_that, &b_that ); result = 1; for( i = 0; i < nin; i++ ) { if( !EQUAL( a_this[ i ], a_that[ i ] ) || !EQUAL( b_this[ i ], b_that[ i ] ) ) { result = 0; break; } } /* Free resources */ a_this = astFree( a_this ); a_that = astFree( a_that ); b_this = astFree( b_this ); b_that = astFree( b_that ); } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetIsLinear( AstMapping *this_mapping, int *status ){ /* * Name: * GetIsLinear * Purpose: * Return the value of the IsLinear attribute for a WinMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * void GetIsLinear( AstMapping *this, int *status ) * Class Membership: * WinMap member function (over-rides the protected astGetIsLinear * method inherited from the Mapping class). * Description: * This function returns the value of the IsLinear attribute for a * Frame, which is always one. * Parameters: * this * Pointer to the WinMap. * status * Pointer to the inherited status variable. */ return 1; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "winmap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * WinMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied WinMap, * in bytes. * Parameters: * this * Pointer to the WinMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *this; /* Pointer to WinMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the WinMap structure. */ this = (AstWinMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astTSizeOf( this->a ); result += astTSizeOf( this->b ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * WinMap member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a WinMap, formatted as a character string. * Parameters: * this * Pointer to the WinMap. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the WinMap, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the WinMap. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Constants: */ #define BUFF_LEN 50 /* Max. characters in result buffer */ /* Local Variables: */ AstWinMap *this; /* Pointer to the WinMap structure */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) this_object; /* At the moment the WinMap class has no attributes, so pass it on to the parent method for further interpretation. */ result = (*parent_getattrib)( this_object, attrib, status ); /* Return the result. */ return result; /* Undefine macros local to this function. */ #undef BUFF_LEN } void astInitWinMapVtab_( AstWinMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitWinMapVtab * Purpose: * Initialise a virtual function table for a WinMap. * Type: * Protected function. * Synopsis: * #include "winmap.h" * void astInitWinMapVtab( AstWinMapVtab *vtab, const char *name ) * Class Membership: * WinMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the WinMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAWinMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->WinTerms = WinTerms; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; mapping->MapSplit = MapSplit; mapping->Rate = Rate; mapping->GetIsLinear = GetIsLinear; /* Declare the class dump, copy and delete functions.*/ astSetDump( vtab, Dump, "WinMap", "Map one window on to another" ); astSetCopy( (AstObjectVtab *) vtab, Copy ); astSetDelete( (AstObjectVtab *) vtab, Delete ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a WinMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * WinMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated WinMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated WinMap with a Mapping which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated WinMap which is to be merged with * its neighbours. This should be a cloned copy of the WinMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * WinMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated WinMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstCmpMap *cm; /* Pointer to neighbouring CmpMap */ AstMapping **maplt; /* New mappings list pointer */ AstMapping *map2; /* Pointer to replacement Mapping */ AstMapping *mc[2]; /* Copies of supplied Mappings to swap */ AstMapping *nc[2]; /* Copies of neighbouring Mappings to merge */ AstMapping *smc0; /* Simplified Mapping */ AstMapping *smc1; /* Simplified Mapping */ AstMapping *simp1; /* Simplified Mapping */ AstMapping *simp2; /* Simplified Mapping */ AstMatrixMap *mtr; /* Pointer to replacement MatrixMap */ AstWinMap *newwm2; /* Second component WinMap */ AstWinMap *newwm; /* Pointer to replacement WinMap */ AstWinMap *oldwm; /* Pointer to supplied WinMap */ const char *class1; /* Pointer to first Mapping class string */ const char *class2; /* Pointer to second Mapping class string */ const char *nclass; /* Pointer to neighbouring Mapping class */ double *a; /* Pointer to zero terms */ double *b; /* Pointer to scale terms */ int *invlt; /* New invert flags list pointer */ int cmlow; /* Is lower neighbour a CmpMap? */ int diag; /* Is WinMap equivalent to a diagonal matrix? */ int do1; /* Would a backward swap make a simplification? */ int do2; /* Would a forward swap make a simplification? */ int i1; /* Index of first WinMap to merge */ int i2; /* Index of last WinMap to merge */ int i; /* Loop counter */ int ic[2]; /* Copies of supplied invert flags to swap */ int inc[4]; /* Copies of supplied invert flags to merge */ int invert; /* Should the inverted Mapping be used? */ int neighbour; /* Index of Mapping with which to swap */ int nin2; /* No. of inputs for second component WinMap */ int nin; /* Number of coordinates for WinMap */ int nmapt; /* No. of Mappings in list */ int nstep1; /* No. of Mappings backwards to next mergable Mapping */ int nstep2; /* No. of Mappings forward to next mergable Mapping */ int old_winv; /* original Invert value for supplied WinMap */ int result; /* Result value to return */ int ser; /* Are Mappings applied in series? */ int simpler; /* Is the resulting Mapping simpler than original? */ int swap; /* Is there an advantage in swapping mappings? */ int swaphi; /* Can WinMap be swapped with higher neighbour? */ int swaplo; /* Can WinMap be swapped with lower neighbour? */ /* Initialise. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ i1 = 0; i2 = 0; neighbour = 0; /* Get the number of axes for the WinMap. */ nin = astGetNin( ( *map_list )[ where ] ); /* Get a pointer to the WinMap. */ oldwm = (AstWinMap *) this; /* First of all, see if the WinMap can be replaced by a simpler Mapping, without reference to the neighbouring Mappings in the list. */ /* ======================================================================*/ /* If the shift terms in the WinMap are all zero, the WinMap can be replaced by a diagonal MatrixMap (which is faster to compute). Check the shift terms. */ diag = 1; newwm = (AstWinMap *) ( *map_list )[ where ]; for( i = 0; i < nin; i++ ){ if( !EQUAL( ( newwm->a )[ i ], 0.0 ) ){ diag = 0; break; } } /* If all the shift terms are zero... */ if( diag ){ /* Temporarily set the Invert attribute of the WinMap to the supplied value. */ old_winv = astGetInvert( newwm ); astSetInvert( newwm, ( *invert_list )[ where ] ); /* Get a copy of the scale terms from the WinMap. */ astWinTerms( newwm, NULL, &b ); /* Create a diagonal MatrixMap holding the scale terms. */ mtr = astMatrixMap( nin, nin, 1, b, "", status ); /* Restore the Invert attribute of the supplied WinMap. */ astSetInvert( newwm, old_winv ); /* Free the memory used to hold the scale terms. */ b = (double *) astFree( (void *) b ); /* Annul the WinMap pointer in the list and replace it with the MatrixMap pointer, and indicate that the forward transformation of the returned MatrixMap should be used. */ (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) mtr; ( *invert_list )[ where ] = 0; /* Return the index of the first modified element. */ result = where; /* If the WinMap itself could not be simplified, see if it can be merged with the Mappings on either side of it in the list. */ } else { /* Store the classes of the neighbouring Mappings in the list. */ class1 = ( where > 0 ) ? astGetClass( ( *map_list )[ where - 1 ] ) : NULL; class2 = ( where < *nmap - 1 ) ? astGetClass( ( *map_list )[ where + 1 ] ) : NULL; /* In series. */ /* ========== */ if ( series ) { /* We first look to see if the WinMap can be merged with one of its neighbours, resulting in a reduction of one in the number of Mappings in the list. WinMaps can only merge directly with another WinMap, a ZoomMap, or a UnitMap. */ if( class1 && ( !strcmp( class1, "WinMap" ) || !strcmp( class1, "ZoomMap" ) || !strcmp( class1, "UnitMap" ) ) ){ nclass = class1; i1 = where - 1; i2 = where; } else if( class2 && ( !strcmp( class2, "WinMap" ) || !strcmp( class2, "ZoomMap" ) || !strcmp( class2, "UnitMap" ) ) ){ nclass = class2; i1 = where; i2 = where + 1; } else { nclass = NULL; } /* If the WinMap can merge with one of its neighbours, create the merged Mapping. */ if( nclass ){ if( !strcmp( nclass, "WinMap" ) ){ newwm = WinWin( ( *map_list )[ i1 ], ( *map_list )[ i2 ], ( *invert_list )[ i1 ], ( *invert_list )[ i2 ], 1, status ); invert = 0; } else if( !strcmp( nclass, "ZoomMap" ) ){ if( i1 == where ){ newwm = WinZoom( (AstWinMap *)( *map_list )[ i1 ], (AstZoomMap *)( *map_list )[ i2 ], ( *invert_list )[ i1 ], ( *invert_list )[ i2 ], 1, 1, status ); } else { newwm = WinZoom( (AstWinMap *)( *map_list )[ i2 ], (AstZoomMap *)( *map_list )[ i1 ], ( *invert_list )[ i2 ], ( *invert_list )[ i1 ], 0, 1, status ); } invert = 0; } else { newwm = astClone( ( *map_list )[ where ] ); invert = ( *invert_list )[ where ]; } /* If succesfull... */ if( astOK ){ /* Annul the first of the two Mappings, and replace it with the merged WinMap. Also set the invert flag. */ (void) astAnnul( ( *map_list )[ i1 ] ); ( *map_list )[ i1 ] = (AstMapping *) newwm; ( *invert_list )[ i1 ] = invert; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ i2 ] ); for ( i = i2 + 1; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = i1; } /* If one of the neighbours is a (parallel) CmpMap, we convert the WinMap into an equivalent parallel CmpMap, and then merge this parallel CmpMap with the neighbouring parallel CmpMap to create a parallel CmpMap containing two series CmpMaps. */ } else if( ( class1 && !strcmp( "CmpMap", class1 ) ) || ( class2 && !strcmp( "CmpMap", class2 ) ) ) { /* Identify the WinMap and the CmpMap. */ if( class1 && !strcmp( "CmpMap", class1 ) ) { i1 = where - 1; i2 = where; cm = (AstCmpMap *) ( *map_list )[ where - 1 ]; cmlow = 1; } else { i1 = where; i2 = where + 1; cm = (AstCmpMap *) ( *map_list )[ where + 1 ]; cmlow = 0; } /* Temporarily set the required Invert attributes in the two Mappings. */ inc[ 0 ] = astGetInvert( ( *map_list )[ i1 ] ); astSetInvert( ( *map_list )[ i1 ], ( *invert_list )[ i1 ] ); inc[ 1 ] = astGetInvert( ( *map_list )[ i2 ] ); astSetInvert( ( *map_list )[ i2 ], ( *invert_list )[ i2 ] ); /* Now get pointers to the scale and zero terms of the nominated WinMap (these describe the forward transformation, taking into account the setting of the Invert flag). */ (void) astWinTerms( oldwm , &a, &b ); /* Get pointers to the two components of the parallel CmpMap. */ astDecompose( cm, mc, mc + 1, &ser, ic, ic + 1 ); /* Check component Mappings are combined in parallel. */ map2 = NULL; if( astOK && !ser ) { /* Temporarily set the required Invert attributes in the two component Mappings to the indicated values. */ inc[ 2 ] = astGetInvert( mc[ 0 ] ); astSetInvert( mc[ 0 ], ic[ 0 ] ); inc[ 3 ] = astGetInvert( mc[ 1 ] ); astSetInvert( mc[ 1 ], ic[ 1 ] ); /* Create the first of two corresponding WinMaps, initially with undefined corners. These could be combined into a parallel CmpMap which would be equivalent to the nominated WinMap. The number of inputs for each WinMap is equal to either the number of outputs or inputs of the corresponding component of the CmpMap, depending on whether the CmpMap is upper or lower neighbour. */ nin = cmlow ? astGetNout( mc[ 0 ] ):astGetNin( mc[ 0 ] ); newwm = astWinMap( nin, NULL, NULL, NULL, NULL, "", status ); if( astOK ) { /* Store the first "nin" scale and zero terms from the nominated WinMap in the new WinMap. */ for( i = 0; i < nin; i++ ) { (newwm->a)[ i ] = a[ i ]; (newwm->b)[ i ] = b[ i ]; } } /* Now create the second WinMap in the same way, which transforms the remaining outputs of the CmpMap. */ nin2 = cmlow ? astGetNout( mc[ 1 ] ):astGetNin( mc[ 1 ] ); newwm2 = astWinMap( nin2, NULL, NULL, NULL, NULL, "", status ); if( astOK ) { /* Store the remaining scale and zero terms from the nominated WinMap in the new WinMap. */ for( i = 0; i < nin2; i++ ) { (newwm2->a)[ i ] = a[ i + nin ]; (newwm2->b)[ i ] = b[ i + nin ]; } } /* Combine the two corresponding lower component Mappings into a series CmpMap, and likewise combine the two corresponding upper component Mappings into a series CmpMap. */ if( cmlow ) { nc[ 0 ] = (AstMapping *) astCmpMap( mc[ 0 ], newwm, 1, "", status ); nc[ 1 ] = (AstMapping *) astCmpMap( mc[ 1 ], newwm2, 1, "", status ); } else { nc[ 0 ] = (AstMapping *) astCmpMap( newwm, mc[ 0 ], 1, "", status ); nc[ 1 ] = (AstMapping *) astCmpMap( newwm2, mc[ 1 ], 1, "", status ); } newwm = astAnnul( newwm ); newwm2 = astAnnul( newwm2 ); /* Attempt to simplify each of the two new series CmpMaps. If neither of them simplify then there is no point in doing the current merger. In fact it would be dangerous to do so since we may end up in an infinite loop where the resulting parallel CmpMap gets converted back into the existing series CmpMap by the CmpMap MapMerge method, and then back again by this method, etc. */ simp1 = astSimplify( nc[ 0 ] ); simp2 = astSimplify( nc[ 1 ] ); /* Test if either could be simplified by checking if its pointer value has changed. */ simpler = ( simp1 != nc[ 0 ] ) || ( simp2 != nc[ 1 ] ); /* If either CmpMap was simplified, then combine the two series CmpMap into a single parallel CmpMap. */ if( simpler ) { map2 = (AstMapping *) astCmpMap( simp1, simp2, 0, "", status ); } /* Re-instate the original Invert attributes in the two component Mappings. */ astSetInvert( mc[ 0 ], inc[ 2 ] ); astSetInvert( mc[ 1 ], inc[ 3 ] ); /* Free resources. */ simp1 = astAnnul( simp1 ); simp2 = astAnnul( simp2 ); nc[ 0 ] = astAnnul( nc[ 0 ] ); nc[ 1 ] = astAnnul( nc[ 1 ] ); } /* Free resources. */ mc[ 0 ] = astAnnul( mc[ 0 ] ); mc[ 1 ] = astAnnul( mc[ 1 ] ); a = astFree( a ); b = astFree( b ); /* Re-instate the original Invert attributes. */ astSetInvert( ( *map_list )[ i1 ], inc[ 0 ] ); astSetInvert( ( *map_list )[ i2 ], inc[ 1 ] ); /* If the above produced a new Mapping, annul the supplied pointers for the two merged Mappings, store the pointer for the new merged Mapping, and shuffle the remaining Mappings down to fill the space left. Nullify the end slot which is no longer used, reduce the number of Mappings in the list by 1, and return the index of the first modified Mapping. */ if( map2 ) { (void) astAnnul( ( *map_list )[ i1 ] ); (void) astAnnul( ( *map_list )[ i2 ] ); ( *map_list )[ i1 ] = map2; ( *invert_list )[ i1 ] = 0; for( i = i2 + 1; i < *nmap; i++ ){ ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } ( *map_list )[ *nmap - 1 ] = NULL; (*nmap)--; result = i1; } /* If the WinMap could not merge directly with either of its neighbours, we consider whether it would be worthwhile to swap the WinMap with either of its neighbours. This can only be done for certain classes of Mapping (MatrixMap & some PermMaps & WcsMaps), and will usually require both Mappings to be modified (unless they are commutative). The advantage of swapping the order of the Mappings is that it may result in the WinMap being adjacent to a Mapping with which it can merge directly on the next invocation of this function, thus reducing the number of Mappings in the list. */ } else { /* Set a flag if we could swap the WinMap with its higher neighbour. "do2" is returned if swapping the Mappings would simplify either of the Mappings. */ if( where + 1 < *nmap ){ swaphi = CanSwap( ( *map_list )[ where ], ( *map_list )[ where + 1 ], ( *invert_list )[ where ], ( *invert_list )[ where + 1 ], &do2, status ); } else { swaphi = 0; do2 = 0; } /* If so, step through each of the Mappings which follow the WinMap, looking for a Mapping with which the WinMap could merge directly. Stop when such a Mapping is found, or if a Mapping is found with which the WinMap could definitely not swap. Note the number of Mappings which separate the WinMap from the Mapping with which it could merge (if any). */ nstep2 = -1; if( swaphi ){ for( i2 = where + 1; i2 < *nmap; i2++ ){ /* See if we can merge with this Mapping. If so, note the number of steps between the two Mappings and leave the loop. */ nclass = astGetClass( ( *map_list )[ i2 ] ); if( !strcmp( nclass, "WinMap" ) || !strcmp( nclass, "ZoomMap" ) || !strcmp( nclass, "UnitMap" ) ) { nstep2 = i2 - where - 1; break; } /* If there is no chance that we can swap with this Mapping, leave the loop with -1 for the number of steps to indicate that no merging is possible. WinMaps can swap with MatrixMaps and some PermMaps. */ if( strcmp( nclass, "MatrixMap" ) && strcmp( nclass, "WcsMap" ) && strcmp( nclass, "PermMap" ) ) { break; } } } /* Do the same working forward from the WinMap towards the start of the map list. */ if( where > 0 ){ swaplo = CanSwap( ( *map_list )[ where - 1 ], ( *map_list )[ where ], ( *invert_list )[ where - 1 ], ( *invert_list )[ where ], &do1, status ); } else { swaplo = 0; do1 = 0; } nstep1 = -1; if( swaplo ){ for( i1 = where - 1; i1 >= 0; i1-- ){ nclass = astGetClass( ( *map_list )[ i1 ] ); if( !strcmp( nclass, "WinMap" ) || !strcmp( nclass, "ZoomMap" ) || !strcmp( nclass, "UnitMap" ) ) { nstep1 = where - 1 - i1; break; } if( strcmp( nclass, "MatrixMap" ) && strcmp( nclass, "WcsMap" ) && strcmp( nclass, "PermMap" ) ) { break; } } } /* Choose which neighbour to swap with so that the WinMap moves towards the nearest Mapping with which it can merge. */ if( do1 || ( nstep1 != -1 && ( nstep2 == -1 || nstep2 > nstep1 ) ) ){ nclass = class1; i1 = where - 1; i2 = where; neighbour = i1; } else if( do2 || nstep2 != -1 ){ nclass = class2; i1 = where; i2 = where + 1; neighbour = i2; } else { nclass = NULL; } /* If there is a target Mapping in the list with which the WinMap could merge, replace the supplied Mappings with swapped Mappings to bring a WinMap closer to the target Mapping. */ if( nclass ){ /* It is possible that the neighbouring Mapping with which we are about to swap could also merge with the target Mapping. When the neighbouring Mapping is reconsidered it may well swap the pair back to put itself nearer the target Mapping. We need to be careful not to end up in an infinite loop in which the pair of neighbouring Mappings are constantly swapped backwards and forwards as each attempts to put itself closer to the target Mapping. To prevent this, we only swap the pair of Mappings if the neighbouring Mapping could not itself merge with the target Mapping. Check to see if this is the case by attempting to merge the neighbouring Mapping with the target Mapping. */ map2 = astClone( (*map_list)[ neighbour ] ); nmapt = *nmap - neighbour; maplt = *map_list + neighbour; invlt = *invert_list + neighbour; result = astMapMerge( map2, 0, series, &nmapt, &maplt, &invlt ); map2 = astAnnul( map2 ); /* If the above call produced a change in the Mapping list, return the remaining number of mappings.. */ if( result != -1 ){ *nmap = nmapt + neighbour; /* Otherwise, if there was no change in the mapping list... */ } else { if( !strcmp( nclass, "MatrixMap" ) ){ WinMat( (*map_list) + i1, (*invert_list) + i1, where - i1, status ); } else if( !strcmp( nclass, "PermMap" ) ){ WinPerm( (*map_list) + i1, (*invert_list) + i1, where - i1, status ); } else if( !strcmp( nclass, "WcsMap" ) ){ WinWcs( (*map_list) + i1, (*invert_list) + i1, where - i1, status ); } /* Store the index of the first modified Mapping. */ result = i1; } /* If there is no Mapping available for merging, it may still be advantageous to swap with a neighbour because the swapped Mapping may be simpler than the original Mappings. For instance, a PermMap may strip axes of the WinMap leaving only a UnitMap. Also, the two neighbours may be able to merge. */ } else if( swaphi || swaplo ) { /* Try swapping with each possible neighbour in turn. */ for( i = 0; i < 2; i++ ) { /* Set up the class and pointers for the mappings to be swapped, first the lower neighbour, then the upper neighbour. */ if( i == 0 && swaplo ){ nclass = class1; i1 = where - 1; i2 = where; } else if( i == 1 && swaphi ){ nclass = class2; i1 = where; i2 = where + 1; } else { nclass = NULL; } /* If we have a Mapping to swap with... */ if( nclass ) { /* Take copies of the Mapping and Invert flag arrays so we do not change the supplied values. */ mc[ 0 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[0] ); mc[ 1 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[1] ); ic[ 0 ] = ( (*invert_list) + i1 )[0]; ic[ 1 ] = ( (*invert_list) + i1 )[1]; /* Swap these Mappings. */ if( !strcmp( nclass, "MatrixMap" ) ){ WinMat( mc, ic, where - i1, status ); } else if( !strcmp( nclass, "PermMap" ) ){ WinPerm( mc, ic, where - i1, status ); } else if( !strcmp( nclass, "WcsMap" ) ){ WinWcs( mc, ic, where - i1, status ); } /* See if the two neighbouring Mappings can merge now that the nominated Mapping is no longer in between them. First get a list of Mapping pointers containing the two Mappings to be merged, and associated invert flags. */ if( i == 0 && where != *nmap - 1 ) { nc[ 0 ] = astClone( mc[ 1 ] ); nc[ 1 ] = astClone( (*map_list)[ where + 1 ] ); inc[ 0 ] = ic[ 1 ]; inc[ 1 ] = (*invert_list)[ where + 1 ]; } else if( i == 1 && where > 0 ) { nc[ 0 ] = astClone( (*map_list)[ where - 1 ] ); nc[ 1 ] = astClone( mc[ 0 ] ); inc[ 0 ] = (*invert_list)[ where - 1 ]; inc[ 1 ] = ic[ 0 ]; } else { nc[ 0 ] = NULL; nc[ 1 ] = NULL; } /* If both neighbours are available, use astMapMerge to see if it is possible to merge the two Mappings. */ swap = 0; if( nc[ 0 ] && nc[ 1 ] ) { nmapt = 2; maplt = nc; invlt = inc; map2 = astClone( nc[ 0 ] ); swap = astMapMerge( map2, 0, series, &nmapt, &maplt, &invlt ); map2 = astAnnul( map2 ); if( swap == -1 ) { map2 = astClone( nc[ 1 ] ); swap = astMapMerge( map2, 1, series, &nmapt, &maplt, &invlt ); map2 = astAnnul( map2 ); } swap = ( nmapt < 2 ) ? 1 : 0; } /* Free resources. */ if( nc[ 0 ] ) nc[ 0 ] = astAnnul( nc[ 0 ] ); if( nc[ 1 ] ) nc[ 1 ] = astAnnul( nc[ 1 ] ); /* If the neighbours could not merge, see if either swapped Mapping can be simplified. */ if( !swap ) { smc0 = astSimplify( mc[0] ); if( smc0 != mc[0] ) { swap = 1; } else { smc1 = astSimplify( mc[1] ); swap = ( smc1 != mc[1] ); smc1 = astAnnul( smc1 ); } smc0 = astAnnul( smc0 ); } /* If there is some point in swapping the Mappings, swap them in the supplied lists. Otherwise annul the swapped Mappings. */ if( swap ) { (*map_list)[ i1 ] = astAnnul( (*map_list)[ i1 ] ); (*map_list)[ i2 ] = astAnnul( (*map_list)[ i2 ] ); (*map_list)[ i1 ] = mc[ 0 ]; (*map_list)[ i2 ] = mc[ 1 ]; (*invert_list)[ i1 ] = ic[ 0 ]; (*invert_list)[ i2 ] = ic[ 1 ]; result = i1; break; } else { mc[ 0 ] = astAnnul( mc[ 0 ] ); mc[ 1 ] = astAnnul( mc[ 1 ] ); } } } } } /* In parallel. */ /* ============ */ /* WinMaps are combined in parallel with neighbouring WinMaps, ZoomMaps and UnitMaps. */ } else { /* We first look to see if the WinMap can be merged with one of its neighbours, resulting in a reduction of one in the number of Mappings in the list. WinMaps can only merge directly with another WinMap, a ZoomMap, or a UnitMap. */ if( class1 && ( !strcmp( class1, "WinMap" ) || !strcmp( class1, "ZoomMap" ) || !strcmp( class1, "UnitMap" ) ) ){ nclass = class1; i1 = where - 1; i2 = where; } else if( class2 && ( !strcmp( class2, "WinMap" ) || !strcmp( class2, "ZoomMap" ) || !strcmp( class2, "UnitMap" ) ) ){ nclass = class2; i1 = where; i2 = where + 1; } else { nclass = NULL; } /* If the WinMap can merge with one of its neighbours, create the merged Mapping. */ if( nclass ){ if( !strcmp( nclass, "WinMap" ) ){ newwm = WinWin( ( *map_list )[ i1 ], ( *map_list )[ i2 ], ( *invert_list )[ i1 ], ( *invert_list )[ i2 ], 0, status ); invert = 0; } else if( !strcmp( nclass, "ZoomMap" ) ){ if( i1 == where ){ newwm = WinZoom( (AstWinMap *)( *map_list )[ i1 ], (AstZoomMap *)( *map_list )[ i2 ], ( *invert_list )[ i1 ], ( *invert_list )[ i2 ], 1, 0, status ); } else { newwm = WinZoom( (AstWinMap *)( *map_list )[ i2 ], (AstZoomMap *)( *map_list )[ i1 ], ( *invert_list )[ i2 ], ( *invert_list )[ i1 ], 0, 0, status ); } invert = 0; } else { if( i1 == where ){ newwm = WinUnit( (AstWinMap *)( *map_list )[ i1 ], (AstUnitMap *)( *map_list )[ i2 ], ( *invert_list )[ i1 ], 1, status ); } else { newwm = WinUnit( (AstWinMap *)( *map_list )[ i2 ], (AstUnitMap *)( *map_list )[ i1 ], ( *invert_list )[ i2 ], 0, status ); } invert = 0; } /* If succesfull... */ if( astOK ){ /* Annul the first of the two Mappings, and replace it with the merged WinMap. Also set the invert flag. */ (void) astAnnul( ( *map_list )[ i1 ] ); ( *map_list )[ i1 ] = (AstMapping *) newwm; ( *invert_list )[ i1 ] = invert; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ i2 ] ); for ( i = i2 + 1; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = i1; } } } } /* Return the result. */ return result; } static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * WinMap method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing WinMap. This is only possible if the specified inputs * correspond to some subset of the WinMap outputs. That is, there * must exist a subset of the WinMap outputs for which each output * depends only on the selected WinMap inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied WinMap, then a NULL Mapping is returned. * Parameters: * this * Pointer to the WinMap to be split (the WinMap is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied WinMap, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied WinMap has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied WinMap. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ AstWinMap *newwm; /* Pointer to returned WinMap */ AstWinMap *this; /* Pointer to WinMap structure */ double *a; /* Pointer to zero terms */ double *b; /* Pointer to scale terms */ int *result; /* Pointer to returned array */ int i; /* Loop count */ int iin; /* Mapping input index */ int mnin; /* No. of Mapping inputs */ int ok; /* Are input indices OK? */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the WinMap structure. */ this = (AstWinMap *) this_map; /* Allocate memory for the returned array and create a WinMap with the required number of axes and undefined corners. */ result = astMalloc( sizeof( int )*(size_t) nin ); newwm = astWinMap( nin, NULL, NULL, NULL, NULL, "", status ); *map = (AstMapping *) newwm; /* Now get pointers to the scale and zero terms of the supplied WinMap (these describe the forward transformation, taking into account the setting of the Invert flag). */ (void) astWinTerms( this , &a, &b ); /* Check pointers can be used safely. */ if( astOK ) { /* Store the required scale and zero terms from the supplied WinMap in the new WinMap. At the same time check that each axis is valid. */ mnin = astGetNin( this ); ok = 1; for( i = 0; i < nin; i++ ) { iin = in[ i ]; if( iin >= 0 && iin < mnin ) { (newwm->a)[ i ] = a[ iin ]; (newwm->b)[ i ] = b[ iin ]; result[ i ] = iin; } else { ok = 0; break; } } /* If the "in" array contained any invalid values, free the returned resources. */ if( !ok ) { result = astFree( result ); *map = astAnnul( *map ); } } /* Free resources. */ a = astFree( a ); b = astFree( b ); /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static void PermGet( AstPermMap *map, int **outperm, int **inperm, double **consts, int *status ){ /* * Name: * PermGet * Purpose: * Get the axis permutation and constants array for a PermMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void PermGet( AstPermMap *map, int **outperm, int **inperm, * double **const, int *status ) * Class Membership: * WinMap member function * Description: * This function returns axis permutation and constants arrays which can * be used to create a PermMap which is equivalent to the supplied PermMap. * Parameters: * map * The PermMap. * outperm * An address at which to return a popinter to an array of ints * holding the output axis permutation array. The array should be * released using astFree when no longer needed. * inperm * An address at which to return a popinter to an array of ints * holding the input axis permutation array. The array should be * released using astFree when no longer needed. * consts * An address at which to return a popinter to an array of doubles * holding the constants array. The array should be released using * astFree when no longer needed. * status * Pointer to the inherited status variable. * Notes: * - NULL pointers are returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstPointSet *pset1; /* PointSet holding input positions for PermMap */ AstPointSet *pset2; /* PointSet holding output positions for PermMap */ double **ptr1; /* Pointer to pset1 data */ double **ptr2; /* Pointer to pset2 data */ double *cnst; /* Pointer to constants array */ double cn; /* Potential new constant value */ double ip; /* Potential output axis index */ double op; /* Potential input axis index */ int *inprm; /* Pointer to input axis permutation array */ int *outprm; /* Pointer to output axis permutation array */ int i; /* Axis count */ int nc; /* Number of constants stored so far */ int nin; /* No. of input coordinates for the PermMap */ int nout; /* No. of output coordinates for the PermMap */ /* Initialise. */ if( outperm ) *outperm = NULL; if( inperm ) *inperm = NULL; if( consts ) *consts = NULL; /* Check the global error status and the supplied pointers. */ if ( !astOK || !outperm || !inperm || !consts ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ nc = 0; /* Get the number of input and output axes for the supplied PermMap. */ nin = astGetNin( map ); nout = astGetNout( map ); /* Allocate the memory for the returned arrays. */ outprm = (int *) astMalloc( sizeof( int )* (size_t) nout ); inprm = (int *) astMalloc( sizeof( int )* (size_t) nin ); cnst = (double *) astMalloc( sizeof( double )* (size_t) ( nout + nin ) ); /* Returned the pointers to these arrays.*/ *outperm = outprm; *inperm = inprm; *consts = cnst; /* Create two PointSets, each holding two points, which can be used for input and output positions with the PermMap. */ pset1 = astPointSet( 2, nin, "", status ); pset2 = astPointSet( 2, nout, "", status ); /* Set up the two input positions to be [0,1,2...] and [-1,-1,-1,...]. The first position is used to enumerate the axes, and the second is used to check for constant axis values. */ ptr1 = astGetPoints( pset1 ); if( astOK ){ for( i = 0; i < nin; i++ ){ ptr1[ i ][ 0 ] = ( double ) i; ptr1[ i ][ 1 ] = -1.0; } } /* Use the PermMap to transform these positions in the forward direction. */ (void) astTransform( map, pset1, 1, pset2 ); /* Look at the mapped positions to determine the output axis permutation array. */ ptr2 = astGetPoints( pset2 ); if( astOK ){ /* No constant axis valeus found yet. */ nc = 0; /* Do each output axis. */ for( i = 0; i < nout; i++ ){ /* If the output axis value is copied from an input axis value, the index of the appropriate input axis will be in the mapped first position. */ op = ptr2[ i ][ 0 ]; /* If the output axis value is assigned a constant value, the result of mapping the two different input axis values will be the same. */ cn = ptr2[ i ][ 1 ]; if( op == cn ) { /* We have found another constant. Store it in the constants array, and store the index of the constant in the output axis permutation array. */ cnst[ nc ] = cn; outprm[ i ] = -( nc + 1 ); nc++; /* If the output axis values are different, then the output axis value must be copied from the input axis value. */ } else { outprm[ i ] = (int) ( op + 0.5 ); } } } /* Now do the same thing to determine the input permutation array. */ if( astOK ){ for( i = 0; i < nout; i++ ){ ptr2[ i ][ 0 ] = ( double ) i; ptr2[ i ][ 1 ] = -1.0; } } (void) astTransform( map, pset2, 0, pset1 ); if( astOK ){ for( i = 0; i < nin; i++ ){ ip = ptr1[ i ][ 0 ]; cn = ptr1[ i ][ 1 ]; if( ip == cn ) { cnst[ nc ] = cn; inprm[ i ] = -( nc + 1 ); nc++; } else { inprm[ i ] = (int) ( ip + 0.5 ); } } } /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* If an error has occurred, attempt to free the returned arrays. */ if( !astOK ) { *outperm = (int *) astFree( (void *) *outperm ); *inperm = (int *) astFree( (void *) *inperm ); *consts = (double *) astFree( (void *) *consts ); } /* Return. */ return; } static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){ /* * Name: * Rate * Purpose: * Calculate the rate of change of a Mapping output. * Type: * Private function. * Synopsis: * #include "winmap.h" * result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ) * Class Membership: * WinMap member function (overrides the astRate method inherited * from the Mapping class ). * Description: * This function returns the rate of change of a specified output of * the supplied Mapping with respect to a specified input, at a * specified input position. * Parameters: * this * Pointer to the Mapping to be applied. * at * The address of an array holding the axis values at the position * at which the rate of change is to be evaluated. The number of * elements in this array should equal the number of inputs to the * Mapping. * ax1 * The index of the Mapping output for which the rate of change is to * be found (output numbering starts at 0 for the first output). * ax2 * The index of the Mapping input which is to be varied in order to * find the rate of change (input numbering starts at 0 for the first * input). * status * Pointer to the inherited status variable. * Returned Value: * The rate of change of Mapping output "ax1" with respect to input * "ax2", evaluated at "at", or AST__BAD if the value cannot be * calculated. */ /* Local Variables: */ AstWinMap *map; double result; /* Check inherited status */ if( !astOK ) return AST__BAD; /* Get a pointer to the WinMap structure. */ map = (AstWinMap *) this; /* If the input and output axes are not equal the result is zero. */ if( ax1 != ax2 ) { result = 0.0; /* Otherwise, return the scale factor for the axis, taking the reciprocal if the WinMap has been inverted. */ } else { result = ( map->b )[ ax1 ]; if( astGetInvert( map ) ) { if( result != 0.0 && result != AST__BAD ) { result = 1.0/result; } else { result = AST__BAD; } } } /* Return the result. */ return result; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void SetAttrib( AstObject *this, const char *setting ) * Class Membership: * WinMap member function (over-rides the astSetAttrib protected * method inherited from the Mapping class). * Description: * This function assigns an attribute value for a WinMap, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the WinMap. * setting * Pointer to a null-terminated string specifying the new attribute * value. */ /* Local Variables: */ AstWinMap *this; /* Pointer to the WinMap structure */ int len; /* Length of setting string */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* The WinMap class currently has no attributes, so pass it on to the parent method for further interpretation. */ (*parent_setattrib)( this_object, setting, status ); } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * WinMap member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a WinMap's attributes. * Parameters: * this * Pointer to the WinMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *this; /* Pointer to the WinMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) this_object; /* The WinMap class currently has no attributes, so pass it on to the parent method for further interpretation. */ result = (*parent_testattrib)( this_object, attrib, status ); /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a WinMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "winmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * WinMap member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a WinMap and a set of points encapsulated in a * PointSet and transforms the points so as to map them into the * required window. * Parameters: * this * Pointer to the WinMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the WinMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstWinMap *map; /* Pointer to WinMap to be applied */ const char *class; /* Object class */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *axin; /* Pointer to next input axis value */ double *axout; /* Pointer to next output axis value */ double *a; /* Pointer to next constant term */ double *b; /* Pointer to next multiplicative term */ double aa; /* Constant term */ double bb; /* Multiplicative term */ int coord; /* Loop counter for coordinates */ int def; /* Is mapping defined? */ int ncoord; /* Number of coordinates per point */ int npoint; /* Number of points */ int point; /* Loop counter for points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ aa = 0.0; bb = 0.0; /* Obtain a pointer to the WinMap. */ map = (AstWinMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ ncoord = astGetNcoord( in ); npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse mapping, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* Report an error if the WinMap does not contain any scales or shifts. */ if( !(map->a && map->b) && astOK ){ class = astGetClass( this ); astError( AST__BADWM, "astTransform(%s): The supplied %s does not " "contain any window information.", status, class, class ); } /* Perform coordinate arithmetic. */ /* ------------------------------ */ if( astOK ){ /* Store pointers to the shift and scale for the next axis. */ a = map->a; b = map->b; /* Apply the mapping to each axis. */ for( coord = 0; coord < ncoord; coord++ ){ /* If either the scale or shift is bad indicate that the mapping is not defined on this axis. */ if( *a == AST__BAD || *b == AST__BAD ){ def = 0; /* Otherwise, get the scale and offset factors for this axis, taking account of whether the mapping is inverted or not. If the mapping is undefined, set the "def" flag to indicate this. */ } else { aa = *a; bb = *b; if( forward ){ def = 1; } else if( bb != 0.0 ){ bb = 1.0/bb; aa = -aa*bb; def = 1; } else { def = 0; } } /* Store pointers to the first inpout and output values on this axis. */ axin = ptr_in[ coord ]; axout = ptr_out[ coord ]; /* If the mapping is defined, apply it to the supplied points. */ if( def ){ for( point = 0; point < npoint; point++ ){ if( *axin != AST__BAD ){ *(axout++) = aa + bb*(*axin); } else { *(axout++) = AST__BAD; } axin++; } /* If the mapping is not defined, store bad values on this axis in the returned points. */ } else { for( point = 0; point < npoint; point++ ) *(axout++) = AST__BAD; } /* Point to the scale and shift for the next axis. */ a++; b++; } } /* Return a pointer to the output PointSet. */ return result; } static void WinMat( AstMapping **maps, int *inverts, int iwm, int *status ){ /* * Name: * WinMat * Purpose: * Swap a WinMap and a MatrixMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void WinMat( AstMapping **maps, int *inverts, int iwm, int *status ) * Class Membership: * WinMap member function * Description: * A list of two Mappings is supplied containing a WinMap and a * MatrixMap. These Mappings are annulled, and replaced with * another pair of Mappings consisting of a WinMap and a MatrixMap * in the opposite order. These Mappings are chosen so that their * combined effect is the same as the original pair of Mappings. * The scale factors in the returned WinMap are always unity (i.e. * the differences in scaling get absorbed into the returned * MatrixMap). * Parameters: * maps * A pointer to an array of two Mapping pointers. * inverts * A pointer to an array of two invert flags. * iwm * The index within "maps" of the WinMap. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstMatrixMap *m1; /* Pointer to Diagonal scale factor MatrixMap */ AstMatrixMap *m2; /* Pointer to returned MatrixMap */ AstMatrixMap *sm2; /* Pointer to simplified returned MatrixMap */ AstMatrixMap *mm; /* Pointer to the supplied MatrixMap */ AstPointSet *pset1; /* Shift terms from supplied WinMap */ AstPointSet *pset2; /* Shift terms for returned WinMap */ AstWinMap *w1; /* Pointer to the returned WinMap */ AstWinMap *sw1; /* Pointer to the simplified returned WinMap */ AstWinMap *wm; /* Pointer to the supplied WinMap */ double **ptr1; /* Pointer to pset1 data */ double **ptr2; /* Pointer to pset2 data */ double *a; /* Array of shift terms from supplied WinMap */ double *aa; /* Pointer to next shift term */ double *b; /* Array of scale terms from supplied WinMap */ double *bb; /* Pointer to next scale term */ int i; /* Axis count */ int nin; /* No. of axes in supplied WinMap */ int nout; /* No. of axes in returned WinMap */ int old_minv; /* Invert value for the supplied MatrixMap */ int old_winv; /* Invert value for the supplied WinMap */ /* Check the global error status. */ if ( !astOK ) return; /* Store pointers to the supplied WinMap and the MatrixMap. */ wm = (AstWinMap *) maps[ iwm ]; mm = (AstMatrixMap *) maps[ 1 - iwm ]; /* Temporarily set the Invert attribute of the supplied Mappings to the supplied values. */ old_winv = astGetInvert( wm ); astSetInvert( wm, inverts[ iwm ] ); old_minv = astGetInvert( mm ); astSetInvert( mm, inverts[ 1 - iwm ] ); /* Get copies of the shift and scale terms used by the WinMap. This also returns the number of axes in the WinMap. */ nin = astWinTerms( wm, &a, &b ); /* Create a diagonal MatrixMap holding the scale factors from the supplied WinMap. */ m1 = astMatrixMap( nin, nin, 1, b, "", status ); /* Create a PointSet holding a single position given by the shift terms in the supplied WinMap. */ pset1 = astPointSet( 1, nin, "", status ); ptr1 = astGetPoints( pset1 ); if( astOK ){ aa = a; for( i = 0; i < nin; i++ ) ptr1[ i ][ 0 ] = *(aa++); } /* First deal with cases when the WinMap is applied first, followed by the MatrixMap. */ if( iwm == 0 ){ /* Multiply the diagonal matrix holding the WinMap scale factors by the supplied matrix. The resulting MatrixMap is the one to return in the map list. */ m2 = astMtrMult( m1, mm ); /* Transform the position given by the shift terms from the supplied WinMap using the supplied MatrixMap to get the shift terms for the returned WinMap. */ pset2 = astTransform( mm, pset1, 1, NULL ); /* Now deal with cases when the MatrixMap is applied first, followed by the WinMap. */ } else { /* Multiply the supplied MatrixMap by the diagonal matrix holding scale factors from the supplied WinMap. The resulting MatrixMap is the one to return in the map list. */ m2 = astMtrMult( mm, m1 ); /* Transform the position given by the shift terms from the supplied WinMap using the inverse of the returned MatrixMap to get the shift terms for the returned WinMap. */ pset2 = astTransform( m2, pset1, 0, NULL ); } /* Re-instate the original value of the Invert attributes of the supplied Mappings. */ astSetInvert( wm, old_winv ); astSetInvert( mm, old_minv ); /* Get pointers to the shift terms for the returned WinMap. */ ptr2 = astGetPoints( pset2 ); /* Create the returned WinMap, initially with undefined corners. The number of axes in the WinMap must equal the number of shift terms. */ nout = astGetNcoord( pset2 ); w1 = astWinMap( nout, NULL, NULL, NULL, NULL, "", status ); /* If succesful, store the scale and shift terms in the WinMap. The scale terms are always unity. */ if( astOK ){ bb = w1->b; aa = w1->a; for( i = 0; i < nout; i++ ) { *(bb++) = 1.0; *(aa++) = ptr2[ i ][ 0 ]; } /* Replace the supplied Mappings and invert flags with the ones found above. Remember that the order of the Mappings is now swapped */ (void) astAnnul( maps[ 0 ] ); (void) astAnnul( maps[ 1 ] ); sw1 = astSimplify( w1 ); w1 = astAnnul( w1 ); maps[ 1 - iwm ] = (AstMapping *) sw1; inverts[ 1 - iwm ] = astGetInvert( sw1 ); sm2 = astSimplify( m2 ); m2 = astAnnul( m2 ); maps[ iwm ] = (AstMapping *) sm2; inverts[ iwm ] = astGetInvert( sm2 ); } /* Annul the MatrixMap and PointSet holding the scale and shift terms from the supplied WinMap. */ m1 = astAnnul( m1 ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Free the copies of the scale and shift terms from the supplied WinMap. */ b = (double *) astFree( (void *) b ); a = (double *) astFree( (void *) a ); /* Return. */ return; } static void WinWcs( AstMapping **maps, int *inverts, int iwm, int *status ){ /* * Name: * WinWcs * Purpose: * Swap a WinMap and a WcsMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void WinWcs( AstMapping **maps, int *inverts, int iwm, int *status ) * Class Membership: * WinMap member function * Description: * A list of two Mappings is supplied containing a WinMap and a * WcsMap. These Mappings are swapped. * Parameters: * maps * A pointer to an array of two Mapping pointers. * inverts * A pointer to an array of two invert flags. * iwm * The index within "maps" of the WinMap. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstMapping *m1; /* Pointer to a Mapping */ int inv; /* Invert value */ /* Check the global error status. */ if ( !astOK ) return; /* Simply swap the values (the CanSwap function will have checked that the WcsMap and WinMap can simply be swapped). */ m1 = maps[ 0 ]; maps[ 0 ] = maps[ 1 ]; maps[ 1 ] = m1; inv = inverts[ 0 ]; inverts[ 0 ] = inverts[ 1 ]; inverts[ 1 ] = inv; /* Return. */ return; } static void WinPerm( AstMapping **maps, int *inverts, int iwm, int *status ){ /* * Name: * WinPerm * Purpose: * Swap a WinMap and a PermMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * void WinPerm( AstMapping **maps, int *inverts, int iwm, int *status ) * Class Membership: * WinMap member function * Description: * A list of two Mappings is supplied containing a WinMap and a * PermMap. These Mappings are annulled, and replaced with * another pair of Mappings consisting of a WinMap and a PermMap * in the opposite order. These Mappings are chosen so that their * combined effect is the same as the original pair of Mappings. * Parameters: * maps * A pointer to an array of two Mapping pointers. * inverts * A pointer to an array of two invert flags. * iwm * The index within "maps" of the WinMap. * status * Pointer to the inherited status variable. * Notes: * - All links between input and output axes in the PermMap must * be bi-directional, but there can be unconnected axes, and there * need not be the same number of input and output axes. */ /* Local Variables: */ AstPermMap *pm; /* Pointer to the supplied PermMap */ AstPermMap *p1; /* Pointer to the returned PermMap */ AstPermMap *sp1; /* Pointer to the simplified returned PermMap */ AstWinMap *w1; /* Pointer to the returned WinMap */ AstWinMap *sw1; /* Pointer to the simplified returned PermMap */ AstWinMap *wm; /* Pointer to the supplied WinMap */ double *a; /* Array of shift terms from supplied WinMap */ double *aa; /* Pointer to next shift term */ double *b; /* Array of scale terms from supplied WinMap */ double *bb; /* Pointer to next scale term */ double *consts; /* Pointer to constants array */ double c; /* A constant value */ int *inperm; /* Pointer to input axis permutation array */ int *outperm; /* Pointer to output axis permutation array */ int i; /* Axis count */ int j; /* Axis index */ int nin; /* No. of axes in supplied WinMap */ int npin; /* No. of input axes in supplied PermMap */ int npout; /* No. of output axes in supplied PermMap */ int old_pinv; /* Invert value for the supplied PermMap */ int old_winv; /* Invert value for the supplied WinMap */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ p1 = NULL; w1 = NULL; /* Store pointers to the supplied WinMap and the PermMap. */ wm = (AstWinMap *) maps[ iwm ]; pm = (AstPermMap *) maps[ 1 - iwm ]; /* Temporarily set the Invert attribute of the supplied Mappings to the supplied values. */ old_winv = astGetInvert( wm ); astSetInvert( wm, inverts[ iwm ] ); old_pinv = astGetInvert( pm ); astSetInvert( pm, inverts[ 1 - iwm ] ); /* Get copies of the shift and scale terms used by the WinMap. This also returns the number of axes in the WinMap. */ nin = astWinTerms( wm, &a, &b ); /* Get the axis permutation and constants arrays representing the PermMap. Note, no constants are used more than once in the returned arrays (i.e. duplicate constants are returned in "consts" if more than one axis uses a given constant). */ PermGet( pm, &outperm, &inperm, &consts, status ); if( astOK ) { /* Get the number of input and output axes in the PermMap. */ npin = astGetNin( pm ); npout = astGetNout( pm ); /* First consider cases where the WinMap is applied first, followed by the PermMap. */ if( iwm == 0 ) { /* Create the new WinMap, initially with undefined corners. Its number of axes will equal the number of output axes of the PermMap. */ w1 = astWinMap( npout, NULL, NULL, NULL, NULL, "", status ); /* Get pointers to the scale and shift terms for the new WinMap. */ bb = w1->b; aa = w1->a; /* Thinking of the forward CmpMap first, consider each of the output axes of the PermMap. */ for( i = 0; i < npout; i++ ){ /* If the value for this output axis is derived from an input axis, copy the scale and shift terms from the corresponding input axis to the new WinMap. */ j = outperm[ i ]; if( j >= 0 && j < nin ) { aa[ i ] = a[ j ]; bb[ i ] = b[ j ]; /* If this output axis is assigned a constant value, use zero and one for the shift and scale in order to preserve the constant value produced by the PermMap. */ } else { aa[ i ] = 0.0; bb[ i ] = 1.0; } } /* Now consider the inverse CmpMap. Any constants produced by the inverse PermMap would previously have been scaled by the inverse WinMap. Since there will be no inverse WinMap to perform this scaling in the returned Mappings, we need to change the constant values to be the values after the scaling which would have been applied by the WinMap. Consider each of the input axes of the PermMap.*/ for( i = 0; i < npin; i++ ){ /* Skip axes which are not assigned a constant value. */ if( inperm[ i ] < 0 ) { /* Scale the constant term associated with this input axis using the inverse WinMap unless it is AST__BAD. */ c = consts[ -inperm[ i ] - 1 ]; if( c != AST__BAD ) { if( a[ i ] != AST__BAD && b[ i ] != AST__BAD && b[ i ] != 0.0 ) { consts[ -inperm[ i ] - 1 ] = ( c - a[ i ] )/b[ i ]; } else { consts[ -inperm[ i ] - 1 ] = AST__BAD; } } } } /* Now consider cases where the PermMap is applied first, followed by the WinMap. */ } else { /* Create the new WinMap, initially with undefined corners. Its number of axes will equal the number of input axes of the PermMap. */ w1 = astWinMap( npin, NULL, NULL, NULL, NULL, "", status ); /* Get pointers to the scale and shift terms for the new WinMap. */ bb = w1->b; aa = w1->a; /* Thinking first about the inverse WinMap, consider each of the input axes of the PermMap. */ for( i = 0; i < npin; i++ ){ /* If the value for this input axis is derived from an output axis, copy the scale and shift terms from the corresponding output axis to the new WinMap. */ j = inperm[ i ]; if( j >= 0 && j < nin ) { aa[ i ] = a[ j ]; bb[ i ] = b[ j ]; /* If this input axis is assigned a constant value, use zero and one for the shift and scale in order to preserve the constant value produced by the PermMap. */ } else { aa[ i ] = 0.0; bb[ i ] = 1.0; } } /* Now consider the forward WinMap. Any constants produced by the forward PermMap would previously have been scaled by the forward WinMap. Since there will be no forward WinMap to perform this scaling in the returned Mappings, we need to change the constant values to be the values after the scaling which would have been applied by the WinMap. Consider each of the output axes of the PermMap.*/ for( i = 0; i < npout; i++ ){ /* Skip axes which are not assigned a constant value. */ if( outperm[ i ] < 0 ) { /* Scale the constant term associated with this input axis using the forward WinMap unless it is AST__BAD. */ c = consts[ -outperm[ i ] - 1 ]; if( c != AST__BAD ) { if( a[ i ] != AST__BAD && b[ i ] != AST__BAD ) { consts[ -outperm[ i ] - 1 ] = a[ i ] + c*b[ i ]; } else { consts[ -outperm[ i ] - 1 ] = AST__BAD; } } } } } /* Create a new PermMap (since the constants may have changed). */ p1 = astPermMap( npin, inperm, npout, outperm, consts, "", status ); /* Free the axis permutation and constants arrays. */ outperm = (int *) astFree( (void *) outperm ); inperm = (int *) astFree( (void *) inperm ); consts = (double *) astFree( (void *) consts ); } /* Re-instate the original value of the Invert attributes of the supplied Mappings. */ astSetInvert( wm, old_winv ); astSetInvert( pm, old_pinv ); /* Replace the supplied Mappings with the ones created above, swapping the order. */ if( astOK ){ (void) astAnnul( wm ); (void) astAnnul( pm ); sp1 = astSimplify( p1 ); p1 = astAnnul( p1 ); sw1 = astSimplify( w1 ); w1 = astAnnul( w1 ); maps[ iwm ] = (AstMapping *) sp1; inverts[ iwm ] = 0; maps[ 1 - iwm ] = (AstMapping *) sw1; inverts[ 1 - iwm ] = astGetInvert( sw1 ); } /* Free the copies of the scale and shift terms from the supplied WinMap. */ b = (double *) astFree( (void *) b ); a = (double *) astFree( (void *) a ); /* Return. */ return; } static int WinTerms( AstWinMap *this, double **shift, double **scale, int *status ){ /* *+ * Name: * astWinTerms * Purpose: * Obtain the scale and shift terms used by a WinMap. * Type: * Protected virtual function. * Synopsis: * #include "winmap.h" * int astWinTerms( AstWinMap *this, double **shift, double **scale ) * Class Membership: * WinMap mewthod. * Description: * This function returns copies of the scale and shift terms used by a * WinMap when transforming points. Each axis of the WinMap has a scale * term B, and a shift term A, and the transformation of a point is done * by applying these to each input axis value X in turn, to get the * output axis value B.X + A. The returned terms take into account the * current setting of the Invert attribute of the WinMap. * Parameters: * this * Pointer to the WinMap. * shift * The address of a location at which to return a pointer to the * start of a dynamically allocated array holding the shift terms * for each axis. * scale * The address of a location at which to return a pointer to the * start of a dynamically allocated array holding the scale terms * for each axis. * Returned Value: * The number of axes in the WinMap. This is the same as the number of * elements in the returned arrays. * Notes: * - The returned arrays should be released using astFree when no * longer needed. * - NULL pointers can be supplied for "scale" or "shift" if the * corresponding arrays are not required. * - A value of zero will be returned, together with NULL pointers * for "scale" and "shift" if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ double *a; /* Pointer to a copy of the shift term array */ double *aa; /* Pointer to the next shift term */ double *b; /* Pointer to a copy of the scale term array */ double *bb; /* Pointer to the next scale term */ int i; /* Axis count */ int result; /* The returned number of axes */ size_t absize; /* Size of shift and scale arrays */ /* Initialise. */ result = 0; if( scale ) *scale = NULL; if( shift ) *shift = NULL; /* Check the global status. */ if ( !astOK ) return result; /* Get the number of axes in the WinMap. */ result = astGetNin( this ); /* Create copies of the scale and shift terms from the WinMap. */ absize = sizeof( double )*(size_t) result; b = (double *) astStore( NULL, (void *) this->b, absize ); a = (double *) astStore( NULL, (void *) this->a, absize ); /* Check the pointers can be used. */ if( astOK ){ /* If the WinMap is inverted, replace the scale and shift terms by the corresponding values for the inverted mapping. */ if( astGetInvert( this ) ){ bb = b; aa = a; for( i = 0; i < result; i++ ){ if( *aa != AST__BAD && *bb != 0.0 && *bb != AST__BAD ){ *bb = 1.0/(*bb); *aa *= -(*bb); } else { *bb = AST__BAD; *aa = AST__BAD; } aa++; bb++; } } /* Store the required pointers, and free arrays which are not required. */ if( scale ){ *scale = b; } else { b = (double *) astFree( (void *) b ); } if( shift ){ *shift = a; } else { a = (double *) astFree( (void *) a ); } } /* If an error has occurred, free the arrays and return zero. */ if( !astOK ){ if( scale ) *scale = (double *) astFree( (void *) *scale ); if( shift ) *shift = (double *) astFree( (void *) *shift ); result = 0; } /* Return the answer. */ return result; } static AstWinMap *WinUnit( AstWinMap *wm, AstUnitMap *um, int winv, int win1, int *status ){ /* * Name: * WinUnit * Purpose: * Create a WinMap by merging a WinMap and a UnitMap in parallel. * Type: * Private function. * Synopsis: * #include "winmap.h" * AstWinMap *WinUnit( AstWinMap *wm, AstUnitMap *um, int winv, int win1, int *status ) * Class Membership: * WinMap member function * Description: * This function creates a new WinMap which performs a mapping * equivalent to applying the two supplied Mappings in parallel in * the directions specified by the "invert" flag (the Invert * attribute of the supplied WinMap is ignored). * Parameters: * wm * A pointer to the WinMap. * um * A pointer to the UnitMap. * winv * The invert flag to use with wm. A value of zero causes the forward * mapping to be used, and a non-zero value causes the inverse * mapping to be used. * win1 * Indicates the order in which the Mappings should be applied. * * If win1 is non-zero: * "wm" applies to the lower axis indices and "um" to the upper * axis indices. * * If win1 is zero: * "um" applies to the lower axis indices and "wm" to the upper * axis indices. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the new WinMap. * Notes: * - The forward direction of the returned WinMap is equivalent to the * combined effect of the two supplied Mappings, operating in the * directions specified by "winv". * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *result; /* Pointer to output WinMap */ double *a; /* Pointer to shift term array */ double *aa; /* Pointer to next shift term */ double *ar; /* Pointer to next shift term in result */ double *b; /* Pointer to scale term array */ double *bb; /* Pointer to next scale term */ double *br; /* Pointer to next scale term in result */ int i; /* Axis index */ int ninw; /* No. of axes in the WinMap */ int ninu; /* No. of axes in the UnitMap */ int old_winv; /* Original setting of WinMap Invert attribute */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the returned pointer. */ result = NULL; /* Temporarily set the Invert attribute of the WinMap to the supplied value. */ old_winv = astGetInvert( wm ); astSetInvert( wm, winv ); /* Create copies of the scale and shift terms from the WinMap, and store the number of axes in it. */ ninw = astWinTerms( wm, &a, &b ); /* Get the number of axes in the UnitMap. */ ninu = astGetNin( um ); /* Create the merged WinMap with unspecified corners. */ result = astWinMap( ninw + ninu, NULL, NULL, NULL, NULL, "", status ); /* Check the pointers can be used. */ if( astOK ){ /* If the WinMap applies to the lower axis indices... */ if( win1 ){ /* Use the scale and shift terms from the WinMap for the lower axes of the new WinMap. */ aa = a; bb = b; ar = result->a; br = result->b; for( i = 0; i < ninw; i++ ){ *(ar++) = *(aa++); *(br++) = *(bb++); } /* Use the scale factor to 1.0 and the shift term to zero for the upper axes of the new WinMap. */ for( i = 0; i < ninu; i++ ){ *(ar++) = 0.0; *(br++) = 1.0; } /* If the WinMap applies to the upper axis indices... */ } else { /* Use the scale factor to 1.0 and the shift term to zero for the lower axes of the new WinMap. */ ar = result->a; br = result->b; for( i = 0; i < ninu; i++ ){ *(ar++) = 0.0; *(br++) = 1.0; } /* Use the scale and shift terms from the WinMap for the upper axes of the new WinMap. */ aa = a; bb = b; for( i = 0; i < ninw; i++ ){ *(ar++) = *(aa++); *(br++) = *(bb++); } } } /* Free the copies of the scale and shift terms from the supplied WinMap. */ b = (double *) astFree( (void *) b ); a = (double *) astFree( (void *) a ); /* Re-instate the original setting of the Invert attribute for the supplied WinMap. */ astSetInvert( wm, old_winv ); /* If an error has occurred, annull the returned WinMap. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output WinMap. */ return result; } static AstWinMap *WinWin( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int series, int *status ){ /* * Name: * WinWin * Purpose: * Create a merged WinMap from two supplied WinMaps. * Type: * Private function. * Synopsis: * #include "winmap.h" * AstWinMap *WinWin( AstMapping *map1, AstMapping *map2, int inv1, * int inv2, int series, int *status ) * Class Membership: * WinMap member function * Description: * This function creates a new WinMap which performs a mapping * equivalent to applying the two supplied WinMaps either in series * or parallel in the directions specified by the "invert" flags * (the Invert attributes of the supplied WinMaps are ignored). * Parameters: * map1 * A pointer to the WinMap to apply first (if in series), or to the * lower axis indices (if in parallel) * map2 * A pointer to the WinMap to apply second (if in series), or to the * upper axis indices (if in parallel) * inv1 * The invert flag to use with map1. A value of zero causes the forward * mapping to be used, and a non-zero value causes the inverse * mapping to be used. * inv2 * The invert flag to use with map2. * series * If non-zero, then the supplied WinMaps are combined in series. * Otherwise, they are combined in parallel. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the new WinMap. * Notes: * - The forward direction of the returned WinMap is equivalent to the * combined effect of the two supplied WinMap, operating in the * directions specified by "inv1" and "inv2". * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *result; /* Pointer to output WinMap */ AstWinMap *wm1; /* Pointer to the first supplied WinMap */ AstWinMap *wm2; /* Pointer to the second supplied WinMap */ double *a[ 2 ]; /* Pointers to shift term arrays */ double *a0; /* Pointer to next shift term from WinMap 1 */ double *a1; /* Pointer to next shift term from WinMap 2 */ double *ar; /* Pointer to next shift term in result */ double *b[ 2 ]; /* Pointers to scale term arrays */ double *b0; /* Pointer to next scale term from WinMap 1 */ double *b1; /* Pointer to next scale term from WinMap 2 */ double *br; /* Pointer to next scale term in result */ int cancel; /* Do the two WinMaps cancel out? */ int i; /* Axis index */ int invert[ 2 ]; /* Array of invert flags */ int nin[ 2 ]; /* No. of axes in the two WinMaps */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the returned pointer. */ result = NULL; /* Store pointers to the WinMaps. */ wm1 = (AstWinMap *) map1; wm2 = (AstWinMap *) map2; /* Temporarily set their Invert attributes to the supplied values. */ invert[ 0 ] = astGetInvert( wm1 ); astSetInvert( wm1, inv1 ); invert[ 1 ] = astGetInvert( wm2 ); astSetInvert( wm2, inv2 ); /* Create copies of the scale and shift terms from the two WinMaps, and store the number of axes in each WinMap. The scale and shift terms returned take into account the setting of the Invert attribute. */ nin[ 0 ] = astWinTerms( wm1, a, b ); nin[ 1 ] = astWinTerms( wm2, a + 1, b + 1 ); /* Check the pointers can be used. */ if( astOK ){ /* Series */ /* ====== */ if( series ){ /* Check for equal and opposite WinMaps. Do this explicitly using the supplied Mappings rather than the values returned by astWinTerms to avoid the affects of rounding error sin the inversions performed by astWinTerms. */ if( ( inv1 == 0 ) != ( inv2 == 0 ) ) { cancel = 1; for( i = 0; i < nin[ 0 ]; i++ ){ if( !EQUAL( (wm1->a)[ i ], (wm2->a)[ i ] ) || !EQUAL( (wm1->b)[ i ], (wm2->b)[ i ] ) ) { cancel = 0; break; } } } else { cancel = 0; } /* If they cancel, just put unit values into the WinMap. */ if( cancel ) { a0 = a[ 0 ]; b0 = b[ 0 ]; for( i = 0; i < nin[ 0 ]; i++ ){ *(a0++) = 0.0; *(b0++) = 1.0; } /* Otherwise, merge the scale and shift terms for the two WinMaps, overwriting the terms for the first WinMap. To be merged in series, both WinMaps must have the same number of axes, so it matters not whether we use nin[ 0 ] or nin[ 1 ] to specify the number of axes. */ } else { a0 = a[ 0 ]; b0 = b[ 0 ]; a1 = a[ 1 ]; b1 = b[ 1 ]; for( i = 0; i < nin[ 0 ]; i++ ){ if( *a0 != AST__BAD && *b0 != AST__BAD && *a1 != AST__BAD && *b1 != AST__BAD ){ *a0 *= (*b1); *a0 += (*a1); *b0 *= (*b1); } else { *a0 = AST__BAD; *b0 = AST__BAD; *a1 = AST__BAD; *b1 = AST__BAD; } /* Move on to the next axis. */ a0++; b0++; a1++; b1++; } } /* Create the merged WinMap with unspecified corners. */ result = astWinMap( nin[ 0 ], NULL, NULL, NULL, NULL, "", status ); /* Store the merged scale and shift terms in the new WinMap. The forward transformation of this WinMap then corresponds to the combination of the two supplied WinMaps, taking into account their invert flags. */ a0 = a[ 0 ]; b0 = b[ 0 ]; ar = result->a; br = result->b; for( i = 0; i < nin[ 0 ]; i++ ){ *(ar++) = *(a0++); *(br++) = *(b0++); } /* Parallel */ /* ======== */ } else { /* Create the merged WinMap with unspecified corners. */ result = astWinMap( nin[ 0 ] + nin[ 1 ], NULL, NULL, NULL, NULL, "", status ); /* Copy the scale and shift terms into the new WinMap. */ a0 = a[ 0 ]; b0 = b[ 0 ]; a1 = a[ 1 ]; b1 = b[ 1 ]; ar = result->a; br = result->b; for( i = 0; i < nin[ 0 ]; i++ ){ *(ar++) = *(a0++); *(br++) = *(b0++); } for( i = 0; i < nin[ 1 ]; i++ ){ *(ar++) = *(a1++); *(br++) = *(b1++); } } } /* Re-instate the original settings of the Invert attributes for the supplied WinMaps. */ astSetInvert( wm1, invert[ 0 ] ); astSetInvert( wm2, invert[ 1 ] ); /* Free the memory. */ a[ 0 ] = (double *) astFree( (void *) a[ 0 ] ); b[ 0 ] = (double *) astFree( (void *) b[ 0 ] ); a[ 1 ] = (double *) astFree( (void *) a[ 1 ] ); b[ 1 ] = (double *) astFree( (void *) b[ 1 ] ); /* If an error has occurred, annull the returned WinMap. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output WinMap. */ return result; } static AstWinMap *WinZoom( AstWinMap *wm, AstZoomMap *zm, int winv, int zinv, int win1, int series, int *status ){ /* * Name: * WinZoom * Purpose: * Create a WinMap by merging a WinMap and a ZoomMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * AstWinMap *WinZoom( AstWinMap *wm, AstZoomMap *zm, int winv, * int zinv, int win1, int series, int *status ) * Class Membership: * WinMap member function * Description: * This function creates a new WinMap which performs a mapping * equivalent to applying the two supplied Mappings in series or * parallel in the directions specified by the "invert" flags (the * Invert attributes of the supplied WinMaps are ignored). * Parameters: * wm * A pointer to the WinMap. * zm * A pointer to the ZoomMap. * winv * The invert flag to use with wm. A value of zero causes the forward * mapping to be used, and a non-zero value causes the inverse * mapping to be used. * zinv * The invert flag to use with zm. * win1 * Indicates the order in which the Mappings should be applied. * * If win1 is non-zero: * If in series: * "wm" is applied first followed by "zm". * If in parallel: * "wm" applies to the lower axis indices and "zm" to the upper * axis indices. * * If win1 is zero: * If in series: * "zm" is applied first followed by "wm". * If in parallel: * "zm" applies to the lower axis indices and "wm" to the upper * axis indices. * series * Should be supplied non-zero if the Mappings are to be combined in * series. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the new WinMap. * Notes: * - The forward direction of the returned WinMap is equivalent to the * combined effect of the two supplied Mappings, operating in the * directions specified by "zinv" and "winv". * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstWinMap *result; /* Pointer to output WinMap */ double *a; /* Pointer to shift term array */ double *aa; /* Pointer to next shift term */ double *ar; /* Pointer to next shift term in result */ double *b; /* Pointer to scale term array */ double *bb; /* Pointer to next scale term */ double *br; /* Pointer to next scale term in result */ double zfac; /* Zoom factor */ int i; /* Axis index */ int ninw; /* No. of axes in the WinMap */ int ninz; /* No. of axes in the ZoomMap */ int old_winv; /* Original setting of WinMap Invert attribute */ int old_zinv; /* Original setting of ZoomMap Invert attribute */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the returned pointer. */ result = NULL; /* Temporarily set the Invert attributes of both Mappings to the supplied values. */ old_winv = astGetInvert( wm ); astSetInvert( wm, winv ); old_zinv = astGetInvert( zm ); astSetInvert( zm, zinv ); /* Get the zoom factor implemented by the ZoomMap. Invert it if necessary since astGetZoom does not take account of the Invert setting. */ zfac = astGetZoom( zm ); if( zinv ) zfac = 1.0 / zfac; /* Create copies of the scale and shift terms from the WinMap, and store the number of axes in it. */ ninw = astWinTerms( wm, &a, &b ); /* Check the pointers can be used. */ if( astOK ){ /* First do series mode... */ if( series ) { /* Modify the WinMap scale and shift terms by the zoom factor. How this is done depends on which way round the Mappings are applied. */ bb = b; aa = a; for( i = 0; i < ninw; i++ ){ if( *aa != AST__BAD && *bb != AST__BAD && zfac != AST__BAD ){ *bb *= zfac; if( win1 ) *aa *= zfac; } else { *bb = AST__BAD; *aa = AST__BAD; } aa++; bb++; } /* Create the merged WinMap with unspecified corners. */ result = astWinMap( ninw, NULL, NULL, NULL, NULL, "", status ); /* Store the merged scale and shift terms in the new WinMap. The forward transformation of this WinMap then corresponds to the combination of the two supplied Mappings, taking into account their invert flags. */ aa = a; bb = b; ar = result->a; br = result->b; for( i = 0; i < ninw; i++ ){ *(ar++) = *(aa++); *(br++) = *(bb++); } /* Now do parallel mode... */ } else { /* Get the number of axes in the ZoomMap. */ ninz = astGetNin( zm ); /* Create the merged WinMap with unspecified corners. */ result = astWinMap( ninw + ninz, NULL, NULL, NULL, NULL, "", status ); /* If the WinMap applies to the lower axis indices... */ if( win1 ) { /* Use the scale and shift terms from the WinMap for the lower axes of the new WinMap. */ aa = a; bb = b; ar = result->a; br = result->b; for( i = 0; i < ninw; i++ ){ *(ar++) = *(aa++); *(br++) = *(bb++); } /* Use the scale factor (with zero shift) from the ZoomMap for the upper axes of the new WinMap. */ for( i = 0; i < ninz; i++ ){ *(ar++) = 0.0; *(br++) = zfac; } /* If the WinMap applies to the upper axis indices... */ } else { /* Use the scale factor (with zero shift) from the ZoomMap for the lower axes of the new WinMap. */ ar = result->a; br = result->b; for( i = 0; i < ninz; i++ ){ *(ar++) = 0.0; *(br++) = zfac; } /* Use the scale and shift terms from the WinMap for the upper axes of the new WinMap. */ aa = a; bb = b; for( i = 0; i < ninw; i++ ){ *(ar++) = *(aa++); *(br++) = *(bb++); } } } } /* Free the copies of the scale and shift terms from the supplied WinMap. */ b = (double *) astFree( (void *) b ); a = (double *) astFree( (void *) a ); /* Re-instate the original settings of the Invert attribute for the supplied Mappings. */ astSetInvert( wm, old_winv ); astSetInvert( zm, old_zinv ); /* If an error has occurred, annull the returned WinMap. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output WinMap. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for WinMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for WinMap objects. * Parameters: * objin * Pointer to the WinMap to be copied. * objout * Pointer to the WinMap being constructed. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstWinMap *out; /* Pointer to output WinMap */ AstWinMap *in; /* Pointer to input WinMap */ int ncoord; /* No. of axes for the mapping */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the input and output WinMaps. */ in= (AstWinMap *) objin; out = (AstWinMap *) objout; /* Get the number of coordinates mapped by the WinMap. */ ncoord = astGetNin( in ); /* Allocate memory holding copies of the scales and shifts window defining the mapping. */ out->a = (double *) astStore( NULL, (void *) in->a, sizeof(double)*(size_t)ncoord ); out->b = (double *) astStore( NULL, (void *) in->b, sizeof(double)*(size_t)ncoord ); /* If an error occurred, free any allocated memory. */ if ( !astOK ) { out->a = (double *) astFree( (void *) out->a ); out->b = (double *) astFree( (void *) out->b ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for WinMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for WinMap objects. * Parameters: * obj * Pointer to the WinMap to be deleted. * status * Pointer to the inherited status variable. * Notes: * - This destructor does nothing and exists only to maintain a * one-to-one correspondence between destructors and copy * constructors. */ /* Local Variables: */ AstWinMap *this; /* Pointer to WinMap */ /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) obj; /* Free the memory holding the scales and shifts. */ this->a = (double *) astFree( (void *) this->a ); this->b = (double *) astFree( (void *) this->b ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for WinMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the WinMap class to an output Channel. * Parameters: * this * Pointer to the WinMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define COMMENT_LEN 50 /* Maximum length of a comment string */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstWinMap *this; /* Pointer to the WinMap structure */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment string */ int axis; /* Axis index */ int ncoord; /* No. of axes for mapping */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the WinMap structure. */ this = (AstWinMap *) this_object; /* Get the number of coordinates to be mapped. */ ncoord = astGetNin( this ); /* Write out values representing the instance variables for the WinMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* The scales and shifts. */ for( axis = 0; axis < ncoord; axis++ ){ (void) sprintf( buff, "Sft%d", axis + 1 ); (void) sprintf( comment, "Shift for axis %d", axis + 1 ); astWriteDouble( channel, buff, (this->a)[ axis ] != 0.0, 0, (this->a)[ axis ], comment ); (void) sprintf( buff, "Scl%d", axis + 1 ); (void) sprintf( comment, "Scale factor for axis %d", axis + 1 ); astWriteDouble( channel, buff, (this->b)[ axis ] != 1.0, 0, (this->b)[ axis ], comment ); } /* Undefine macros local to this function. */ #undef COMMENT_LEN #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAWinMap and astCheckWinMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(WinMap,Mapping) astMAKE_CHECK(WinMap) AstWinMap *astWinMap_( int ncoord, const double c1_in[], const double c2_in[], const double c1_out[], const double c2_out[], const char *options, int *status, ...) { /* *++ * Name: c astWinMap f AST_WINMAP * Purpose: * Create a WinMap. * Type: * Public function. * Synopsis: c #include "winmap.h" c AstWinMap *astWinMap( int ncoord, c const double ina[], const double inb[], c const double outa[], const double outb[], c const char *options, ... ) f RESULT = AST_WINMAP( NCOORD, INA, INB, OUTA, OUTB, OPTIONS, STATUS ) * Class Membership: * WinMap constructor. * Description: * This function creates a new WinMap and optionally initialises its * attributes. * * A Winmap is a linear Mapping which transforms a rectangular * window in one coordinate system into a similar window in another * coordinate system by scaling and shifting each axis (the window * edges being parallel to the coordinate axes). * * A WinMap is specified by giving the coordinates of two opposite * corners (A and B) of the window in both the input and output * coordinate systems. * Parameters: c ncoord f NCOORD = INTEGER (Given) * The number of coordinate values for each point to be * transformed (i.e. the number of dimensions of the space in * which the points will reside). The same number is applicable * to both input and output points. c ina f INA( NCOORD ) = DOUBLE PRECISION (Given) c An array containing the "ncoord" f An array containing the * coordinates of corner A of the window in the input coordinate * system. c inb f INB( NCOORD ) = DOUBLE PRECISION (Given) c An array containing the "ncoord" f An array containing the * coordinates of corner B of the window in the input coordinate * system. c outa f OUTA( NCOORD ) = DOUBLE PRECISION (Given) c An array containing the "ncoord" f An array containing the * coordinates of corner A of the window in the output coordinate * system. c outb f OUTB( NCOORD ) = DOUBLE PRECISION (Given) c An array containing the "ncoord" f An array containing the * coordinates of corner B of the window in the output coordinate * system. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new WinMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new WinMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astWinMap() f AST_WINMAP = INTEGER * A pointer to the new WinMap. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstWinMap *new; /* Pointer to new WinMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the WinMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitWinMap( NULL, sizeof( AstWinMap ), !class_init, &class_vtab, "WinMap", ncoord, c1_in, c2_in, c1_out, c2_out ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new WinMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new WinMap. */ return new; } AstWinMap *astWinMapId_( int ncoord, const double c1_in[], const double c2_in[], const double c1_out[], const double c2_out[], const char *options, ... ) { /* * Name: * astWinMapId_ * Purpose: * Create a WinMap. * Type: * Private function. * Synopsis: * #include "winmap.h" * AstWinMap *astWinMapId_( int ncoord, const double c1_in[], * const double c2_in[], const double c1_out[], * const double c2_out[], * const char *options, ... ) * Class Membership: * WinMap constructor. * Description: * This function implements the external (public) interface to the * astWinMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astWinMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astWinMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astWinMap_. * Returned Value: * The ID value associated with the new WinMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstWinMap *new; /* Pointer to new WinMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the WinMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitWinMap( NULL, sizeof( AstWinMap ), !class_init, &class_vtab, "WinMap", ncoord, c1_in, c2_in, c1_out, c2_out ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new WinMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new WinMap. */ return astMakeId( new ); } AstWinMap *astInitWinMap_( void *mem, size_t size, int init, AstWinMapVtab *vtab, const char *name, int ncoord, const double *c1_in, const double *c2_in, const double *c1_out, const double *c2_out, int *status ) { /* *+ * Name: * astInitWinMap * Purpose: * Initialise a WinMap. * Type: * Protected function. * Synopsis: * #include "winmap.h" * AstWinMap *astInitWinMap( void *mem, size_t size, int init, * AstWinMapVtab *vtab, const char *name, * int ncoord, const double *c1_in, * const double *c2_in, * const double *c1_out, const double *c2_out ) * Class Membership: * WinMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new WinMap object. It allocates memory (if necessary) to accommodate * the WinMap plus any additional data associated with the derived class. * It then initialises a WinMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a WinMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the WinMap is to be initialised. * This must be of sufficient size to accommodate the WinMap data * (sizeof(WinMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the WinMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the WinMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the WinMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new WinMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * ncoord * The number of coordinate values per point. * c1_in * The input coordinates of corner C1 of the window. * c2_in * The input coordinates of corner C2 of the window. * c1_out * The output coordinates of corner C1 of the window. * c2_out * The output coordinates of corner C2 of the window. * Returned Value: * A pointer to the new WinMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstWinMap *new; /* Pointer to new WinMap */ double denom; /* Denominotor */ int axis; /* Axis index */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitWinMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Initialise a Mapping structure (the parent class) as the first component within the WinMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstWinMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, ncoord, ncoord, 1, 1 ); if ( astOK ) { /* Initialise the WinMap data. */ /* ---------------------------- */ /* Allocate memory to hold the shift and scale for each axis. */ new->a = (double *) astMalloc( sizeof(double)*(size_t)ncoord ); new->b = (double *) astMalloc( sizeof(double)*(size_t)ncoord ); /* Check the pointers can be used */ if( astOK ){ /* Calculater and store the shift and scale for each axis. */ for( axis = 0; axis < ncoord; axis++ ){ /* If any of the corners have not been provided, store bad values. */ if( !c1_in || !c1_out || !c2_in || !c2_out ) { (new->b)[ axis ] = AST__BAD; (new->a)[ axis ] = AST__BAD; /* Otherwise, check the corners are good (not AST__BAD or NaN)... */ } else if( astISGOOD(c2_in[ axis ]) && astISGOOD(c1_in[ axis ]) && astISGOOD(c2_out[ axis ]) && astISGOOD(c1_out[ axis ]) ){ denom = c2_in[ axis ] - c1_in[ axis ]; if( denom != 0.0 ){ (new->b)[ axis ] = ( c2_out[ axis ] - c1_out[ axis ] )/denom; (new->a)[ axis ] = c1_out[ axis ] - (new->b)[ axis ]*c1_in[ axis ]; } else { (new->b)[ axis ] = AST__BAD; (new->a)[ axis ] = AST__BAD; } } else { (new->b)[ axis ] = AST__BAD; (new->a)[ axis ] = AST__BAD; } } } /* If an error occurred, clean up by deleting the new WinMap. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new WinMap. */ return new; } AstWinMap *astLoadWinMap_( void *mem, size_t size, AstWinMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadWinMap * Purpose: * Load a WinMap. * Type: * Protected function. * Synopsis: * #include "winmap.h" * AstWinMap *astLoadWinMap( void *mem, size_t size, * AstWinMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * WinMap loader. * Description: * This function is provided to load a new WinMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * WinMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a WinMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the WinMap is to be * loaded. This must be of sufficient size to accommodate the * WinMap data (sizeof(WinMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the WinMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the WinMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstWinMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new WinMap. If this is NULL, a pointer * to the (static) virtual function table for the WinMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "WinMap" is used instead. * Returned Value: * A pointer to the new WinMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants. */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstWinMap *new; /* Pointer to the new WinMap */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ int axis; /* Axis index */ int ncoord; /* The number of coordinate axes */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this WinMap. In this case the WinMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstWinMap ); vtab = &class_vtab; name = "WinMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitWinMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built WinMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Get the number of axis for the mapping. */ ncoord = astGetNin( (AstMapping *) new ); /* Allocate memory to hold the scales and shifts. */ new->a = (double *) astMalloc( sizeof(double)*(size_t)ncoord ); new->b = (double *) astMalloc( sizeof(double)*(size_t)ncoord ); /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "WinMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* The scales and shifts. */ for( axis = 0; axis < ncoord; axis++ ){ (void) sprintf( buff, "sft%d", axis + 1 ); (new->a)[ axis ] = astReadDouble( channel, buff, 0.0 ); (void) sprintf( buff, "scl%d", axis + 1 ); (new->b)[ axis ] = astReadDouble( channel, buff, 1.0 ); } } /* If an error occurred, clean up by deleting the new WinMap. */ if ( !astOK ) new = astDelete( new ); /* Return the new WinMap pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ int astWinTerms_( AstWinMap *this, double **scale, double **shift, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,WinMap,WinTerms))( this, scale, shift, status ); } ./ast-7.3.3/frame.h0000644000175000017500000017664712262533650012432 0ustar olesoles#if !defined( FRAME_INCLUDED ) /* Include this file only once */ #define FRAME_INCLUDED /* *+ * Name: * frame.h * Type: * C include file. * Purpose: * Define the interface to the Frame class. * Invocation: * #include "frame.h" * Description: * This include file defines the interface to the Frame class and * provides the type definitions, function prototypes and macros, etc. * needed to use this class. * * A Frame object encapsulates information about a coordinate * system, including its axes. It may also act as a "template" to * be matched against another Frame object. This process determines * whether it is possible to perform a coordinate transformation * between the two coordinates systems they describe. * Inheritance: * The Frame class inherits from the Mapping class. * Attributes Over-Ridden: * Nin (integer, readonly) * The Frame class sets this value to be equal to the number of * Frame axes. * Nout (integer, readonly) * The Frame class sets this value to be equal to the number of * Frame axes. * New Attributes Defined: * AlignSystem (string) * This attribute takes a value to identify the coordinate system * in which the Frame should be aligned with other Frames. * Digits [or Digits(axis)] (integer) * Specifies how many digits of precision are required by * default when a coordinate value for a Frame is formatted * (e.g. using the astFormat method). The Digits value acts as a * default only and is over-ridden if a Format string is * specified for an axis explicitly. * * The default Digits value for a Frame is 7. This attribute * normally applies to all the Frame's axes, but reference may * be made to a particular axis by adding an axis subscript * (e.g. Digits(1)). If a value is set for an individual axis, * it will over-ride the Digits value for the Frame as a whole * when formatting values for that axis. * Direction(axis) (integer) * A boolean value which specifies how coordinate values for * each Frame axis should be displayed (e.g. in graphs). By * default, it has the value one, indicating that they should be * shown in the conventional sense (i.e. increasing left to * right for an abscissa and bottom to top for an ordinate). If * set to zero, this attribute indicates that the direction * should be reversed (as would often be done for an * astronomical magnitude or a right ascension axis, for * example). * Epoch (double) * This value is used to qualify coordinate systems by * giving the moment in time when the coordinates are known to * be correct. Often, this will be the date of observation. * Format(axis) (string) * Specifies the format to be used to display coordinate values * for each Frame axis (i.e. to convert them from binary to * character form). The interpretation of this string (e.g. by * derived classes) is left to the astFormat method which, in * turn will invoke the astAxisFormat for the Axis object that * describes each axis. By default, the Frame class supplies an * Axis class object for each axis and this will interpret this * parameter as a C "printf" format string which should be * capable of formatting a single coordinate value stored as a * double (e.g. "%1.7G"). If no Format string is set, the * default format is based on the value of the Digits attribute. * Label(axis) (string) * Specifies the label to be attached to each Frame axis when it * is represented in (e.g.) a graph. It is intended purely for * interpretation by human readers and not by software. The * default supplied by the Frame class is the string "Axis ", * where is 1, 2, etc. for each successive axis. * MatchEnd (integer) * A boolean value that controls how a Frame behaves when used * as a template to match another Frame. If it is zero and a * template Frame matches a target frame which has a different * number of axes, then the axes wich occur first in the target * frame will be matched and any trailing axes in either the * target or template will be discarded (if necessary). If it is * non-zero, however, the last axes in each frame will be * matched and any un-matched leading axes will be discarded * instead. The default value supplied by the Frame class is * zero. * MaxAxes (integer) * Specifies the maximum number of axes in a target Frame that * can be matched when using the Frame as a template. Normally, * by default, this value is equal to the number of Frame axes, * so that a Frame will only match another Frame with the same * number of axes as itself. By setting a different value, * however, Frames with different numbers of axes may be matched * (the MatchEnd attribute then determines which of the * individual axes are matched). * * When setting this value, the value of the MinAxes attribute * may be silently changed so that it remains consistent with * (i.e. does not exceed) the new value. The default value may * also be reduced if necessary to remain consistent with the * MinAxes value. * MinAxes (integer) * Specifies the minimum number of axes in a target Frame that * can be matched when using the Frame as a template. Normally, * by default, this value is equal to the number of Frame axes, * so that a Frame will only match another Frame with the same * number of axes as itself. By setting a different value, * however, Frames with different numbers of axes may be matched * (the MatchEnd attribute then determines which of the * individual axes are matched). * * When setting this value, the value of the MaxAxes attribute * may be silently changed so that it remains consistent with * (i.e. is not less than) the new value. The default value may * also be reduced if necessary to remain consistent with the * MaxAxes value. * Domain (string) * A string which may be used to identify the physical domain to * which a Frame applies and used as an additional key when * matching a target Frame with a template. If the Domain * attribute in the template Frame is set, then only target * frames with the same Domain value will be matched. If a * Domain is not set in the template Frame, the target Frame's * Domain value will be ignored and has no effect on * matching. The default value supplied by the Frame class is an * empty string. Domain values are automatically converted to * upper case and all white space is removed before use. * Naxes (integer) * A read-only attribute that gives the number of axes in a * Frame (i.e. the number of dimensions of the space which the * Frame describes). This value is determined when the Frame is * created. * Permute (integer) * A boolean value which specifies whether the axis order of a * target Frame may be permuted in order to obtain a match with * a template. If this value is set to zero in the template * Frame, it will only match a target if it can do so without * changing the order of its axes. The default value supplied by * the Frame class is 1 (i.e. allow axis permutations). * PreserveAxes (integer) * A boolean value which determines how the "result" Frame is * produced whan a target frame is matched by a template. If * this value is zero in the template Frame, then the result * Frame will have the same number of axes as the template. If * it is non-zero, however, the axes of the target Frame will be * preserved, so that the result Frame will have the same number * of axes as the target. The default supplied by the Frame * class is zero (i.e. target axes are not preserved). * * The main use for this attribute is when the MaxAxes and/or * MinAxes attributes have been set to search for a Frame which * may have a different number of axes from the template. For * example, if a 2-dimensional template Frame matches a * 3-dimensional target Frame, then by default the result is * 2-dimensional and the last axis (normally) will be * discarded. However, if the template's PreserveAxes value is * non-zero, the result will instead be 3-dimensional to * correspond with the target Frame. * Symbol(axis) (string) * Specifies the symbol to be used to represent coordinate * values for each Frame axis in "short form", such as in * algebraic expressions where a full description of the axis * would be inappropriate. Examples include "RA" and "Dec" (for * Right Ascension and Declination). * * The default supplied by the Frame class is the string * "", where is 1, 2, etc. for successive axes, * and is the value of the Frame's Domain attribute * (with any white space replaced by underscores and truncated * if necessary so that the final string does not exceed 15 * characters). If no Domain value has been set, "x" is used as * the value in constructing this default string. * System (string) * This attribute takes a value to identify the coordinate system * used to describe positions within the domain of the Frame. * Title (string) * Specifies a string to be used as a title on (e.g.) graphs to * describe the coordinate system which the Frame * represents. Examples would be "Detector Coordinates" or * "Galactic Coordinates". This string is intended solely for * interpretation by human readers and not by software. The * default supplied by the Frame class is "-D Coordinate * System", where is the number of Frame axes. * Unit(axis) (string) * Describes the units used to represent coordinate values on * each Frame axis. The default supplied by the Frame class is * an empty string. * Methods Over-Ridden: * Public: * astGetNin * Get the number of input coordinates for a Frame. * astGetNout * Get the number of output coordinates for a Frame. * astTransform * Use a Frame to transform a set of points. * Protected: * astClearAttrib * Clear an attribute value for a Frame. * astGetAttrib * Get an attribute value for a Frame. * astReportPoints * Report the effect of transforming a set of points using a Frame. * astSetAttrib * Set an attribute value for a Frame. * astTestAttrib * Test if an attribute value has been set for a Frame. * New Methods Defined: * Public: * astAngle * Calculate the angle between three points. * astAxAngle * Find the angle from an axis to a line through two points. * astAxDistance * Calculate the distance between two axis values * astAxOffset * Calculate an offset along an axis * astConvert * Determine how to convert between two coordinate systems. * astDistance * Calculate the distance between two points. * astFindFrame * Find a coordinate system with specified characteristics * astFormat * Format a coordinate value for a Frame axis. * astNorm * Normalise a set of Frame coordinates. * astOffset * Calculate an offset along a geodesic curve. * astOffset2 * Calculate an offset along a geodesic curve for a 2D Frame. * astPermAxes * Permute the order of a Frame's axes. * astPickAxes * Create a new Frame by picking axes from an existing one. * astResolve * Resolve a vector into two orthogonal components. * astUnformat * Read a formatted coordinate value for a Frame axis. * Protected: * astAbbrev * Abbreviate a formatted Frame axis value by skipping * leading fields. * astCheckPerm * Check that an array contains a valid permutation. * astClearDigits * Clear the Digits attribute for a Frame. * astClearDirection * Clear the Direction attribute for a Frame axis. * astClearDomain * Clear the Domain attribute for a Frame. * astClearFormat * Clear the Format attribute for a Frame axis. * astClearLabel * Clear the Label attribute for a Frame axis. * astClearMatchEnd * Clear the MatchEnd attribute for a Frame. * astClearMaxAxes * Clear the MaxAxes attribute for a Frame. * astClearMinAxes * Clear the MinAxes attribute for a Frame. * astClearPermute * Clear the Permute attribute for a Frame. * astClearPreserveAxes * Clear the PreserveAxes attribute for a Frame. * astClearSymbol * Clear the Symbol attribute for a Frame axis. * astClearSystem * Clear the value of the System attribute for a Frame. * astClearTitle * Clear the Title attribute for a Frame. * astClearUnit * Clear the Unit attribute for a Frame axis. * astConvertX * Determine how to convert between two coordinate systems. * astFields * Identify the fields within a formatted Frame axis value. * astGap * Find a "nice" gap for tabulating Frame axis values. * astGetAxis * Obtain a pointer to a specified Axis from a Frame. * astGetDigits * Get the value of the Digits attribute for a Frame. * astGetDirection * Get the value of the Direction attribute for a Frame axis. * astGetDomain * Get a pointer to the Domain attribute for a Frame. * astGetFormat * Get a pointer to the Format attribute for a Frame axis. * astGetLabel * Get a pointer to the Label attribute for a Frame axis. * astGetMatchEnd * Get the value of the MatchEnd attribute for a Frame. * astGetMaxAxes * Get the value of the MaxAxes attribute for a Frame. * astGetMinAxes * Get the value of the MinAxes attribute for a Frame. * astGetNaxes * Determine how many axes a Frame has. * astGetPerm * Access the axis permutation array for a Frame. * astGetPermute * Get the value of the Permute attribute for a Frame. * astGetPreserveAxes * Get the value of the PreserveAxes attribute for a Frame. * astGetSymbol * Get a pointer to the Symbol attribute for a Frame axis. * astGetSystem * Get the value of the System attribute for a Frame. * astGetTitle * Get a pointer to the Title attribute for a Frame. * astGetUnit * Get a pointer to the Unit attribute for a Frame axis. * astIsUnitFrame * Returns a flag indicating if a Frame is equivalent to a UnitMap. * astMatch * Determine if conversion is possible between two coordinate systems. * astOverlay * Overlay the attributes of a template Frame on to another Frame. * astPrimaryFrame * Uniquely identify a primary Frame and one of its axes. * astResolvePoints * Resolve many vectors into two orthogonal components. * astSetAxis * Set a new Axis for a Frame. * astSetDigits * Set the value of the Digits attribute for a Frame. * astSetDirection * Set the value of the Direction attribute for a Frame axis. * astSetDomain * Set the value of the Domain attribute for a Frame. * astSetFormat * Set the value of the Format attribute for a Frame axis. * astSetLabel * Set the value of the Label attribute for a Frame axis. * astSetMatchEnd * Set the value of the MatchEnd attribute for a Frame. * astSetMaxAxes * Set the value of the MaxAxes attribute for a Frame. * astSetMinAxes * Set the value of the MinAxes attribute for a Frame. * astSetPermute * Set the value of the Permute attribute for a Frame. * astSetPreserveAxes * Set the value of the PreserveAxes attribute for a Frame. * astSetSymbol * Set the value of the Symbol attribute for a Frame axis. * astSetSystem * Set the value of the System attribute for a Frame. * astSetTitle * Set the value of the Title attribute for a Frame. * astSetUnit * Set the value of the Unit attribute for a Frame axis. * astSubFrame * Select axes from a Frame and convert to the new coordinate system. * astTestDigits * Test whether a value has been set for the Digits attribute of a * Frame. * astTestDirection * Test whether a value has been set for the Direction attribute of a * Frame axis. * astTestDomain * Test whether a value has been set for the Domain attribute of a * Frame. * astTestFormat * Test whether a value has been set for the Format attribute of a * Frame axis. * astTestLabel * Test whether a value has been set for the Label attribute of a * Frame axis. * astTestMatchEnd * Test whether a value has been set for the MatchEnd attribute of a * Frame. * astTestMaxAxes * Test whether a value has been set for the MaxAxes attribute of a * Frame. * astTestMinAxes * Test whether a value has been set for the MinAxes attribute of a * Frame. * astTestPermute * Test whether a value has been set for the Permute attribute of a * Frame. * astTestPreserveAxes * Test whether a value has been set for the PreserveAxes attribute of * a Frame. * astTestSymbol * Test whether a value has been set for the Symbol attribute of a * Frame axis. * astTestSystem * Test whether a value has been set for the System attribute of a * Frame. * astTestTitle * Test whether a value has been set for the Title attribute of a * Frame. * astTestUnit * Test whether a value has been set for the Unit attribute of a Frame * axis. * astValidateAxis * Validate and permute a Frame's axis index. * astValidateAxisSelection * Check that a set of axes selected from a Frame is valid. * astValidateSystem * Validate a Frame's System attribute. * astSystemString * Return a string representation of a System code. * astSystemCode * Return a code for a string representation of a System value * Other Class Functions: * Public: * astFrame * Create a Frame. * astIsAFrame * Test class membership. * Protected: * astCheckFrame * Validate class membership. * astInitFrame * Initialise a Frame. * astInitFrameVtab * Initialise the virtual function table for the Frame class. * astLoadFrame * Load a Frame. * Macros: * Public: * None. * Protected: * AST__BADSYSTEM * A "bad" (undefined) value for the System attribute. * Type Definitions: * Public: * AstFrame * Frame object type. * Protected: * AstFrameVtab * Frame virtual function table type. * AstSystemType * Enumerated type used for the System attribute. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: B.S. Berry (Starlink) * History: * 1-MAR-1996 (RFWS): * Original version. * 25-APR-1996 (RFWS): * Tidied up, etc. * 11-SEP-1996 (RFWS): * Added astGap (written by DSB). * 10-JUN-1997 (RFWS): * Revised astConvert and added astFindFrame. * 15-FEB-1998 (RFWS): * Added astUnformat. * 21-JUN-2001 (DSB): * Added astAngle and astOffset2. * 29-AUG-2001 (DSB): * Added astAxDistance and astAxOffset. * 4-SEP-2001 (DSB): * Added astResolve. * 9-SEP-2001 (DSB): * Added astBear. * 21-SEP-2001 (DSB): * Replace astBear with astAxAngle. * 15-NOV-2002 (DSB): * Moved System and Epoch attributes from SkyFrame into this class. * Added AlignSystem attribute. * 8-JAN-2003 (DSB): * Added protected astInitFrameVtab method. * 24-JAN-2004 (DSB): * o Added astFields. * o Added argument "fmt" to astAbbrev. * 24-JUN-2004 (DSB): * Remove unused entry "void (* SetMatchRange)( AstFrame *, int, int );" * from AstFrameVtab structure. * 9-NOV-2004 (DSB): * Added protected astIsAUnitFrame method. * 12-AUG-2005 (DSB): * Added ObsLat and ObsLon attributes. * 14-OCT-2006 (DSB): * Added dut1 to the Frame structure. * Added Dut1 accessor methods. * 17-MAY-2007 (DSB): * Added NormUnit attribute. * 14-JAN-2009 (DSB): * Added astIntersect method. * 18-JUN-2009 (DSB): * Added ObsAlt attribute. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ #include "axis.h" /* Coordinate Axis class */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #include /* Macros. */ /* ------- */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif #if defined(astCLASS) /* Protected */ /* A bad value for the System attribute. */ #define AST__BADSYSTEM -1 /* The legal System values recognized by this class of Frame. */ #define AST__CART 0 /* Flag bitmasks for use with astSetFrameFlags. */ # define AST__INTFLAG 1 /* FrameSet integrity is currently being restored */ /* Define constants used to size global arrays in this module. */ #define AST__FRAME_LABEL_BUFF_LEN 100 /* Max length of default axis Label string */ #define AST__FRAME_SYMBOL_BUFF_LEN 50 /* Max length of default axis Symbol string */ #define AST__FRAME_TITLE_BUFF_LEN 100 /* Max length of default title string */ #define AST__FRAME_GETATTRIB_BUFF_LEN 50 /* Max length of string returned by GetAttrib */ #define AST__FRAME_ASTFMTDECIMALYR_BUFF_LEN 50 /* Max length of string returned by GetAttrib */ #define AST__FRAME_ASTFORMATID_MAX_STRINGS 50 /* Number of string values buffer by astFormatID*/ #endif /* Type Definitions. */ /* ================= */ /* Integer type used to store the System attribute values. */ typedef int AstSystemType; /* Frame structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstFrame { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ AstAxis **axis; /* Pointer to array of Axis objects */ char *domain; /* Pointer to Domain string */ char *title; /* Pointer to Title string */ double epoch; /* Epoch as Modified Julian Date */ double obslat; /* Geodetic latitude of observer */ double obslon; /* Geodetic longitude of observer */ double obsalt; /* Height above reference spheroid (geodetic, metres) */ double dut1; /* UT1-UTC in seconds */ int *perm; /* Pointer to axis permutation array */ int digits; /* Default digits of precision */ int match_end; /* Match final axes of target? */ int active_unit; /* Use Unit when aligning Frames? */ int max_axes; /* Minimum no. axes matched */ int min_axes; /* Max. no. axes matched */ int naxes; /* Number of axes */ int permute; /* Permute axes in order to match? */ int preserve_axes; /* Preserve target axes? */ AstSystemType system; /* Code identifying coordinate system */ AstSystemType alignsystem; /* Code for Alignment coordinate system */ int flags; /* Bit mask containing various protected flags */ struct AstFrameSet *variants; /* FrameSet defining alternative properties for the Frame */ } AstFrame; /* Cached Line structure. */ /* ---------------------- */ /* This structure contains information describing a line segment within a 2D Frame. It is used by other classes to store intermediate cached values relating to the line in order to speed up repeated operations on the line. */ typedef struct AstLineDef { AstFrame *frame; /* Pointer to Frame in which the line is defined */ double length; /* Line length */ int infinite; /* Disregard the start and end of the line? */ double start[2]; /* Frame axis values at line start */ double end[2]; /* Frame axis values at line end */ double dir[2]; /* Unit vector defining line direction */ double q[2]; /* Unit vector perpendicular to line */ } AstLineDef; /* Virtual function table. */ /* ----------------------- */ /* The virtual function table makes a forward reference to the AstFrameSet structure which is not defined until "frameset.h" is included (below). Hence make a preliminary definition available now. */ struct AstFrameSet; /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstFrameVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ AstAxis *(* GetAxis)( AstFrame *, int, int * ); AstFrame *(* PickAxes)( AstFrame *, int, const int[], AstMapping **, int * ); AstLineDef *(* LineDef)( AstFrame *, const double[2], const double[2], int * ); AstPointSet *(* ResolvePoints)( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * ); const char *(* Abbrev)( AstFrame *, int, const char *, const char *, const char *, int * ); const char *(* Format)( AstFrame *, int, double, int * ); const char *(* GetDomain)( AstFrame *, int * ); const char *(* GetFormat)( AstFrame *, int, int * ); const char *(* GetLabel)( AstFrame *, int, int * ); const char *(* GetSymbol)( AstFrame *, int, int * ); const char *(* GetTitle)( AstFrame *, int * ); const char *(* GetNormUnit)( AstFrame *, int, int * ); const char *(* GetUnit)( AstFrame *, int, int * ); const int *(* GetPerm)( AstFrame *, int * ); double (* Angle)( AstFrame *, const double[], const double[], const double[], int * ); double (* Distance)( AstFrame *, const double[], const double[], int * ); double (* Gap)( AstFrame *, int, double, int *, int * ); int (* Fields)( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * ); double (* AxDistance)( AstFrame *, int, double, double, int * ); double (* AxOffset)( AstFrame *, int, double, double, int * ); int (* AxIn)( AstFrame *, int, double, double, double, int, int * ); int (* GetDigits)( AstFrame *, int * ); int (* GetDirection)( AstFrame *, int, int * ); int (* GetMatchEnd)( AstFrame *, int * ); int (* GetMaxAxes)( AstFrame *, int * ); int (* GetMinAxes)( AstFrame *, int * ); int (* GetNaxes)( AstFrame *, int * ); int (* GetPermute)( AstFrame *, int * ); int (* GetPreserveAxes)( AstFrame *, int * ); int (* IsUnitFrame)( AstFrame *, int * ); int (* LineCrossing)( AstFrame *, AstLineDef *, AstLineDef *, double **, int * ); int (* LineContains)( AstFrame *, AstLineDef *, int, double *, int * ); int (* Match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); int (* SubFrame)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); int (* TestDigits)( AstFrame *, int * ); int (* TestDirection)( AstFrame *, int, int * ); int (* TestDomain)( AstFrame *, int * ); int (* TestFormat)( AstFrame *, int, int * ); int (* TestLabel)( AstFrame *, int, int * ); int (* TestMatchEnd)( AstFrame *, int * ); int (* TestMaxAxes)( AstFrame *, int * ); int (* TestMinAxes)( AstFrame *, int * ); int (* TestPermute)( AstFrame *, int * ); int (* TestPreserveAxes)( AstFrame *, int * ); int (* TestSymbol)( AstFrame *, int, int * ); int (* TestTitle)( AstFrame *, int * ); int (* TestUnit)( AstFrame *, int, int * ); int (* Unformat)( AstFrame *, int, const char *, double *, int * ); int (* ValidateAxis)( AstFrame *, int, int, const char *, int * ); AstSystemType (* ValidateSystem)( AstFrame *, AstSystemType, const char *, int * ); AstSystemType (* SystemCode)( AstFrame *, const char *, int * ); const char *(* SystemString)( AstFrame *, AstSystemType, int * ); struct AstFrameSet *(* Convert)( AstFrame *, AstFrame *, const char *, int * ); struct AstFrameSet *(* ConvertX)( AstFrame *, AstFrame *, const char *, int * ); struct AstFrameSet *(* FindFrame)( AstFrame *, AstFrame *, const char *, int * ); void (* MatchAxes)( AstFrame *, AstFrame *, int[], int * ); void (* MatchAxesX)( AstFrame *, AstFrame *, int[], int * ); void (* CheckPerm)( AstFrame *, const int *, const char *, int * ); void (* ClearDigits)( AstFrame *, int * ); void (* ClearDirection)( AstFrame *, int, int * ); void (* ClearDomain)( AstFrame *, int * ); void (* ClearFormat)( AstFrame *, int, int * ); void (* ClearLabel)( AstFrame *, int, int * ); void (* ClearMatchEnd)( AstFrame *, int * ); void (* ClearMaxAxes)( AstFrame *, int * ); void (* ClearMinAxes)( AstFrame *, int * ); void (* ClearPermute)( AstFrame *, int * ); void (* ClearPreserveAxes)( AstFrame *, int * ); void (* ClearSymbol)( AstFrame *, int, int * ); void (* ClearTitle)( AstFrame *, int * ); void (* ClearUnit)( AstFrame *, int, int * ); void (* Intersect)( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * ); void (* Norm)( AstFrame *, double[], int * ); void (* NormBox)( AstFrame *, double *, double *, AstMapping *, int * ); void (* Offset)( AstFrame *, const double[], const double[], double, double[], int * ); double (* AxAngle)( AstFrame *, const double[2], const double[2], int, int * ); double (* Offset2)( AstFrame *, const double[2], double, double, double[2], int * ); void (* Overlay)( AstFrame *, const int *, AstFrame *, int * ); void (* PermAxes)( AstFrame *, const int[], int * ); void (* PrimaryFrame)( AstFrame *, int, AstFrame **, int *, int * ); void (* Resolve)( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); void (* SetAxis)( AstFrame *, int, AstAxis *, int * ); void (* SetDigits)( AstFrame *, int, int * ); void (* SetDirection)( AstFrame *, int, int, int * ); void (* SetDomain)( AstFrame *, const char *, int * ); void (* SetFormat)( AstFrame *, int, const char *, int * ); void (* SetLabel)( AstFrame *, int, const char *, int * ); void (* SetMatchEnd)( AstFrame *, int, int * ); void (* SetMaxAxes)( AstFrame *, int, int * ); void (* SetMinAxes)( AstFrame *, int, int * ); void (* SetPermute)( AstFrame *, int, int * ); void (* SetPreserveAxes)( AstFrame *, int, int * ); void (* SetSymbol)( AstFrame *, int, const char *, int * ); void (* SetTitle)( AstFrame *, const char *, int * ); void (* SetUnit)( AstFrame *, int, const char *, int * ); void (* ValidateAxisSelection)( AstFrame *, int, const int *, const char *, int * ); void (* LineOffset)( AstFrame *, AstLineDef *, double, double, double[2], int * ); AstPointSet *(* FrameGrid)( AstFrame *, int, const double *, const double *, int * ); struct AstFrameSet *(* GetFrameVariants)( AstFrame *, int * ); void (* SetFrameVariants)( AstFrame *, struct AstFrameSet *, int * ); double (* GetTop)( AstFrame *, int, int * ); int (* TestTop)( AstFrame *, int, int * ); void (* ClearTop)( AstFrame *, int, int * ); void (* SetTop)( AstFrame *, int, double, int * ); double (* GetBottom)( AstFrame *, int, int * ); int (* TestBottom)( AstFrame *, int, int * ); void (* ClearBottom)( AstFrame *, int, int * ); void (* SetBottom)( AstFrame *, int, double, int * ); AstSystemType (* GetSystem)( AstFrame *, int * ); int (* TestSystem)( AstFrame *, int * ); void (* ClearSystem)( AstFrame *, int * ); void (* SetSystem)( AstFrame *, AstSystemType, int * ); AstSystemType (* GetAlignSystem)( AstFrame *, int * ); int (* TestAlignSystem)( AstFrame *, int * ); void (* ClearAlignSystem)( AstFrame *, int * ); void (* SetAlignSystem)( AstFrame *, AstSystemType, int * ); double (* GetEpoch)( AstFrame *, int * ); int (* TestEpoch)( AstFrame *, int * ); void (* ClearEpoch)( AstFrame *, int * ); void (* SetEpoch)( AstFrame *, double, int * ); int (* TestActiveUnit)( AstFrame *, int * ); int (* GetActiveUnit)( AstFrame *, int * ); void (* SetActiveUnit)( AstFrame *, int, int * ); double (* GetObsLon)( AstFrame *, int * ); int (* TestObsLon)( AstFrame *, int * ); void (* ClearObsLon)( AstFrame *, int * ); void (* SetObsLon)( AstFrame *, double, int * ); double (* GetObsLat)( AstFrame *, int * ); int (* TestObsLat)( AstFrame *, int * ); void (* ClearObsLat)( AstFrame *, int * ); void (* SetObsLat)( AstFrame *, double, int * ); double (* GetObsAlt)( AstFrame *, int * ); int (* TestObsAlt)( AstFrame *, int * ); void (* ClearObsAlt)( AstFrame *, int * ); void (* SetObsAlt)( AstFrame *, double, int * ); double (* GetDut1)( AstFrame *, int * ); int (* TestDut1)( AstFrame *, int * ); void (* ClearDut1)( AstFrame *, int * ); void (* SetDut1)( AstFrame *, double, int * ); void (* SetFrameFlags)( AstFrame *, int, int * ); int (* GetFrameFlags)( AstFrame *, int * ); } AstFrameVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstFrameGlobals { AstFrameVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ AST__FRAME_GETATTRIB_BUFF_LEN + 1 ]; char *AstFormatID_Strings[ AST__FRAME_ASTFORMATID_MAX_STRINGS ]; int AstFormatID_Istr; int AstFormatID_Init; char Label_Buff[ AST__FRAME_LABEL_BUFF_LEN + 1 ]; char Symbol_Buff[ AST__FRAME_SYMBOL_BUFF_LEN + 1 ]; char Title_Buff[ AST__FRAME_TITLE_BUFF_LEN + 1 ]; char AstFmtDecimalYr_Buff[ AST__FRAME_ASTFMTDECIMALYR_BUFF_LEN + 1 ]; } AstFrameGlobals; #endif #endif /* More include files. */ /* =================== */ /* The interface to the FrameSet class must be included here (after the type definitions for the Frame class) because "frameset.h" itself includes this file ("frame.h"), although "frameset.h" refers to the AstFrameSet structure above. This seems a little strange at first, but is simply analogous to making a forward reference to a structure type when recursively defining a normal C structure (except that here the definitions happen to be in separate include files). */ #include "frameset.h" /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Frame) /* Check class membership */ astPROTO_ISA(Frame) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected */ AstFrame *astFrame_( int, const char *, int *, ...); #else AstFrame *astFrameId_( int, const char *, ... )__attribute__((format(printf,2,3))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstFrame *astInitFrame_( void *, size_t, int, AstFrameVtab *, const char *, int, int * ); /* Vtab initialiser. */ void astInitFrameVtab_( AstFrameVtab *, const char *, int * ); /* Loader. */ AstFrame *astLoadFrame_( void *, size_t, AstFrameVtab *, const char *, AstChannel *channel, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitFrameGlobals_( AstFrameGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ AstFrameSet *astConvert_( AstFrame *, AstFrame *, const char *, int * ); AstFrameSet *astFindFrame_( AstFrame *, AstFrame *, const char *, int * ); double astAngle_( AstFrame *, const double[], const double[], const double[], int * ); double astAxAngle_( AstFrame *, const double[2], const double[2], int, int * ); double astAxDistance_( AstFrame *, int, double, double, int * ); double astAxOffset_( AstFrame *, int, double, double, int * ); double astDistance_( AstFrame *, const double[], const double[], int * ); double astOffset2_( AstFrame *, const double[2], double, double, double[2], int * ); int astGetActiveUnit_( AstFrame *, int * ); void astIntersect_( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * ); void astMatchAxes_( AstFrame *, AstFrame *, int[], int * ); void astNorm_( AstFrame *, double[], int * ); void astOffset_( AstFrame *, const double[], const double[], double, double[], int * ); void astResolve_( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); void astSetActiveUnit_( AstFrame *, int, int * ); AstFrameSet *astGetFrameVariants_( AstFrame *, int * ); void astSetFrameVariants_( AstFrame *, AstFrameSet *, int * ); #if defined(astCLASS) /* Protected */ void astNormBox_( AstFrame *, double *, double *, AstMapping *, int * ); AstFrame *astPickAxes_( AstFrame *, int, const int[], AstMapping **, int * ); const char *astFormat_( AstFrame *, int, double, int * ); int astUnformat_( AstFrame *, int, const char *, double *, int * ); void astPermAxes_( AstFrame *, const int[], int * ); #else AstFrame *astPickAxesId_( AstFrame *, int, const int[], AstMapping **, int * ); const char *astFormatId_( AstFrame *, int, double, int * ); int astUnformatId_( AstFrame *, int, const char *, double *, int * ); void astPermAxesId_( AstFrame *, const int[], int * ); #endif #if defined(astCLASS) /* Protected */ int astAxIn_( AstFrame *, int, double, double, double, int, int * ); AstAxis * astGetAxis_( AstFrame *, int, int * ); AstFrameSet *astConvertX_( AstFrame *, AstFrame *, const char *, int * ); void astMatchAxesX_( AstFrame *, AstFrame *, int[], int * ); AstLineDef *astLineDef_( AstFrame *, const double[2], const double[2], int * ); AstPointSet *astResolvePoints_( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * ); const char *astAbbrev_( AstFrame *, int, const char *, const char *, const char *, int * ); const char *astGetDomain_( AstFrame *, int * ); const char *astGetFormat_( AstFrame *, int, int * ); const char *astGetLabel_( AstFrame *, int, int * ); const char *astGetSymbol_( AstFrame *, int, int * ); const char *astGetTitle_( AstFrame *, int * ); const char *astGetUnit_( AstFrame *, int, int * ); const char *astGetNormUnit_( AstFrame *, int, int * ); const int *astGetPerm_( AstFrame *, int * ); double astGap_( AstFrame *, int, double, int *, int * ); int astFields_( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * ); int astGetDigits_( AstFrame *, int * ); int astGetDirection_( AstFrame *, int, int * ); int astGetMatchEnd_( AstFrame *, int * ); int astGetMaxAxes_( AstFrame *, int * ); int astGetMinAxes_( AstFrame *, int * ); int astGetNaxes_( AstFrame *, int * ); int astGetPermute_( AstFrame *, int * ); int astGetPreserveAxes_( AstFrame *, int * ); int astIsUnitFrame_( AstFrame *, int * ); int astLineCrossing_( AstFrame *, AstLineDef *, AstLineDef *, double **, int * ); int astLineContains_( AstFrame *, AstLineDef *, int, double *, int * ); int astMatch_( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); int astSubFrame_( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); int astTestDigits_( AstFrame *, int * ); int astTestDirection_( AstFrame *, int, int * ); int astTestDomain_( AstFrame *, int * ); int astTestFormat_( AstFrame *, int, int * ); int astTestLabel_( AstFrame *, int, int * ); int astTestMatchEnd_( AstFrame *, int * ); int astTestMaxAxes_( AstFrame *, int * ); int astTestMinAxes_( AstFrame *, int * ); int astTestPermute_( AstFrame *, int * ); int astTestPreserveAxes_( AstFrame *, int * ); int astTestSymbol_( AstFrame *, int, int * ); int astTestTitle_( AstFrame *, int * ); int astTestUnit_( AstFrame *, int, int * ); int astValidateAxis_( AstFrame *, int, int, const char *, int * ); AstSystemType astValidateSystem_( AstFrame *, AstSystemType, const char *, int * ); AstSystemType astSystemCode_( AstFrame *, const char *, int * ); const char *astSystemString_( AstFrame *, AstSystemType, int * ); void astCheckPerm_( AstFrame *, const int *, const char *, int * ); void astClearDigits_( AstFrame *, int * ); void astClearDirection_( AstFrame *, int, int * ); void astClearDomain_( AstFrame *, int * ); void astClearFormat_( AstFrame *, int, int * ); void astClearLabel_( AstFrame *, int, int * ); void astClearMatchEnd_( AstFrame *, int * ); void astClearMaxAxes_( AstFrame *, int * ); void astClearMinAxes_( AstFrame *, int * ); void astClearPermute_( AstFrame *, int * ); void astClearPreserveAxes_( AstFrame *, int * ); void astClearSymbol_( AstFrame *, int, int * ); void astClearTitle_( AstFrame *, int * ); void astClearUnit_( AstFrame *, int, int * ); void astOverlay_( AstFrame *, const int *, AstFrame *, int * ); void astPrimaryFrame_( AstFrame *, int, AstFrame **, int *, int * ); void astSetAxis_( AstFrame *, int, AstAxis *, int * ); void astSetDigits_( AstFrame *, int, int * ); void astSetDirection_( AstFrame *, int, int, int * ); void astSetDomain_( AstFrame *, const char *, int * ); void astSetFormat_( AstFrame *, int, const char *, int * ); void astSetLabel_( AstFrame *, int, const char *, int * ); void astSetMatchEnd_( AstFrame *, int, int * ); void astSetMaxAxes_( AstFrame *, int, int * ); void astSetMinAxes_( AstFrame *, int, int * ); void astSetPermute_( AstFrame *, int, int * ); void astSetPreserveAxes_( AstFrame *, int, int * ); void astSetSymbol_( AstFrame *, int, const char *, int * ); void astSetTitle_( AstFrame *, const char *, int * ); void astSetUnit_( AstFrame *, int, const char *, int * ); void astValidateAxisSelection_( AstFrame *, int, const int *, const char *, int * ); double astReadDateTime_( const char *, int * ); const char *astFmtDecimalYr_( double, int, int * ); void astLineOffset_( AstFrame *, AstLineDef *, double, double, double[2], int * ); AstPointSet *astFrameGrid_( AstFrame *, int, const double *, const double *, int * ); double astGetTop_( AstFrame *, int, int * ); int astTestTop_( AstFrame *, int, int * ); void astClearTop_( AstFrame *, int, int * ); void astSetTop_( AstFrame *, int, double, int * ); double astGetBottom_( AstFrame *, int, int * ); int astTestBottom_( AstFrame *, int, int * ); void astClearBottom_( AstFrame *, int, int * ); void astSetBottom_( AstFrame *, int, double, int * ); AstSystemType astGetSystem_( AstFrame *, int * ); int astTestSystem_( AstFrame *, int * ); void astClearSystem_( AstFrame *, int * ); void astSetSystem_( AstFrame *, AstSystemType, int * ); AstSystemType astGetAlignSystem_( AstFrame *, int * ); int astTestAlignSystem_( AstFrame *, int * ); void astClearAlignSystem_( AstFrame *, int * ); void astSetAlignSystem_( AstFrame *, AstSystemType, int * ); double astGetEpoch_( AstFrame *, int * ); int astTestEpoch_( AstFrame *, int * ); void astClearEpoch_( AstFrame *, int * ); void astSetEpoch_( AstFrame *, double, int * ); double astGetObsLon_( AstFrame *, int * ); int astTestObsLon_( AstFrame *, int * ); void astClearObsLon_( AstFrame *, int * ); void astSetObsLon_( AstFrame *, double, int * ); double astGetObsLat_( AstFrame *, int * ); int astTestObsLat_( AstFrame *, int * ); void astClearObsLat_( AstFrame *, int * ); void astSetObsLat_( AstFrame *, double, int * ); double astGetObsAlt_( AstFrame *, int * ); int astTestObsAlt_( AstFrame *, int * ); void astClearObsAlt_( AstFrame *, int * ); void astSetObsAlt_( AstFrame *, double, int * ); double astGetDut1_( AstFrame *, int * ); int astTestDut1_( AstFrame *, int * ); void astClearDut1_( AstFrame *, int * ); void astSetDut1_( AstFrame *, double, int * ); int astTestActiveUnit_( AstFrame *, int * ); void astSetFrameFlags_( AstFrame *, int, int * ); int astGetFrameFlags_( AstFrame *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckFrame(this) astINVOKE_CHECK(Frame,this,0) #define astVerifyFrame(this) astINVOKE_CHECK(Frame,this,1) /* Test class membership. */ #define astIsAFrame(this) astINVOKE_ISA(Frame,this) /* Constructor. */ #if defined(astCLASS) /* Protected */ #define astFrame astINVOKE(F,astFrame_) #else #define astFrame astINVOKE(F,astFrameId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitFrame(mem,size,init,vtab,name,naxes) \ astINVOKE(O,astInitFrame_(mem,size,init,vtab,name,naxes,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitFrameVtab(vtab,name) astINVOKE(V,astInitFrameVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadFrame(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadFrame_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckFrame to validate Frame pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astConvert(from,to,domainlist) \ astINVOKE(O,astConvert_(astCheckFrame(from),astCheckFrame(to),domainlist,STATUS_PTR)) #define astAngle(this,a,b,c) \ astINVOKE(V,astAngle_(astCheckFrame(this),a,b,c,STATUS_PTR)) #define astDistance(this,point1,point2) \ astINVOKE(V,astDistance_(astCheckFrame(this),point1,point2,STATUS_PTR)) #define astFindFrame(target,template,domainlist) \ astINVOKE(O,astFindFrame_(astCheckFrame(target),astCheckFrame(template),domainlist,STATUS_PTR)) #define astMatchAxes(frm1,frm2,axes) \ astINVOKE(V,astMatchAxes_(astCheckFrame(frm1),astCheckFrame(frm2),axes,STATUS_PTR)) #define astNorm(this,value) \ astINVOKE(V,astNorm_(astCheckFrame(this),value,STATUS_PTR)) #define astAxDistance(this,axis,v1,v2) \ astINVOKE(V,astAxDistance_(astCheckFrame(this),axis,v1,v2,STATUS_PTR)) #define astAxOffset(this,axis,v1,dist) \ astINVOKE(V,astAxOffset_(astCheckFrame(this),axis,v1,dist,STATUS_PTR)) #define astOffset(this,point1,point2,offset,point3) \ astINVOKE(V,astOffset_(astCheckFrame(this),point1,point2,offset,point3,STATUS_PTR)) #define astAxAngle(this,a,b,axis) \ astINVOKE(V,astAxAngle_(astCheckFrame(this),a,b,axis,STATUS_PTR)) #define astIntersect(this,a1,a2,b1,b2,cross) \ astINVOKE(V,astIntersect_(astCheckFrame(this),a1,a2,b1,b2,cross,STATUS_PTR)) #define astOffset2(this,point1,angle,offset,point2) \ astINVOKE(V,astOffset2_(astCheckFrame(this),point1,angle,offset,point2,STATUS_PTR)) #define astResolve(this,point1,point2,point3,point4,d1,d2) \ astINVOKE(V,astResolve_(astCheckFrame(this),point1,point2,point3,point4,d1,d2,STATUS_PTR)) #define astGetActiveUnit(this) \ astINVOKE(V,astGetActiveUnit_(astCheckFrame(this),STATUS_PTR)) #define astSetActiveUnit(this,value) \ astINVOKE(V,astSetActiveUnit_(astCheckFrame(this),value,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astGetFrameVariants(this) \ astINVOKE(O,astGetFrameVariants_(astCheckFrame(this),STATUS_PTR)) #define astSetFrameVariants(this,variants) \ astINVOKE(V,astSetFrameVariants_(astCheckFrame(this),astCheckFrameSet(variants),STATUS_PTR)) #define astNormBox(this,lbnd,ubnd,reg) \ astINVOKE(V,astNormBox_(astCheckFrame(this),lbnd,ubnd,astCheckMapping(reg),STATUS_PTR)) #define astFormat(this,axis,value) \ astINVOKE(V,astFormat_(astCheckFrame(this),axis,value,STATUS_PTR)) #define astPermAxes(this,perm) \ astINVOKE(V,astPermAxes_(astCheckFrame(this),perm,STATUS_PTR)) #define astPickAxes(this,naxes,axes,map) \ astINVOKE(O,astPickAxes_(astCheckFrame(this),naxes,axes,(AstMapping **)(map),STATUS_PTR)) #define astUnformat(this,axis,string,value) \ astINVOKE(V,astUnformat_(astCheckFrame(this),axis,string,value,STATUS_PTR)) #else #define astFormat(this,axis,value) \ astINVOKE(V,astFormatId_(astCheckFrame(this),axis,value,STATUS_PTR)) #define astPermAxes(this,perm) \ astINVOKE(V,astPermAxesId_(astCheckFrame(this),perm,STATUS_PTR)) #define astPickAxes(this,naxes,axes,map) \ astINVOKE(O,astPickAxesId_(astCheckFrame(this),naxes,axes,(AstMapping **)(map),STATUS_PTR)) #define astUnformat(this,axis,string,value) \ astINVOKE(V,astUnformatId_(astCheckFrame(this),axis,string,value,STATUS_PTR)) #endif #if defined(astCLASS) /* Protected */ #define astAxIn(this,axis,lo,hi,val,closed) \ astINVOKE(V,astAxIn_(astCheckFrame(this),axis,lo,hi,val,closed,STATUS_PTR)) #define astAbbrev(this,axis,fmt,str1,str2) \ astINVOKE(V,astAbbrev_(astCheckFrame(this),axis,fmt,str1,str2,STATUS_PTR)) #define astFields(this,axis,fmt,str,maxfld,fields,nc,val) \ astINVOKE(V,astFields_(astCheckFrame(this),axis,fmt,str,maxfld,fields,nc,val,STATUS_PTR)) #define astCheckPerm(this,perm,method) \ astINVOKE(V,astCheckPerm_(astCheckFrame(this),perm,method,STATUS_PTR)) #define astResolvePoints(this,p1,p2,in,out) \ astINVOKE(O,astResolvePoints_(astCheckFrame(this),p1,p2,astCheckPointSet(in),((out)?astCheckPointSet(out):NULL),STATUS_PTR)) #define astLineDef(this,p1,p2) \ astINVOKE(V,astLineDef_(astCheckFrame(this),p1,p2,STATUS_PTR)) #define astLineOffset(this,line,par,prp,point) \ astINVOKE(V,astLineOffset_(astCheckFrame(this),line,par,prp,point,STATUS_PTR)) #define astFrameGrid(this,size,lbnd,ubnd) \ astINVOKE(O,astFrameGrid_(astCheckFrame(this),size,lbnd,ubnd,STATUS_PTR)) #define astLineCrossing(this,l1,l2,cross) \ astINVOKE(V,astLineCrossing_(astCheckFrame(this),l1,l2,cross,STATUS_PTR)) #define astLineContains(this,l,def,point) \ astINVOKE(V,astLineContains_(astCheckFrame(this),l,def,point,STATUS_PTR)) #define astClearDigits(this) \ astINVOKE(V,astClearDigits_(astCheckFrame(this),STATUS_PTR)) #define astClearDirection(this,axis) \ astINVOKE(V,astClearDirection_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearDomain(this) \ astINVOKE(V,astClearDomain_(astCheckFrame(this),STATUS_PTR)) #define astClearFormat(this,axis) \ astINVOKE(V,astClearFormat_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearLabel(this,axis) \ astINVOKE(V,astClearLabel_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearMatchEnd(this) \ astINVOKE(V,astClearMatchEnd_(astCheckFrame(this),STATUS_PTR)) #define astClearMaxAxes(this) \ astINVOKE(V,astClearMaxAxes_(astCheckFrame(this),STATUS_PTR)) #define astClearMinAxes(this) \ astINVOKE(V,astClearMinAxes_(astCheckFrame(this),STATUS_PTR)) #define astClearPermute(this) \ astINVOKE(V,astClearPermute_(astCheckFrame(this),STATUS_PTR)) #define astClearPreserveAxes(this) \ astINVOKE(V,astClearPreserveAxes_(astCheckFrame(this),STATUS_PTR)) #define astClearSymbol(this,axis) \ astINVOKE(V,astClearSymbol_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearTitle(this) \ astINVOKE(V,astClearTitle_(astCheckFrame(this),STATUS_PTR)) #define astClearUnit(this,axis) \ astINVOKE(V,astClearUnit_(astCheckFrame(this),axis,STATUS_PTR)) #define astConvertX(to,from,domainlist) \ astINVOKE(O,astConvertX_(astCheckFrame(to),astCheckFrame(from),domainlist,STATUS_PTR)) #define astGap(this,axis,gap,ntick) \ astINVOKE(V,astGap_(astCheckFrame(this),axis,gap,ntick,STATUS_PTR)) #define astGetAxis(this,axis) \ astINVOKE(O,astGetAxis_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetDigits(this) \ astINVOKE(V,astGetDigits_(astCheckFrame(this),STATUS_PTR)) #define astGetDirection(this,axis) \ astINVOKE(V,astGetDirection_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetDomain(this) \ astINVOKE(V,astGetDomain_(astCheckFrame(this),STATUS_PTR)) #define astGetFormat(this,axis) \ astINVOKE(V,astGetFormat_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetLabel(this,axis) \ astINVOKE(V,astGetLabel_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetMatchEnd(this) \ astINVOKE(V,astGetMatchEnd_(astCheckFrame(this),STATUS_PTR)) #define astGetMaxAxes(this) \ astINVOKE(V,astGetMaxAxes_(astCheckFrame(this),STATUS_PTR)) #define astGetMinAxes(this) \ astINVOKE(V,astGetMinAxes_(astCheckFrame(this),STATUS_PTR)) #define astGetNaxes(this) \ astINVOKE(V,astGetNaxes_(astCheckFrame(this),STATUS_PTR)) #define astGetPerm(this) \ astINVOKE(V,astGetPerm_(astCheckFrame(this),STATUS_PTR)) #define astGetPermute(this) \ astINVOKE(V,astGetPermute_(astCheckFrame(this),STATUS_PTR)) #define astGetPreserveAxes(this) \ astINVOKE(V,astGetPreserveAxes_(astCheckFrame(this),STATUS_PTR)) #define astGetSymbol(this,axis) \ astINVOKE(V,astGetSymbol_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetTitle(this) \ astINVOKE(V,astGetTitle_(astCheckFrame(this),STATUS_PTR)) #define astGetUnit(this,axis) \ astINVOKE(V,astGetUnit_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetNormUnit(this,axis) \ astINVOKE(V,astGetNormUnit_(astCheckFrame(this),axis,STATUS_PTR)) #define astMatch(template,target,matchsub,template_axes,target_axes,map,result) \ astINVOKE(V,astMatch_(astCheckFrame(template),astCheckFrame(target),matchsub,template_axes,target_axes,(AstMapping **)(map),(AstFrame **)(result),STATUS_PTR)) #define astIsUnitFrame(this) \ astINVOKE(V,astIsUnitFrame_(astCheckFrame(this),STATUS_PTR)) #define astOverlay(template,template_axes,result) \ astINVOKE(V,astOverlay_(astCheckFrame(template),template_axes,astCheckFrame(result),STATUS_PTR)) #define astPrimaryFrame(this,axis1,frame,axis2) \ astINVOKE(V,astPrimaryFrame_(astCheckFrame(this),axis1,(AstFrame **)(frame),axis2,STATUS_PTR)) #define astSetAxis(this,axis,newaxis) \ astINVOKE(V,astSetAxis_(astCheckFrame(this),axis,astCheckAxis(newaxis),STATUS_PTR)) #define astSetDigits(this,digits) \ astINVOKE(V,astSetDigits_(astCheckFrame(this),digits,STATUS_PTR)) #define astSetDirection(this,axis,direction) \ astINVOKE(V,astSetDirection_(astCheckFrame(this),axis,direction,STATUS_PTR)) #define astSetDomain(this,domain) \ astINVOKE(V,astSetDomain_(astCheckFrame(this),domain,STATUS_PTR)) #define astSetFormat(this,axis,format) \ astINVOKE(V,astSetFormat_(astCheckFrame(this),axis,format,STATUS_PTR)) #define astSetLabel(this,axis,label) \ astINVOKE(V,astSetLabel_(astCheckFrame(this),axis,label,STATUS_PTR)) #define astSetMatchEnd(this,value) \ astINVOKE(V,astSetMatchEnd_(astCheckFrame(this),value,STATUS_PTR)) #define astSetMaxAxes(this,value) \ astINVOKE(V,astSetMaxAxes_(astCheckFrame(this),value,STATUS_PTR)) #define astSetMinAxes(this,value) \ astINVOKE(V,astSetMinAxes_(astCheckFrame(this),value,STATUS_PTR)) #define astSetPermute(this,value) \ astINVOKE(V,astSetPermute_(astCheckFrame(this),value,STATUS_PTR)) #define astSetPreserveAxes(this,value) \ astINVOKE(V,astSetPreserveAxes_(astCheckFrame(this),value,STATUS_PTR)) #define astSetSymbol(this,axis,symbol) \ astINVOKE(V,astSetSymbol_(astCheckFrame(this),axis,symbol,STATUS_PTR)) #define astSetTitle(this,title) \ astINVOKE(V,astSetTitle_(astCheckFrame(this),title,STATUS_PTR)) #define astSetUnit(this,axis,unit) \ astINVOKE(V,astSetUnit_(astCheckFrame(this),axis,unit,STATUS_PTR)) #define astSubFrame(target,template,result_naxes,target_axes,template_axes,map,result) \ astINVOKE(V,astSubFrame_(astCheckFrame(target),template?astCheckFrame(template):NULL,result_naxes,target_axes,template_axes,(AstMapping **)(map),(AstFrame **)(result),STATUS_PTR)) #define astTestDigits(this) \ astINVOKE(V,astTestDigits_(astCheckFrame(this),STATUS_PTR)) #define astTestDirection(this,axis) \ astINVOKE(V,astTestDirection_(astCheckFrame(this),axis,STATUS_PTR)) #define astTestDomain(this) \ astINVOKE(V,astTestDomain_(astCheckFrame(this),STATUS_PTR)) #define astTestFormat(this,axis) \ astINVOKE(V,astTestFormat_(astCheckFrame(this),axis,STATUS_PTR)) #define astTestLabel(this,axis) \ astINVOKE(V,astTestLabel_(astCheckFrame(this),axis,STATUS_PTR)) #define astTestMatchEnd(this) \ astINVOKE(V,astTestMatchEnd_(astCheckFrame(this),STATUS_PTR)) #define astTestMaxAxes(this) \ astINVOKE(V,astTestMaxAxes_(astCheckFrame(this),STATUS_PTR)) #define astTestMinAxes(this) \ astINVOKE(V,astTestMinAxes_(astCheckFrame(this),STATUS_PTR)) #define astTestPermute(this) \ astINVOKE(V,astTestPermute_(astCheckFrame(this),STATUS_PTR)) #define astTestPreserveAxes(this) \ astINVOKE(V,astTestPreserveAxes_(astCheckFrame(this),STATUS_PTR)) #define astTestSymbol(this,axis) \ astINVOKE(V,astTestSymbol_(astCheckFrame(this),axis,STATUS_PTR)) #define astTestTitle(this) \ astINVOKE(V,astTestTitle_(astCheckFrame(this),STATUS_PTR)) #define astTestUnit(this,axis) \ astINVOKE(V,astTestUnit_(astCheckFrame(this),axis,STATUS_PTR)) #define astValidateAxis(this,axis,fwd,method) \ astINVOKE(V,astValidateAxis_(astCheckFrame(this),axis,fwd,method,STATUS_PTR)) #define astValidateAxisSelection(this,naxes,axes,method) \ astINVOKE(V,astValidateAxisSelection_(astCheckFrame(this),naxes,axes,method,STATUS_PTR)) #define astMatchAxesX(frm2,frm1,axes) \ astINVOKE(V,astMatchAxesX_(astCheckFrame(frm2),astCheckFrame(frm1),axes,STATUS_PTR)) #define astFmtDecimalYr(year,digits) astFmtDecimalYr_(year,digits,STATUS_PTR) #define astReadDateTime(value) astReadDateTime_(value,STATUS_PTR) #define astValidateSystem(this,system,method) \ astINVOKE(V,astValidateSystem_(astCheckFrame(this),system,method,STATUS_PTR)) #define astSystemString(this,system) \ astINVOKE(V,astSystemString_(astCheckFrame(this),system,STATUS_PTR)) #define astSystemCode(this,system) \ astINVOKE(V,astSystemCode_(astCheckFrame(this),system,STATUS_PTR)) #define astClearTop(this,axis) \ astINVOKE(V,astClearTop_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetTop(this,axis) \ astINVOKE(V,astGetTop_(astCheckFrame(this),axis,STATUS_PTR)) #define astSetTop(this,axis,value) \ astINVOKE(V,astSetTop_(astCheckFrame(this),axis,value,STATUS_PTR)) #define astTestTop(this,axis) \ astINVOKE(V,astTestTop_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearBottom(this,axis) \ astINVOKE(V,astClearBottom_(astCheckFrame(this),axis,STATUS_PTR)) #define astGetBottom(this,axis) \ astINVOKE(V,astGetBottom_(astCheckFrame(this),axis,STATUS_PTR)) #define astSetBottom(this,axis,value) \ astINVOKE(V,astSetBottom_(astCheckFrame(this),axis,value,STATUS_PTR)) #define astTestBottom(this,axis) \ astINVOKE(V,astTestBottom_(astCheckFrame(this),axis,STATUS_PTR)) #define astClearSystem(this) \ astINVOKE(V,astClearSystem_(astCheckFrame(this),STATUS_PTR)) #define astGetSystem(this) \ astINVOKE(V,astGetSystem_(astCheckFrame(this),STATUS_PTR)) #define astSetSystem(this,value) \ astINVOKE(V,astSetSystem_(astCheckFrame(this),value,STATUS_PTR)) #define astTestSystem(this) \ astINVOKE(V,astTestSystem_(astCheckFrame(this),STATUS_PTR)) #define astClearAlignSystem(this) \ astINVOKE(V,astClearAlignSystem_(astCheckFrame(this),STATUS_PTR)) #define astGetAlignSystem(this) \ astINVOKE(V,astGetAlignSystem_(astCheckFrame(this),STATUS_PTR)) #define astSetAlignSystem(this,value) \ astINVOKE(V,astSetAlignSystem_(astCheckFrame(this),value,STATUS_PTR)) #define astTestAlignSystem(this) \ astINVOKE(V,astTestAlignSystem_(astCheckFrame(this),STATUS_PTR)) #define astClearEpoch(this) \ astINVOKE(V,astClearEpoch_(astCheckFrame(this),STATUS_PTR)) #define astGetEpoch(this) \ astINVOKE(V,astGetEpoch_(astCheckFrame(this),STATUS_PTR)) #define astSetEpoch(this,value) \ astINVOKE(V,astSetEpoch_(astCheckFrame(this),value,STATUS_PTR)) #define astTestEpoch(this) \ astINVOKE(V,astTestEpoch_(astCheckFrame(this),STATUS_PTR)) #define astGetObsLon(this) \ astINVOKE(V,astGetObsLon_(astCheckFrame(this),STATUS_PTR)) #define astTestObsLon(this) \ astINVOKE(V,astTestObsLon_(astCheckFrame(this),STATUS_PTR)) #define astClearObsLon(this) \ astINVOKE(V,astClearObsLon_(astCheckFrame(this),STATUS_PTR)) #define astSetObsLon(this,value) \ astINVOKE(V,astSetObsLon_(astCheckFrame(this),value,STATUS_PTR)) #define astGetObsLat(this) \ astINVOKE(V,astGetObsLat_(astCheckFrame(this),STATUS_PTR)) #define astTestObsLat(this) \ astINVOKE(V,astTestObsLat_(astCheckFrame(this),STATUS_PTR)) #define astClearObsLat(this) \ astINVOKE(V,astClearObsLat_(astCheckFrame(this),STATUS_PTR)) #define astSetObsLat(this,value) \ astINVOKE(V,astSetObsLat_(astCheckFrame(this),value,STATUS_PTR)) #define astGetObsAlt(this) \ astINVOKE(V,astGetObsAlt_(astCheckFrame(this),STATUS_PTR)) #define astTestObsAlt(this) \ astINVOKE(V,astTestObsAlt_(astCheckFrame(this),STATUS_PTR)) #define astClearObsAlt(this) \ astINVOKE(V,astClearObsAlt_(astCheckFrame(this),STATUS_PTR)) #define astSetObsAlt(this,value) \ astINVOKE(V,astSetObsAlt_(astCheckFrame(this),value,STATUS_PTR)) #define astClearDut1(this) \ astINVOKE(V,astClearDut1_(astCheckFrame(this),STATUS_PTR)) #define astGetDut1(this) \ astINVOKE(V,astGetDut1_(astCheckFrame(this),STATUS_PTR)) #define astSetDut1(this,value) \ astINVOKE(V,astSetDut1_(astCheckFrame(this),value,STATUS_PTR)) #define astTestDut1(this) \ astINVOKE(V,astTestDut1_(astCheckFrame(this),STATUS_PTR)) #define astTestActiveUnit(this) \ astINVOKE(V,astTestActiveUnit_(astCheckFrame(this),STATUS_PTR)) #define astSetFrameFlags(this,flags) \ astINVOKE(V,astSetFrameFlags_(astCheckFrame(this),flags,STATUS_PTR)) #define astGetFrameFlags(this) \ astINVOKE(V,astGetFrameFlags_(astCheckFrame(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/AST_ERR0000644000175000017500000004050712262533710012227 0ustar olesoles* FORTRAN error include file for facility AST (Code 1521) * Generated by the MESSGEN utility * attribute getting error INTEGER AST__ATGER PARAMETER ( AST__ATGER = 233933154 ) * attribute setting error INTEGER AST__ATSER PARAMETER ( AST__ATSER = 233933162 ) * attribute value invalid INTEGER AST__ATTIN PARAMETER ( AST__ATTIN = 233933170 ) * axis index invalid INTEGER AST__AXIIN PARAMETER ( AST__AXIIN = 233933178 ) * bad attribute name INTEGER AST__BADAT PARAMETER ( AST__BADAT = 233933186 ) * zero-sized box given INTEGER AST__BADBX PARAMETER ( AST__BADBX = 233933194 ) * bad input data INTEGER AST__BADIN PARAMETER ( AST__BADIN = 233933202 ) * bad number of input coordinates INTEGER AST__BADNI PARAMETER ( AST__BADNI = 233933210 ) * bad number of output coordinates INTEGER AST__BADNO PARAMETER ( AST__BADNO = 233933218 ) * PolyMap contains illegal power value INTEGER AST__BADPW PARAMETER ( AST__BADPW = 233933226 ) * ShiftMap contains no shift information INTEGER AST__BADSM PARAMETER ( AST__BADSM = 233933234 ) * WinMap contains no bounds information INTEGER AST__BADWM PARAMETER ( AST__BADWM = 233933242 ) * bad break index INTEGER AST__BDBRK PARAMETER ( AST__BDBRK = 233933250 ) * bad field specifier INTEGER AST__BDFMT PARAMETER ( AST__BDFMT = 233933258 ) * invalid FITS keyword value found INTEGER AST__BDFTS PARAMETER ( AST__BDFTS = 233933266 ) * inappropriate Object supplied INTEGER AST__BDOBJ PARAMETER ( AST__BDOBJ = 233933274 ) * wrong number of clipping axes INTEGER AST__CLPAX PARAMETER ( AST__CLPAX = 233933282 ) * range of coordinates invalid INTEGER AST__CORNG PARAMETER ( AST__CORNG = 233933290 ) * too many breaks in a curve INTEGER AST__CVBRK PARAMETER ( AST__CVBRK = 233933298 ) * array dimensions invalid INTEGER AST__DIMIN PARAMETER ( AST__DIMIN = 233933306 ) * date/time error INTEGER AST__DTERR PARAMETER ( AST__DTERR = 233933314 ) * invalid use of astEnd INTEGER AST__ENDIN PARAMETER ( AST__ENDIN = 233933322 ) * end of input Channel encountered INTEGER AST__EOCHN PARAMETER ( AST__EOCHN = 233933330 ) * attempt to export Object pointer from level zero INTEGER AST__EXPIN PARAMETER ( AST__EXPIN = 233933338 ) * corrupted FitsChan supplied INTEGER AST__FCRPT PARAMETER ( AST__FCRPT = 233933346 ) * error while formatting coordinate value INTEGER AST__FMTER PARAMETER ( AST__FMTER = 233933354 ) * Frame index invalid INTEGER AST__FRMIN PARAMETER ( AST__FRMIN = 233933362 ) * FrameSet invalid INTEGER AST__FRSIN PARAMETER ( AST__FRSIN = 233933370 ) * cannot convert FITS data value type INTEGER AST__FTCNV PARAMETER ( AST__FTCNV = 233933378 ) * low level graphics error INTEGER AST__GRFER PARAMETER ( AST__GRFER = 233933386 ) * invalid Handle INTEGER AST__INHAN PARAMETER ( AST__INHAN = 233933394 ) * incompatible numbers of coordinates INTEGER AST__INNCO PARAMETER ( AST__INNCO = 233933402 ) * internal programming error INTEGER AST__INTER PARAMETER ( AST__INTER = 233933410 ) * incompatible transformation directions INTEGER AST__INTRD PARAMETER ( AST__INTRD = 233933418 ) * circular dependency between KeyMaps INTEGER AST__KYCIR PARAMETER ( AST__KYCIR = 233933426 ) * class loader error INTEGER AST__LDERR PARAMETER ( AST__LDERR = 233933434 ) * invalid lookup table increment INTEGER AST__LUTII PARAMETER ( AST__LUTII = 233933442 ) * invalid number of lookup table elements INTEGER AST__LUTIN PARAMETER ( AST__LUTIN = 233933450 ) * requested memory size invalid INTEGER AST__MEMIN PARAMETER ( AST__MEMIN = 233933458 ) * not a 2d or 3d MatrixMap INTEGER AST__MTR23 PARAMETER ( AST__MTR23 = 233933466 ) * null rotation axis supplied INTEGER AST__MTRAX PARAMETER ( AST__MTRAX = 233933474 ) * bad matrix shapes for multiplication INTEGER AST__MTRML PARAMETER ( AST__MTRML = 233933482 ) * null matrix supplied INTEGER AST__MTRMT PARAMETER ( AST__MTRMT = 233933490 ) * number of axes invalid INTEGER AST__NAXIN PARAMETER ( AST__NAXIN = 233933498 ) * number of characters invalid INTEGER AST__NCHIN PARAMETER ( AST__NCHIN = 233933506 ) * number of coordinates invalid INTEGER AST__NCOIN PARAMETER ( AST__NCOIN = 233933514 ) * number of coordinates per point invalid INTEGER AST__NCPIN PARAMETER ( AST__NCPIN = 233933522 ) * number of array elements invalid INTEGER AST__NELIN PARAMETER ( AST__NELIN = 233933530 ) * number of output coordinates too small INTEGER AST__NOCTS PARAMETER ( AST__NOCTS = 233933538 ) * transformation not defined INTEGER AST__NODEF PARAMETER ( AST__NODEF = 233933546 ) * required FITS keywords missing INTEGER AST__NOFTS PARAMETER ( AST__NOFTS = 233933554 ) * unable to allocate memory INTEGER AST__NOMEM PARAMETER ( AST__NOMEM = 233933562 ) * number of output points too small INTEGER AST__NOPTS PARAMETER ( AST__NOPTS = 233933570 ) * attribute is read-only INTEGER AST__NOWRT PARAMETER ( AST__NOWRT = 233933578 ) * number of points invalid INTEGER AST__NPTIN PARAMETER ( AST__NPTIN = 233933586 ) * Object invalid INTEGER AST__OBJIN PARAMETER ( AST__OBJIN = 233933594 ) * invalid Plot option INTEGER AST__OPT PARAMETER ( AST__OPT = 233933602 ) * points data structure invalid INTEGER AST__PDSIN PARAMETER ( AST__PDSIN = 233933610 ) * no numerical labels can be produced INTEGER AST__PLFMT PARAMETER ( AST__PLFMT = 233933618 ) * permutation invalid INTEGER AST__PRMIN PARAMETER ( AST__PRMIN = 233933626 ) * pointer invalid INTEGER AST__PTRIN PARAMETER ( AST__PTRIN = 233933634 ) * range of points invalid INTEGER AST__PTRNG PARAMETER ( AST__PTRNG = 233933642 ) * read error INTEGER AST__RDERR PARAMETER ( AST__RDERR = 233933650 ) * invalid or corrupted Region structure supplied INTEGER AST__REGIN PARAMETER ( AST__REGIN = 233933658 ) * invalid attempt to remove last Frame INTEGER AST__REMIN PARAMETER ( AST__REMIN = 233933666 ) * sky coordinate system invalid INTEGER AST__SCSIN PARAMETER ( AST__SCSIN = 233933674 ) * axis selection invalid INTEGER AST__SELIN PARAMETER ( AST__SELIN = 233933682 ) * bad SLALIB transformation type INTEGER AST__SLAIN PARAMETER ( AST__SLAIN = 233933690 ) * coordinate transformation not defined INTEGER AST__TRNND PARAMETER ( AST__TRNND = 233933698 ) * unmatched quotes INTEGER AST__UNMQT PARAMETER ( AST__UNMQT = 233933706 ) * valid area too small INTEGER AST__VSMAL PARAMETER ( AST__VSMAL = 233933714 ) * non-existent longitude or latitude axis INTEGER AST__WCSAX PARAMETER ( AST__WCSAX = 233933722 ) * too few mapping coordinates INTEGER AST__WCSNC PARAMETER ( AST__WCSNC = 233933730 ) * invalid projection parameters INTEGER AST__WCSPA PARAMETER ( AST__WCSPA = 233933738 ) * unknown projection type INTEGER AST__WCSTY PARAMETER ( AST__WCSTY = 233933746 ) * too many Objects in use at once INTEGER AST__XSOBJ PARAMETER ( AST__XSOBJ = 233933754 ) * zoom factor invalid INTEGER AST__ZOOMI PARAMETER ( AST__ZOOMI = 233933762 ) * bad coordinate index INTEGER AST__BADCI PARAMETER ( AST__BADCI = 233933770 ) * FrameSet integrity lost INTEGER AST__ILOST PARAMETER ( AST__ILOST = 233933778 ) * error in IntraMap transformation function INTEGER AST__ITFER PARAMETER ( AST__ITFER = 233933786 ) * IntraMap transformation function name invalid INTEGER AST__ITFNI PARAMETER ( AST__ITFNI = 233933794 ) * Mapping bounding box not found INTEGER AST__MBBNF PARAMETER ( AST__MBBNF = 233933802 ) * multiple registration of IntraMap transformation function INTEGER AST__MRITF PARAMETER ( AST__MRITF = 233933810 ) * Object class unknown INTEGER AST__OCLUK PARAMETER ( AST__OCLUK = 233933818 ) * error while unformatting a coordinate value INTEGER AST__UNFER PARAMETER ( AST__UNFER = 233933826 ) * unregistered IntraMap transformation function INTEGER AST__URITF PARAMETER ( AST__URITF = 233933834 ) * grid bounds invalid INTEGER AST__GBDIN PARAMETER ( AST__GBDIN = 233933842 ) * number of grid dimensions invalid INTEGER AST__NGDIN PARAMETER ( AST__NGDIN = 233933850 ) * positional accuracy tolerance invalid INTEGER AST__PATIN PARAMETER ( AST__PATIN = 233933858 ) * sub-pixel interpolation scheme invalid INTEGER AST__SISIN PARAMETER ( AST__SISIN = 233933866 ) * scale size in pixels invalid INTEGER AST__SSPIN PARAMETER ( AST__SSPIN = 233933874 ) * error in user-supplied sub-pixel interpolation function INTEGER AST__UINER PARAMETER ( AST__UINER = 233933882 ) * error in user-supplied 1-d sub-pixel interpolation kernel INTEGER AST__UK1ER PARAMETER ( AST__UK1ER = 233933890 ) * invalid comma in expression INTEGER AST__COMIN PARAMETER ( AST__COMIN = 233933898 ) * invalid constant in expression INTEGER AST__CONIN PARAMETER ( AST__CONIN = 233933906 ) * duplicate variable name INTEGER AST__DUVAR PARAMETER ( AST__DUVAR = 233933914 ) * invalid number of transformation functions INTEGER AST__INNTF PARAMETER ( AST__INNTF = 233933922 ) * missing or invalid operand in expression INTEGER AST__MIOPA PARAMETER ( AST__MIOPA = 233933930 ) * missing or invalid operator in expression INTEGER AST__MIOPR PARAMETER ( AST__MIOPR = 233933938 ) * missing variable name INTEGER AST__MISVN PARAMETER ( AST__MISVN = 233933946 ) * missing left parenthesis in expression INTEGER AST__MLPAR PARAMETER ( AST__MLPAR = 233933954 ) * missing right parenthesis in expression INTEGER AST__MRPAR PARAMETER ( AST__MRPAR = 233933962 ) * missing right hand side in function INTEGER AST__NORHS PARAMETER ( AST__NORHS = 233933970 ) * undefined variable or function in expression INTEGER AST__UDVOF PARAMETER ( AST__UDVOF = 233933978 ) * variable name invalid INTEGER AST__VARIN PARAMETER ( AST__VARIN = 233933986 ) * wrong number of function arguments in expression INTEGER AST__WRNFA PARAMETER ( AST__WRNFA = 233933994 ) * invalid units specification INTEGER AST__BADUN PARAMETER ( AST__BADUN = 233934002 ) * no rest frequency is defined INTEGER AST__NORSF PARAMETER ( AST__NORSF = 233934010 ) * no standard of rest is defined INTEGER AST__NOSOR PARAMETER ( AST__NOSOR = 233934018 ) * invalid SpecMap INTEGER AST__SPCIN PARAMETER ( AST__SPCIN = 233934026 ) * invalid XML name or prefix INTEGER AST__XMLNM PARAMETER ( AST__XMLNM = 233934034 ) * invalid XML comment text INTEGER AST__XMLCM PARAMETER ( AST__XMLCM = 233934042 ) * invalid XML processing instruction target text INTEGER AST__XMLPT PARAMETER ( AST__XMLPT = 233934050 ) * invalid XML content item index INTEGER AST__XMLIT PARAMETER ( AST__XMLIT = 233934058 ) * supplied XML document is not well formed INTEGER AST__XMLWF PARAMETER ( AST__XMLWF = 233934066 ) * Range of log axis scale includes zero INTEGER AST__ZERAX PARAMETER ( AST__ZERAX = 233934074 ) * Invalid parameters for offset sky coordinate system INTEGER AST__BADOC PARAMETER ( AST__BADOC = 233934082 ) * error getting a named value from a KeyMap INTEGER AST__MPGER PARAMETER ( AST__MPGER = 233934090 ) * invalid integer index supplied for a KeyMap entry INTEGER AST__MPIND PARAMETER ( AST__MPIND = 233934098 ) * region cannot be re-centred INTEGER AST__REGCN PARAMETER ( AST__REGCN = 233934106 ) * attribute has no usable value INTEGER AST__NOVAL PARAMETER ( AST__NOVAL = 233934114 ) * incompatible time scales INTEGER AST__INCTS PARAMETER ( AST__INCTS = 233934122 ) * invalid TimeMap INTEGER AST__TIMIN PARAMETER ( AST__TIMIN = 233934130 ) * cannot use supplied AstroCoords info INTEGER AST__STCKEY PARAMETER ( AST__STCKEY = 233934138 ) * invalid AstroCoords index INTEGER AST__STCIND PARAMETER ( AST__STCIND = 233934146 ) * cannot conserve flux whilst resampling an array of data INTEGER AST__CNFLX PARAMETER ( AST__CNFLX = 233934154 ) * Unknown AST tuning parameter name supplied INTEGER AST__TUNAM PARAMETER ( AST__TUNAM = 233934162 ) * Bad value supplied for a public function parameter INTEGER AST__BDPAR PARAMETER ( AST__BDPAR = 233934170 ) * Supplied FrameSet does not contain any independent axes INTEGER AST__3DFSET PARAMETER ( AST__3DFSET = 233934178 ) * Attempt to delete original Plot3D base Frame INTEGER AST__PXFRRM PARAMETER ( AST__PXFRRM = 233934186 ) * Illegal syntax for string substitution template INTEGER AST__BADSUB PARAMETER ( AST__BADSUB = 233934194 ) * Incompatible flags for re-sampling or re-binning INTEGER AST__BADFLG PARAMETER ( AST__BADFLG = 233934202 ) * Error locking or unlocking an AST Object INTEGER AST__LCKERR PARAMETER ( AST__LCKERR = 233934210 ) * FITS keyword had undefined value INTEGER AST__FUNDEF PARAMETER ( AST__FUNDEF = 233934218 ) * invalid integer index supplied for a KeyMap vector element INTEGER AST__MPVIN PARAMETER ( AST__MPVIN = 233934226 ) * operation specifier invalid INTEGER AST__OPRIN PARAMETER ( AST__OPRIN = 233934234 ) * no inside point found INTEGER AST__NONIN PARAMETER ( AST__NONIN = 233934242 ) * requested key not found in KeyMap INTEGER AST__MPKER PARAMETER ( AST__MPKER = 233934250 ) * error putting a named value into a KeyMap INTEGER AST__MPPER PARAMETER ( AST__MPPER = 233934258 ) * Attempt made to add an entry to a locked KeyMap INTEGER AST__BADKEY PARAMETER ( AST__BADKEY = 233934266 ) * Bad data type INTEGER AST__BADTYP PARAMETER ( AST__BADTYP = 233934274 ) * Column already exists with different properties INTEGER AST__OLDCOL PARAMETER ( AST__OLDCOL = 233934282 ) * Bad null value for a FITS table column INTEGER AST__BADNULL PARAMETER ( AST__BADNULL = 233934290 ) * Key string is too long INTEGER AST__BIGKEY PARAMETER ( AST__BIGKEY = 233934298 ) * No such column exists in the table INTEGER AST__BADCOL PARAMETER ( AST__BADCOL = 233934306 ) * Table is too large INTEGER AST__BIGTAB PARAMETER ( AST__BIGTAB = 233934314 ) * Invalid array size INTEGER AST__BADSIZ PARAMETER ( AST__BADSIZ = 233934322 ) * Error reading WCS from FITS binary table INTEGER AST__BADTAB PARAMETER ( AST__BADTAB = 233934330 ) * Cannot access FITS binary table INTEGER AST__NOTAB PARAMETER ( AST__NOTAB = 233934338 ) * Error in levmar Levenberg-Marquardt code INTEGER AST__LEVMAR PARAMETER ( AST__LEVMAR = 233934346 ) * Fit failed INTEGER AST__NOFIT PARAMETER ( AST__NOFIT = 233934354 ) * A transformation generated one or more NaN values INTEGER AST__ISNAN PARAMETER ( AST__ISNAN = 233934362 ) * write error INTEGER AST__WRERR PARAMETER ( AST__WRERR = 233934370 ) * Bad variant Mapping name INTEGER AST__BDVNM PARAMETER ( AST__BDVNM = 233934378 ) * Attempt to add a variant Mapping to a mirror Frame INTEGER AST__MIRRO PARAMETER ( AST__MIRRO = 233934386 ) ./ast-7.3.3/unit.c0000644000175000017500000061231312262533650012273 0ustar olesoles/* * Name: * unit.c * Purpose: * Implement unit conversion functions. * Description: * This file implements the Unit module which is used for identifying * units and transforming between them. It follows the recommendations * for unit handling contained within FITS WCS paper I (Greisen & * Calabretta). All methods have protected access. * Methods: * astUnitMapper: Create a Mapping between two systems of units. * astUnitLabel: Returns a label for a given unit symbol. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 10-DEC-2002 (DSB): * Original version. * 10-FEB-2004 (DSB): * Added debug conditional code to keep track of memory leaks. * 15-JUL-2004 (DSB): * In astUnitMapper: if no Mapping can be found from input to * output units (e.g. because fo the less than perfect simplication * algorithm in SimplifyTree), try finding a Mapping from output to * input units and inverting the result. * 14-DEC-2004 (DSB): * In CreateTree, move the invocation of FixConstants from after * InvertConstants to before InvertConstants. This is because * InvertConstants ignores nodes which contain all constant * arguments. This results in constants not being inverted in * expressions such as "1/60 deg" (because all arguments are * constant in the the "1/60" node). * 18-JAN-2005 (DSB): * Fix memory leaks. * 2-FEB-2005 (DSB): * - Avoid using astStore to allocate more storage than is supplied * in the "data" pointer. This can cause access violations since * astStore will then read beyond the end of the "data" area. * 15-FEB-2005 (DSB): * - Modified CleanExp to fix up some common units mistakes. * 21-FEB-2005 (DSB): * - Modified CleanExp to accept as equivalent to * ^. * - Modified MakeTree to do case insensitive checking if case * sensitive checking failsto produce a match to a multiplier/unit * symbol combination. If this still produces no match, do a case * insensitive match for multiplier/unit label. * 1-MAR-2006 (DSB): * Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM. * 6-APR-2006 (DSB): * Modify CleanExp to convert "MJY/STER" to standard form ("MJy/sr"). * 7-JUL-2006 (DSB): * Correct initialisation of "word" flag in CleanExp. * 17-MAY-2007 (DSB): * Simplify the units string returned by astUnitNormaliser. * - Fix indexing bug in CombineFactors. * 26-MAY-2007 (DSB): * - Correct error reporting in astUNitNormaliser. * - Fix bug in CleanExp that caused (for example) "-2" to be * converted to "^-2". * 2-DEC-2008 (DSB): * Correct memory allocation bug in CleanExp. * 6-MAY-2011 (DSB): * Include "adu" as basic unit. * 9-MAY-2011 (DSB): * Change "A" to be Ampere (as defined by FITS-WCS paper 1) rather * than "Angstrom". */ /* Module Macros. */ /* ============== */ /* Define the astCLASS macro (even although this is not a class implementation) to obtain access to the protected error and memory handling functions. */ #define astCLASS #define PI 3.141592653589793 #define E 2.718281828459045 /* Macro which returns the nearest integer to a given floating point value. */ #define NINT(x) (int)((x)+(((x)>0.0)?0.5:-0.5)) /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Macro identifying a character as lower or upper case letter, digit or + or -. */ #define ISWORD(c) (isalnum(c)||((c)=='+')||((c)=='-')) /* The number of basic dimension quantities used for dimensional analysis. In addition to the usual M, L and T, this includes pseudo-dimensions describing strictly dimensionless quantities such as plane angle, magnitude, etc. */ #define NQUANT 10 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "error.h" #include "memory.h" #include "pointset.h" #include "mapping.h" #include "unitmap.h" #include "zoommap.h" #include "mathmap.h" #include "unit.h" /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #ifdef THREAD_SAFE #include #endif /* Module Type Definitions. */ /* ======================== */ /* This declaration enumerates the codes for the operations which may legally be included in a units expression. */ typedef enum { OP_LDCON, /* Load constant */ OP_LDVAR, /* Load variable */ OP_LOG, /* Common logarithm */ OP_LN, /* Natural logarithm */ OP_EXP, /* Natural exponential */ OP_SQRT, /* Square root */ OP_POW, /* Exponentiate */ OP_DIV, /* Division */ OP_MULT, /* Multiplication */ OP_LDPI, /* Load constant PI */ OP_LDE, /* Load constant E */ OP_NULL /* Null operation */ } Oper; /* A structure describing a standard multiplier prefix. */ typedef struct Multiplier { const char *label; /* Multipler label string (null terminated) */ const char *sym; /* Multipler symbol string (null terminated) */ int symlen; /* Length of symbol (without trailing null ) */ int lablen; /* Length of label (without trailing null ) */ double scale; /* The scale factor associated with the prefix */ struct Multiplier *next; /* Next Multiplier in linked list */ } Multiplier; /* A structure describing a single node in a tree representation of a single units expression. */ typedef struct UnitNode { Oper opcode; /* Code for operation performed by this node */ int narg; /* No. of arguments used by the operation */ struct UnitNode **arg; /* Array of pointers to argument nodes */ double con; /* Constant to be loaded by OP_LDCON operations */ struct KnownUnit *unit; /* Known unit referred to by OP_LDVAR nodes */ Multiplier *mult; /* Multiplier used by OP_LDVAR nodes */ const char *name; /* User-defined unit referred to by OP_LDVAR nodes (no multiplier prefix included) */ } UnitNode; /* A structure describing a known unit. */ typedef struct KnownUnit { const char *sym; /* Unit symbol string (null terminated) */ const char *label; /* Unit label string (null terminated) */ int symlen; /* Length of symbol (without trailing null ) */ int lablen; /* Length of label (without trailing null ) */ struct UnitNode *head; /* Head of definition tree (NULL for basic units) */ struct KnownUnit *next; /* Next KnownUnit in linked list */ struct KnownUnit *use; /* KnownUnit to be used in place of this one */ } KnownUnit; /* Module Variables. */ /* ================= */ /* A pointer to the KnownUnit structure at the head of a linked list of such structures containing definitions of all known units. */ static KnownUnit *known_units = NULL; /* An array of pointers to KnownUnits which list the basic quantities used in dimensional analysis. */ static KnownUnit *quant_units[ NQUANT ]; /* A pointer to the Multiplier structure at the head of a linked list of such structures containing definitions of all known multipliers. */ static Multiplier *multipliers = NULL; /* Set up mutexes */ #ifdef THREAD_SAFE static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX1 pthread_mutex_lock( &mutex1 ); #define UNLOCK_MUTEX1 pthread_mutex_unlock( &mutex1 ); static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); #else #define LOCK_MUTEX1 #define UNLOCK_MUTEX1 #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #endif /* Prototypes for Private Functions. */ /* ================================= */ static AstMapping *MakeMapping( UnitNode *, int * ); static KnownUnit *GetKnownUnits( int, int * ); static Multiplier *GetMultipliers( int * ); static UnitNode *ConcatTree( UnitNode *, UnitNode *, int * ); static UnitNode *CopyTree( UnitNode *, int * ); static UnitNode *CreateTree( const char *, int, int, int * ); static UnitNode *FixUnits( UnitNode *, UnitNode *, int * ); static UnitNode *FreeTree( UnitNode *, int * ); static UnitNode *MakeTree( const char *, int, int, int * ); static UnitNode *MakeLabelTree( const char *, int, int * ); static UnitNode *NewNode( UnitNode *, Oper, int * ); static UnitNode *CombineFactors( UnitNode **, double *, int, double, int * ); static const char *CleanExp( const char *, int * ); static int EndsWith( const char *, int, const char *, int * ); static int CmpTree( UnitNode *, UnitNode *, int, int * ); static void FixConstants( UnitNode **, int, int * ); static void InvertConstants( UnitNode **, int * ); static UnitNode *InvertTree( UnitNode *, UnitNode *, int * ); static void LocateUnits( UnitNode *, UnitNode ***, int *, int * ); static void MakeKnownUnit( const char *, const char *, const char *, int * ); static void MakeUnitAlias( const char *, const char *, int * ); static void RemakeTree( UnitNode **, int * ); static int SimplifyTree( UnitNode **, int, int * ); static int ComplicateTree( UnitNode **, int * ); static int ReplaceNode( UnitNode *, UnitNode *, UnitNode *, int * ); static void FindFactors( UnitNode *, UnitNode ***, double **, int *, double *, int * ); static const char *MakeExp( UnitNode *, int, int, int * ); static int DimAnal( UnitNode *, double[NQUANT], double *, int * ); static int Ustrcmp( const char *, const char *, int * ); static int Ustrncmp( const char *, const char *, size_t, int * ); static int SplitUnit( const char *, int, const char *, int, Multiplier **, int *, int * ); static UnitNode *ModifyPrefix( UnitNode *, int * ); static int ConStart( const char *, double *, int *, int * ); /* Debug functions... static const char *DisplayTree( UnitNode *, int ); static void OpSym( UnitNode *, char * ); static const char *OpName( Oper ); static const char *TreeExp( UnitNode * ); */ /* Function implementations. */ /* ========================= */ static const char *CleanExp( const char *exp, int *status ) { /* * Name: * CleanExp * Purpose: * Produce a clean copy of a units expression. * Type: * Private function. * Synopsis: * #include "unit.h" * const char *CleanExp( const char *exp ) * Class Membership: * Unit member function. * Description: * This function returns a pointer to dynamic memory containing a * cleaned copy of the supplied units expression. Cleaning consists of * the following operations: * - removal of leading and trailing white space. * - replacement of multiple adjacent spaces by a single space * - removal of spaces adjacent to a parenthesis * - removal of spaces adjacent to a binary operator * - translates various common non-standard units into equivalent * standard units. * * Such carefull handling of spaces is necessary since a space is * recognised by the MakeTree function as a multiplication operator. * Parameters: * exp * A pointer to the expression to be cleaned. * Returned Value: * A pointer to the cleaned expression, which should be freed using * astFree when no longer needed. * Notes: * - This function returns NULL if it is invoked with the global error * status set, or if it should fail for any reason. */ /* Local Variables: */ char **tok; char *p; char *r; char *result; char *s; char *t; char *w; const char *start; int i; int l; int len; char *tt; int ntok; int po; int ps; int word; /* Initialise */ result = NULL; /* Check inherited status */ if( !astOK ) return result; /* Split the supplied string up into tokens. Each block of contiguous alphanumeric characters is a token. Each contiguous block of non-alphanumerical characters is also a token. The + and - signs are counted as alphanumeric. */ start = exp; p = (char *) exp - 1; word = ISWORD( *( p + 1 ) ); ntok = 0; tok = NULL; while( *(++p) ){ if( word ) { if( !ISWORD( *p ) ) { l = p - start; t = astStore( NULL, start, l + 1 ); if( t ) t[ l ] = 0; tok = astGrow( tok, ntok + 1, sizeof( char * ) ); if( tok ) tok[ ntok++ ] = t; start = p; word = 0; } } else { if( ISWORD( *p ) ) { l = p - start; t = astStore( NULL, start, l + 1 ); if( t ) t[ l ] = 0; tok = astGrow( tok, ntok + 1, sizeof( char * ) ); if( tok ) tok[ ntok++ ] = t; start = p; word = 1; } } } l = p - start; t = astStore( NULL, start, l + 1 ); if( t ) t[ l ] = 0; tok = astGrow( tok, ntok + 1, sizeof( char * ) ); if( tok ) tok[ ntok++ ] = t; /* Check the tokens for known non-standard unit syntax, and replace with the equivalent standard syntax. Starlink SPLAT has a class called UnitUtilities which has more of these common units mistakes. AST has to be a bit more conservative than SPLAT though because of its wider remit. */ len = 0; tt = NULL; for( i = 0; i < ntok; i++ ) { t = tok[ i ]; l = strlen( t ); tt = astStore( tt, t, l + 1 ); /* Any alphabetical word followed by a digit is taken as ^. Any alphabetical word followed by a sign and a digit is taken as ^. */ if( l > 1 && *t != '-' && *t != '+' && strcspn( t, "0123456789" ) == l - 1 ) { tok[ i ] = astMalloc( l + 2 ); if( tok[ i ] ) { strcpy( tok[ i ], t ); w = t + l - 2; if( *w != '+' && *w != '-' ) { tok[ i ][ l - 1 ] = '^'; strcpy( tok[ i ] + l, t + l - 1 ); } else { tok[ i ][ l - 2 ] = '^'; strcpy( tok[ i ] + l - 1, t + l - 2 ); } t = astFree( t ); } l++; /* If the word ends with "micron" change to "(m*1.0E-6)". Should be OK for things like "Kmicron". */ } else if( ( s = strstr( t, "micron" ) ) ) { tok[ i ] = astMalloc( s - t + 11 ); if( tok[ i ] ) { w = tok[ i ]; *(w++) = '('; if( s > t ) { strncpy( w, t, s - t ); w += s - t; } strcpy( w, "m*1.0E-6)" ); l = s - t + 11; t = astFree( t ); } /* Convert "STER" to "sr". */ } else if( !Ustrcmp( t, "STER", status ) ) { tok[ i ] = astStore( NULL, "sr", 3 ); l = 2; t = astFree( t ); /* If the word ends with "JY" and is preceded by a single character, change to "Jy". Should be OK for things like "MJY". */ } else if( l == 3 && !strcmp( t + 1, "JY" ) ) { tok[ i ][ 2 ] = 'y'; /* If the word begins with "nano" (case-insensitive) change "nano" to "n". Such changes are usually handled by SplitUnit, but we need to handle this as a special case here since scanf seems to read "nan" as a string representation of NaN. */ } else if( !Ustrncmp( t, "nano", 4, status ) ) { tok[ i ] = astStore( NULL, t + 3, l - 2 ); if( tok[ i ] ) { *(tok[ i ]) = 'n'; t = astFree( t ); } l -= 3; } /* Update the total length of the string. */ len += l; } tt = astFree( tt ); /* Concatentate the tokens into a single string, freeing the individual strings. */ result = astMalloc( len + 1 ); if( result ) { p = result; for( i = 0; i < ntok; i++ ) { len = strlen( tok[ i ] ); memcpy( p, tok[ i ], len ); p += len; tok[ i ] = astFree( tok[ i ] ); } *p = 0; tok = astFree( tok ); /* Now do other cleaning. ---------------------- */ /* Initialise a pointer to the previous character read from the string. */ r = result - 1; /* Initialise a pointer to the next character to be written to the string. */ w = result; /* Pretend the previous character written to the string was a space. */ ps = 1; /* Read all the supplied string, copying it to earlier parts of the string discarding leading spaces and multiple adjacent embedded spaces in the process. */ while( *(++r) ) { /* If the character read is a space, only write it to the string if the previous character written was not a space (in which case set a flag to indicate that the previous character written to the string is now a space). */ if( isspace( *r ) ) { if( !ps ) { *(w++) = *r; ps = 1; } /* Write all non-space characters to the string, and clear the flag which indicates if the previous character written to the string was a space. */ } else { *(w++) = *r; ps = 0; } } /* If the last character written to the string was a space, reduce the length of the string by one since we do not want any trailing spaces. */ if( ps ) w--; /* Terminate the string. */ *w = 0; /* We now need to pass through the string again, this time removing any spaces which are adjacent to a binary operator or a parenthesis. */ r = result - 1; w = result; ps = 0; po = 0; while( *(++r) ) { /* If the current character is a space, only write it if the previous written character was not an operator or parenthesis. */ if( isspace( *r ) ) { if( !po ) { *(w++) = *r; po = 1; ps = 1; } /* If the current character is an operator or parenthesis, back up one character before writing it out if the previous written character was a space. */ } else if( *r == '*' || *r == '/' || *r == '^' || *r == '.' || *r == ')' || *r == '(' ) { if( ps ) w--; *(w++) = *r; po = 1; ps = 0; /* If the current character is not a space and not an operator symbol, just write it out. */ } else { *(w++) = *r; po = 0; ps = 0; } } /* Terminate the string. */ if( ps ) w--; *w = 0; } /* Return the result. */ return (const char *) result; } static int CmpTree( UnitNode *tree1, UnitNode *tree2, int exact, int *status ) { /* * Name: * CmpTree * Purpose: * Compares two trees of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * int CmpTree( UnitNode *tree1, UnitNode *tree2, int exact, int *status ) * Class Membership: * Unit member function. * Description: * This function returns a zero value if the two trees are * equivalent. This requires the trees to have identical structure * except that, if "exact" is zero, arguments for OP_MULT nodes can * be swapped. * * If the trees are not equivalent then a value of +1 or -1 is returned * depending on whether tree1 should be placed before or after tree2 * in a sorted list of trees. * Parameters: * tree1 * A pointer to the UnitNode at the head of the first tree. * tree2 * A pointer to the UnitNode at the head of the second tree. * exact * If non-zero, then OP_MULT nodes must have their arguments the * same way round in order for the OP_MULT nodes to match. Otherwise, * OP_MULT nodes with equivalent arguments match even if the * arguments are swapped. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the two trees are equal. +1 if tree1 should be placed before * tree2 in a sorted list of trees. -1 if tree1 should be placed after * tree2 in a sorted list of trees. * Notes: * - Zero is returned if an error has already occurred, or * if this function fails for any reason. */ /* Local Variables: */ int result; int i; Oper op; /* Initialise. */ result = 0; /* Check inherited status. */ if( !astOK ) return result; /* If the op codes differ, compare them as integers. */ op = tree1->opcode; if( op != tree2->opcode ) { result = ( op > tree2->opcode ) ? 1: -1; /* If both supplied nodes are OP_LDVAR nodes, compare the associated names. */ } else if( op == OP_LDVAR ){ result = strcmp( tree1->name, tree2->name ); /* If both supplied nodes are constant nodes, compare the constant values. */ } else if( tree1->con != AST__BAD ){ result = EQUAL( tree1->con, tree2->con ) ? 0 : ( ( tree1->con > tree2->con ) ? 1 : -1 ); /* Otherwise, compare the arguments for the node. */ } else { for( i = 0; i < tree1->narg; i++ ) { result = CmpTree( tree1->arg[ i ], tree2->arg[ i ], exact, status ); if( result ) break; } /* If the head nodes of the two trees are OP_MULT nodes, and the above check determined they are different, this may be just because they have their operands swapped. If "exact" si zero, this is considered an insignificant difference between the two trees which we should ignore. To check for this try comparing the arguments again, this time swapping the arguments of tree2. */ if( result && op == OP_MULT && !exact ) { for( i = 0; i < tree1->narg; i++ ) { result = CmpTree( tree1->arg[ i ], tree2->arg[ 1 - i ], 0, status ); if( result ) break; } } } /* If an error has occurred, return zero. */ if( !astOK ) result = 0; /* Return the answer. */ return result; } static UnitNode *CombineFactors( UnitNode **factors, double *powers, int nfactor, double coeff, int *status ) { /* * Name: * CombineFactors * Purpose: * Create a tree which represents the product of the supplied factors. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *CombineFactors( UnitNode **factors, double *powers, * int nfactor, double coeff, int *status ) * Class Membership: * Unit member function. * Description: * This function createa a tree of UnitNodes which represents the * product of the supplied factors, and the supplied coefficient. * The factors are sorted before being combined, using the sort order * implemented by the CmpTree function. * Parameters: * factors * A pointer to an array with "nfactor" elements, each element being * a pointer to a UnitNode which is a factor of the required tree. * On exit, the array is sorted. * powers * A pointer to an array with "nfactor" elements, each element being a * double holding the power of the associated factor in "factors". * On exit, the array reflects the sorting applied to "factors". * nfactor * The number of elements in the "factors" and "powers" arrays. * coeff * The overall coefficient to be applied to the product of the factors. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which is at the head of the new tree. * Notes: * - A NULL pointer is returned if an error has already occurred, or * if this function fails for any reason. */ /* Local Variables: */ UnitNode *result; int i; int j; int jp; int done; UnitNode *ftmp; UnitNode *node1; UnitNode *node2; UnitNode *pnode; double ptmp; /* Initialise. */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Sort the supplied list of factors, modifying the powers array correspondingly. A simple bubblesort algorithm is used since there will only be a handfull of factors. */ for( i = nfactor - 1; i > 0; i-- ) { done = 1; for( j = 0, jp = 1; j < i; j++, jp++ ) { if( CmpTree( factors[ j ], factors[ jp ], 0, status ) > 0 ) { ftmp = factors[ j ]; factors[ j ] = factors[ jp ]; factors[ jp ] = ftmp; ptmp = powers[ j ]; powers[ j ] = powers[ jp ]; powers[ jp ] = ptmp; done = 0; } } if( done ) break; } /* The first root term of the returned tree is the coefficient, unless the coefficient is 1.0, in which case it will be the first factor. */ if( coeff != 1.0 ) { node1 = NewNode( NULL, OP_LDCON, status ); if( astOK ) node1->con = coeff; } else { node1 = NULL; } /* Loop through the factors. */ for( i = 0; i < nfactor; i++ ) { /* If the power of this factor is zero, we ignore the factor. */ if( powers[ i ] != 0.0 ) { /* If the power of this factor is one, we use the factor directly. */ if( EQUAL( powers[ i ], 1.0 ) ) { node2 = CopyTree( factors[ i ], status ); /* Otherwise, for non-zero, non-unity powers, we create a POW node for the factor. */ } else { node2 = NewNode( NULL, OP_POW, status ); pnode = NewNode( NULL, OP_LDCON, status ); if( astOK ) { pnode->con = powers[ i ]; node2->arg[ 0 ] = CopyTree( factors[ i ], status ); node2->arg[ 1 ] = pnode; } } /* We now combine node1 and node2 using an OP_MULT node, which becomes the "node1" for the next pass. On the first pass we may have no node1 (if the supplied coefficient was 1.0), in which case we reserve the current node2 as the node1 for the next pass. */ if( node1 ) { result = NewNode( NULL, OP_MULT, status ); if( astOK ) { result->arg[ 0 ] = node1; result->arg[ 1 ] = node2; node1 = result; } } else { node1 = node2; } } } /* Ensure we have a node to return. */ if( astOK ) { if( !result ) result = node1; if( !result ) { result = NewNode( NULL, OP_LDCON, status ); if( astOK ) result->con = 1.0; } } /* If an error has occurred, free any new tree. */ if( !astOK ) result = FreeTree( result, status ); /* Return the answer. */ return result; } static int ComplicateTree( UnitNode **node, int *status ) { /* * Name: * ComplicateTree * Purpose: * Removes standardisations introduced by SimplifyTree. * Type: * Private function. * Synopsis: * #include "unit.h" * int ComplicateTree( UnitNode **node ) * Class Membership: * Unit member function. * Description: * This function modifies a tree of UnitNodes by removing standardisations * introduced by SimplifyTree. The standardisations removed are ones * which would make the corresponding algebraic expression (as produced * by MakeExp) unnatural to a human reader. * Parameters: * node * The address of a pointer to the UnitNode at the head of the tree * which is to be complicated. On exit the supplied tree is freed and * a pointer to a new tree is placed at the given address. * Returned Value: * Non-zero if any change was introduced into the tree. */ /* Local Variables: */ int i; UnitNode *newnode; UnitNode *node1; UnitNode *node2; UnitNode *node3; Oper op; double con; double fk; int k; int result; double kcon; /* Initialise */ result = 0; /* Check inherited status. */ if( !astOK ) return result; /* Initiallially, we have no replacement node. */ newnode = NULL; node1 = NULL; node3 = NULL; /* Complicate the sub-trees corresponding to the arguments of the node at the head of the supplied tree. */ for( i = 0; i < (*node)->narg; i++ ) { if( ComplicateTree( &( (*node)->arg[ i ] ), status ) ) result = 1; } /* Now undo specific simplifications appropriate to the nature of the node at the head of the tree. */ op = (*node)->opcode; /* If the head is an OP_MULT node with a constant first argument and a "LN" second argument, rearrange the nodes to represent ln(x**k) instead of k*ln(x). If k is an integer multiple of "0.1/ln(10)" convert the "ln" function into a "log" (base 10) function. Check for "k==1" in which case we do not need a POW node. */ if( (*node)->opcode == OP_MULT ) { con = (*node)->arg[ 0 ]->con; if( con != AST__BAD && (*node)->arg[ 1 ]->opcode == OP_LN ) { fk = 10.0*con*log( 10.0 ); k = NINT(fk); if( EQUAL(fk,k) ) { newnode = NewNode( NULL, OP_LOG, status ); con = k/10.0; } else { newnode = NewNode( NULL, OP_LN, status ); } node2 = CopyTree( (*node)->arg[ 1 ]->arg[ 0 ], status ); if( !EQUAL( con, 1.0 ) ){ node1 = CopyTree( (*node)->arg[ 0 ], status ); node3 = NewNode( NULL, OP_POW, status ); } if( astOK ) { if( !EQUAL( con, 1.0 ) ){ node1->con = con; node3->arg[ 0 ] = node2; node3->arg[ 1 ] = node1; newnode->arg[ 0 ] = node3; } else { newnode->arg[ 0 ] = node2; } } /* Replace "(A**-1)*B" with "B/A" */ } else if( (*node)->arg[ 0 ]->opcode == OP_POW && EQUAL( (*node)->arg[ 0 ]->arg[ 1 ]->con, -1.0 )) { newnode = NewNode( NULL, OP_DIV, status ); if( astOK ) { newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 1 ], status ); newnode->arg[ 1 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); } /* Replace "B*(A**-1)" with "B/A" */ } else if( (*node)->arg[ 1 ]->opcode == OP_POW && EQUAL( (*node)->arg[ 1 ]->arg[ 1 ]->con, -1.0 )) { newnode = NewNode( NULL, OP_DIV, status ); if( astOK ) { newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ], status ); newnode->arg[ 1 ] = CopyTree( (*node)->arg[ 1 ]->arg[ 0 ], status ); } /* Convert (x**k)*(y**k) to (x*y)**k. */ } else if( (*node)->arg[ 0 ]->opcode == OP_POW && (*node)->arg[ 1 ]->opcode == OP_POW && EQUAL( (*node)->arg[ 0 ]->arg[ 1 ]->con, (*node)->arg[ 1 ]->arg[ 1 ]->con )) { newnode = NewNode( NULL, OP_POW, status ); node1 = NewNode( NULL, OP_MULT, status ); if( astOK ) { node1->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); node1->arg[ 1 ] = CopyTree( (*node)->arg[ 1 ]->arg[ 0 ], status ); newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 1 ], status ); } /* Convert c*sqrt(x) to sqrt((c**2)*x) (if c > 0). */ } else if( (kcon=(*node)->arg[ 0 ]->con) != AST__BAD && kcon > 0.0 && (*node)->arg[ 1 ]->opcode == OP_SQRT ) { newnode = NewNode( NULL, OP_SQRT, status ); node1 = NewNode( NULL, OP_MULT, status ); node2 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node2->con = kcon*kcon; node1->arg[ 0 ] = node2; node1->arg[ 1 ] = CopyTree( (*node)->arg[ 1 ]->arg[ 0 ], status ); newnode->arg[ 0 ] = node1; } } /* If the head node is a POW node, replace "x**0.5" by sqrt(x) */ } else if( (*node)->opcode == OP_POW ) { if( EQUAL( (*node)->arg[ 1 ]->con, 0.5 ) ) { newnode = NewNode( NULL, OP_SQRT, status ); if( astOK ) { newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ], status ); } } } /* If we have produced a new node which is identical to the old node, free it. Otherwise, indicate we have made some changes. */ if( newnode ) { if( !CmpTree( newnode, *node, 1, status ) ) { newnode = FreeTree( newnode, status ); } else { result = 1; } } /* If an error has occurred, free any new node. */ if( !astOK ) { newnode = FreeTree( newnode, status ); result = 0; } /* If we have a replacement node, free the supplied tree and return a pointer to the new tree. */ if( newnode ) { FreeTree( *node, status ); *node = newnode; } /* If the above produced some change, try simplifying (without re-introducing the standardisation we have just got rid of!) and then re-complicating the tree. */ if( result ) { SimplifyTree( node, 0, status ); ComplicateTree( node, status ); } /* Return the result. */ return result; } static UnitNode *ConcatTree( UnitNode *tree1, UnitNode *tree2, int *status ) { /* * Name: * ConcatTree * Purpose: * Concatenate two trees together. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *ConcatTree( UnitNode *tree1, UnitNode *tree2, int *status ) * Class Membership: * Unit member function. * Description: * This function a pointer to the head of a new tree of UnitNodes which * is formed by feeding the output of "tree1" (i.e. the quantity * represented by the node at the head of tree1) into the (single) * input of "tree2" (i.e. the single OP_LDVAR Node containined within * tree2). * Parameters: * tree1 * A pointer to the first tree. * tree2 * A pointer to the second tree. This should have no more than one * OP_LDVAR node. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which is at the head of the new tree. * Notes: * - If "tree2" contains zero units, a NULL pointer is returned but no * error is reported. * - If "tree2" contains more than one unit, an error is reported * error is reported. * - A NULL pointer is returned if an error has already occurred, or * if this function fails for any reason. */ /* Local Variables: */ UnitNode *result; UnitNode **units; int nunits; /* Initialise. */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Produce a copy of tree2. */ result = CopyTree( tree2, status ); /* Locate the OP_LDVAR node in the copy of tree2. */ units = NULL; nunits = 0; LocateUnits( result, &units, &nunits, status ); /* If no OP_LDVAR nodes were found in tree2, we cannot concatenate the trees. */ if( nunits > 0 ) { /* Report an error if the number of pointers returned is larger than 1. */ if( nunits > 1 && astOK ) { astError( AST__INTER, "ConcatTree(unit): tree2 uses %d units - " "should be 1 (internal AST programming error).", status, nunits ); } /* Replace the OP_LDVAR node in the copy of tree2 with a copy of tree1. */ if( astOK ) { /* If the node at the head of the supplied tree2 is the node to be replaced, just free the tree created earlier and return a copy of tree1. */ if( units[ 0 ] == result ) { FreeTree( result, status ); result = CopyTree( tree1, status ); /* Otherwise, search for the node to be replaced and do the substitution within the tree created earlier. */ } else { ReplaceNode( result, units[ 0 ], CopyTree( tree1, status ), status ); } } } /* Free resources. */ units = astFree( units ); /* If an error has occurred, free any new tree. */ if( !astOK ) result = FreeTree( result, status ); /* Return the answer. */ return result; } static int ConStart( const char *text, double *val, int *nc, int *status ) { /* * Name: * ConStart * Purpose: * See if the supplied string starts with a literal numeric constant. * Type: * Private function. * Synopsis: * #include "unit.h" * int ConStart( const char *text, double *val, int *nc, int *status ) * Class Membership: * Unit member function. * Description: * This function checks if the supplied string starts with a literal * numeric constant and returns it if it does. It is a wrap-up for scanf * since scanf has non-standard behaviour on some platforms (e.g. Cygwin * scanf interprets the character "n" as a floating point number!). * Parameters: * text * The text to check. * val * Address of a double to receive any numerical constant read * from the start of the string. Unity is returned if the string * does not start with a numerical constant. * nc * Address of an int to receive the number of characters used to * create the value returned in "val". Zero is returned if the * string does not start with a numerical constant. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the text started with a numerical constant. */ /* Local Variables: */ int result; const char *c; /* Initialise */ *nc = 0; *val = 1.0; /* Return zero if no text was supplied */ if( !text ) return 0; /* Use sscanf to see if the string begin with a numerical constant */ result = astSscanf( text, "%lf%n", val, nc ); /* If so, check that the first non-blank character in the string is not "N" (interpreted by Cygwin as numerical zero!). */ if( result ) { c = text; while( isspace( *c ) ) c++; if( *c == 'n' || *c == 'N' ) { result = 0; *nc = 0; *val = 1.0; } } /* Return the result. */ return result; } static UnitNode *CopyTree( UnitNode *tree, int *status ) { /* * Name: * CopyTree * Purpose: * Create a new tree of UnitNodes containing a copy of a given tree. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *CopyTree( UnitNode *tree, int *status ) * Class Membership: * Unit member function. * Description: * This function creates a copy of the supplied tree of UnitNodes. * Parameters: * tree * The UnitNode at the head of the tree to be copied. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the UnitNode at the head of the new tree. * Notes: * - A value of NULL will be returned if this function is invoked with * the global error status set, or if it should fail for any reason. */ /* Local Variables: */ UnitNode **args; UnitNode *result; int i; int narg; /* Initialise. */ result = NULL; /* Check the inherited status. */ if( !astOK || !tree ) return result; /* Create a new node to represent the head of the supplied tree. */ result = astMalloc( sizeof( UnitNode ) ); /* Check pointers can be used safely. */ if( astOK ) { /* Copy the fields of the supplied node. */ narg = tree->narg; result->arg = NULL; result->unit = tree->unit; result->mult = tree->mult; result->opcode = tree->opcode; result->narg = narg; result->con = tree->con; result->name = tree->name ? astStore( NULL, tree->name, strlen( tree->name ) + 1 ) : NULL; /* Create an array of UnitNode pointers for the arguments. */ args = astMalloc( narg*sizeof( UnitNode * ) ); if( astOK ) { result->arg = args; /* Copy the sub-trees headed by the argument nodes. */ for( i = 0; i < narg; i++ ) { args[ i ] = CopyTree( tree->arg[ i ], status ); } } } /* Free any result if an error occurred. */ if( !astOK ) result = FreeTree( result, status ); /* Return the answer. */ return result; } static UnitNode *CreateTree( const char *exp, int basic, int lock, int *status ){ /* * Name: * CreateTree * Purpose: * Convert an algebraic units expression into a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *CreateTree( const char *exp, int basic, int lock, int *status ) * Class Membership: * Unit member function. * Description: * This function converts the supplied algebraic units expression into * a tree of UnitNodes. The result tree can optionally be expanded to * create a tree in which the "roots" (LDVAR nodes) all refer to * basic units. * Parameters: * exp * The units expression. This should not include any leading or * trailing spaces. * basic * Should the tree created from parsing "exp" be expanded so that * the leaf nodes of the tree are all basic units? * lock * Use a mutex to guard access to the KnownUnits list? * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which forms the head of a tree of UnitNodes * representing the supplied unit expression. * Notes: * - A NULL value is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables: */ UnitNode *result; const char *cleanex; /* Initialise */ result = NULL; /* Check the global error status, and that we have a string. */ if ( !astOK ) return result; /* Produce a clean copy of the supplied string. This has no leading or trailing white space, and any spaces adjacent to operators within the string are removed (this is needed because spaces are treated as multiplication symbols). */ cleanex = CleanExp( exp, status ); /* If the string is blank, return the NULL pointer. Otherwise, create a tree of UnitNodes describing the units. The returned tree has LDVAR nodes which refer to the unit symbols contained in the supplied string. */ if( cleanex && (*cleanex) ) { result = MakeTree( cleanex, strlen( cleanex ), lock, status ); /* Replace each subtree which simply combines constants (i.e. which has no OP_LDVAR nodes) with a single OP_LDCON node. */ FixConstants( &result, 0, status ); /* Invert literal constant unit multipliers. */ InvertConstants( &result, status ); /* Now replace each LDVAR node which refers to a known derived unit with a sub-tree which defines the derived unit in terms of known basic units. The LDVAR nodes in the resulting tree all refer to basic units. */ if( basic ) RemakeTree( &result, status ); } /* Free resources. */ cleanex = astFree( (void *) cleanex ); /* Free any returned tree if an error has occurred. */ if( !astOK ) result = FreeTree( result, status ); /* Return the result. */ return result; } static int DimAnal( UnitNode *node, double powers[NQUANT], double *scale, int *status ) { /* * Name: * DimAnal * Purpose: * Perform a dimensional analysis of a unit tree. * Type: * Protected function. * Synopsis: * #include "unit.h" * int DimAnal( UnitNode *node, double powers[NQUANT], double *scale, int *status ) * Class Membership: * Unit member function. * Description: * This function returns a set of powers and a scaling factor which * represent the units tree. * Parameters: * node * Pointer to the UnitNode at the head of the unit tree. * powers * An array in which are returned the powers for each of the following * basic units (in the order shown): kilogramme, metre, second, radian, * Kelvin, count, adu, photon, magnitude, pixel. If the supplied unit * does not depend on a given basic unit a value of 0.0 will be returned * in the array. The returns values represent a system of units which is * a scaled form of the supplied units, expressed in the basic units of * m, kg, s, rad, K, count, adu, photon, mag and pixel. For instance, a * returned array of [1,0,-2,0,0,0,0,0,0,0] would represent "m/s**2". * scale * Pointer to a location at which to return a scaling factor for the * supplied units. The is the value, in the units represented by the * returned powers, which corresponds to a value of 1.0 in the supplied * units. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the tree was analysed succesfully. Zero otherwise. * Notes: * - Zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables; */ Oper oper; int result; int i; double p0[ NQUANT ]; double p1[ NQUANT ]; double s0; double s1; /* Check inherited status */ if( !astOK ) return 0; /* Initialise the powers of all dimensions to zero, and set the scaling factor to unity. */ result = 1; *scale = 1.0; for( i = 0; i < NQUANT; i++ ) powers[ i ] = 0.0; /* Load constant: constant is dimensionaless so leave powers unchanged, and set the scaling factor. */ oper = node->opcode; if( oper == OP_LDCON ) { *scale = 1.0/node->con; /* Load variable: check it is one of the basic known dimensional quantities. If so, set the power of the quantity to unity and store the scale factor. If the unit is "g" modify the scale factor so that the analysis quantity is "kg". */ } else if( oper == OP_LDVAR ) { result = 0; for( i = 0; i < NQUANT; i++ ) { if( node->unit == quant_units[ i ] ) { powers[ i ] = 1.0; *scale = node->mult ? 1.0/node->mult->scale : 1.0; if( !strcmp( node->unit->sym, "g" ) ) *scale *= 0.001; result = 1; break; } } /* How does dimensional analysis handle log or exp units?*/ } else if( oper == OP_LOG ) { result= 0; } else if( oper == OP_LN ) { result= 0; } else if( oper == OP_EXP ) { result= 0; /* Get the powers for the child unit and then multiply each by 0.5 and take the square root of the scale factor. */ } else if( oper == OP_SQRT ) { result = DimAnal( node->arg[0], powers, scale, status ); if( result ) { for( i = 0; i < NQUANT; i++ ) powers[ i ]*= 0.5; *scale = sqrt( *scale ); } /* Similarly for pow nodes. */ } else if( oper == OP_POW ) { result = DimAnal( node->arg[0], powers, scale, status ); if( result ) { double power = node->arg[1]->con; for( i = 0; i < NQUANT; i++ ) powers[ i ]*= power; *scale = pow( *scale, power ); } /* Binary operators. Analyses the operands dimensions and combine. */ } else if( oper == OP_DIV ) { if( DimAnal( node->arg[0], p0, &s0, status ) && DimAnal( node->arg[1], p1, &s1, status ) ) { for( i = 0; i < NQUANT; i++ ) powers[ i ] = p0[ i ] - p1[ i ]; *scale = s0/s1; } else { result = 0; } } else if( oper == OP_MULT ) { if( DimAnal( node->arg[0], p0, &s0, status ) && DimAnal( node->arg[1], p1, &s1, status ) ) { for( i = 0; i < NQUANT; i++ ) powers[ i ] = p0[ i ] + p1[ i ]; *scale = s0*s1; } else { result = 0; } /* Named constants are dimensionless */ } else if( oper == OP_LDPI ) { *scale = 1.0/PI; } else if( oper == OP_LDE ) { *scale = 1.0/E; } return result; } static int EndsWith( const char *c, int nc, const char *test, int *status ){ /* * Name: * EndsWith * Purpose: * See if a string ends with another string * Type: * Private function. * Synopsis: * #include "unit.h" * int EndsWith( const char *c, int nc, const char *test, int *status ) * Class Membership: * Unit member function. * Description: * This function sees if the string given by "c" ends with the string * given by "test". The comparison is case-insensitive. * Parameters: * c * A pointer to the last character in the string to be tested. * nc * The number of characters in the string to be tested. * test * A pointer to the string to be tested for. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the string "c" ends with the string "test". */ /* Local Variables: */ const char *start; int i; int result; int tlen; /* initialise. */ result = 0; /* Check inherited status. */ if( !astOK ) return result; /* Check the string being tested for is not longer than the string being tested. */ tlen = strlen( test ); if( tlen <= nc ){ /* Get a pointer to where the matching string would start if the string "c" ends with the required string "test". */ start = c - tlen + 1; /* Do the comparison. */ result = 1; for( i = 0; i < tlen; i++ ) { if( tolower( start[ i ] ) != tolower( test[ i ] ) ) { result = 0; break; } } } /* Return the result. */ return result; } static void FindFactors( UnitNode *node, UnitNode ***factors, double **powers, int *nfactor, double *coeff, int *status ){ /* * Name: * FindFactors * Purpose: * Find the factors within an expression given by a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * void FindFactors( UnitNode *node, UnitNode ***factors, double **powers, * int *nfactor, double *coeff, int *status ) * Class Membership: * Unit member function. * Description: * This function analyses the supplied tree of UnitNoes and returns * an array of pointers to nodes within the supplied tree which form * factors of the tree. The power associated with each factor is also * returned, together with an overall coefficient for the tree. The * expression represented by the tree is thus the product of the * coefficient with each of the factors, each raised to the associated * power. * Parameters: * node * A pointer to the UnitNode at the head of the tree which is to be * analysed. * factors * The address at which to return a pointer to an array with "*nfactor" * elements, each element being a pointer to a UnitNode within the * supplied tree which is a factor of the supplied tree. * powers * The address at which to return a pointer to an array with "*nfactor" * elements, each element being a double holding the power of the * associated factor in "*factors". * nfactor * The address of an int containing the number of elements in the * returned "*factors" and "*powers" arrays. * coeff * The address of a double containing the overall coefficient to be * applied to the product of the factors. * status * Pointer to the inherited status variable. * Notes: * - If the supplied node is a constant node, then "*coeff" is * returned holding the value of the constant and "*nfactor" is returned * equal to zero ("*factors" and "*powers" are returned holding NULL). * - If an error has already occurred, or if this function fails, then * "*factors" and "*powers" are returned holding NULL, "*nfactor" is * returned holding zero and "*coeff" is returned holding 1.0. */ /* Local Variables: */ int i; int j; int found; UnitNode **fact1; double *pow1; double coeff1; int nfac1; double con; /* Initialise */ *factors = NULL; *powers = NULL; *nfactor = 0; *coeff = 1.0; /* Check inherited status. */ if( !astOK ) return; /* If the node at the head of the supplied tree is an OP_MULT node... */ if( node->opcode == OP_MULT ) { /* Find the factors of the two arguments of the OP_MULT node. */ FindFactors( node->arg[ 0 ], factors, powers, nfactor, coeff, status ); FindFactors( node->arg[ 1 ], &fact1, &pow1, &nfac1, &coeff1, status ); /* Combine the two lists. Loop round the factors of the seocnd argument. */ for( i = 0; i < nfac1; i++ ) { /* See if there is already an equivalent factor in the returned list of factors. */ found = 0; for( j = 0; j < *nfactor; j++ ) { if( !CmpTree( (*factors)[ j ], fact1[ i ], 0, status ) ){ found = 1; break; } } /* If so, increment the power of the factor. */ if( found ) { (*powers)[ j ] += pow1[ i ]; /* Otherwise, add the factor to the end of the returned list. */ } else { *factors = astGrow( *factors, *nfactor + 1, sizeof( UnitNode *) ); *powers = astGrow( *powers, *nfactor + 1, sizeof( double ) ); if( astOK ) { (*factors)[ *nfactor ] = fact1[ i ]; (*powers)[ (*nfactor)++ ] = pow1[ i ]; } } } /* Modify the overall coefficient. */ *coeff *= coeff1; /* Free resources */ fact1 = astFree( fact1 ); pow1 = astFree( pow1 ); /* If the node at the head of the supplied tree is an OP_POW node, */ } else if( node->opcode == OP_POW ) { /* Find the factors of the first argument. */ FindFactors( node->arg[ 0 ], factors, powers, nfactor, coeff, status ); /* Multiply all the factor powers by the constant exponent of the POW node. */ con = node->arg[ 1 ]->con; for( j = 0; j < *nfactor; j++ ) { (*powers)[ j ] *= con; } /* Exponentiate the coefficient. */ if( *coeff >= 0.0 || (int) con == con ) { *coeff = pow( *coeff, con ); } else { astError( AST__BADUN, "Simplifying a units expression requires a " "negative value to be raised to a non-intergal power." , status); } /* If the node at the head of the supplied tree is an OP_DIV node, */ } else if( node->opcode == OP_DIV ) { /* Find the factors of the two arguments of the OP_DIV node. */ FindFactors( node->arg[ 0 ], factors, powers, nfactor, coeff, status ); FindFactors( node->arg[ 1 ], &fact1, &pow1, &nfac1, &coeff1, status ); /* Combine the two lists. Loop round the factors of the second argument (the denominator). */ for( i = 0; i < nfac1; i++ ) { /* See if there is already an equivalent factor in the returned list of factors. */ found = 0; for( j = 0; j < *nfactor; j++ ) { if( !CmpTree( (*factors)[ j ], fact1[ i ], 0, status ) ){ found = 1; break; } } /* If so, decrement the power of the factor. */ if( found ) { (*powers)[ j ] -= pow1[ i ]; /* Otherwise, add the factor to the end of the returned list, with a negated power. */ } else { *factors = astGrow( *factors, *nfactor + 1, sizeof( UnitNode *) ); *powers = astGrow( *powers, *nfactor + 1, sizeof( double ) ); if( astOK ) { (*factors)[ *nfactor ] = fact1[ i ]; (*powers)[ (*nfactor)++ ] = -pow1[ i ]; } } } /* Modify the overall coefficient. */ if( coeff1 != 0.0 ) { *coeff /= coeff1; } else { astError( AST__BADUN, "Simplifying a units expression" "requires a division by zero." , status); } /* Free resources */ fact1 = astFree( fact1 ); pow1 = astFree( pow1 ); /* If the node at the head of the supplied tree is an OP_SQRT node, */ } else if( node->opcode == OP_SQRT ) { /* Find the factors of the argument. */ FindFactors( node->arg[ 0 ], factors, powers, nfactor, coeff, status ); /* Multiply all the factor powers by 0.5. */ for( j = 0; j < *nfactor; j++ ) { (*powers)[ j ] *= 0.5; } /* Square root the coefficient. */ if( *coeff >= 0.0 ) { *coeff = sqrt( *coeff ); } else { astError( AST__BADUN, "Simplifying a units expression requires " "the square root of a negative value to be taken." , status); } /* If the node at the head of the supplied tree is constant we have no factors but we have a coeffcient. */ } else if( node->con != AST__BAD ) { *coeff = node->con; /* Other nodes have no factors other than themselves, so just return a pointer to the supplied node. */ } else { *factors = astMalloc( sizeof( UnitNode *) ); *powers = astMalloc( sizeof( double ) ); if( astOK ) { *nfactor = 1; (*factors)[ 0 ] = node; (*powers)[ 0 ] = 1.0; *coeff = 1.0; } } /* If an error has occurred, free any returned resources. */ if( !astOK ) { *factors = astFree( *factors ); *powers = astFree( *powers ); *nfactor = 0; *coeff = 1.0; } } static void FixConstants( UnitNode **node, int unity, int *status ) { /* * Name: * FixConstants * Purpose: * Take the reciprocal of all constants in a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * void FixConstants( UnitNode **node, int unity, int *status ) * Class Membership: * Unit member function. * Description: * This function replaces sub-trees which have a constant value by * a single OP_LDCON node which loads the appropriate constant. * Parameters: * node * The address of a pointer to the UnitNode at the head of the tree * which is to be fixed. On exit the supplied tree is freed and a * pointer to a new tree is palced at he given address. * unity * If non-zero, then all multiplicative constants are set to 1.0, and * their original values are forgotten, but only if the other * argument of the OP_MULT node is an OP_LDVAR, OP_POW or OP_SQRT Node. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; UnitNode *newnode; int allcon; Oper op; double newcon; /* Check inherited status and pointer. */ if( !astOK || !node || !(*node) ) return; /* Initiallially, we have no replacement node */ newnode = NULL; newcon = AST__BAD; /* There is nothing to fix if the node has no arguments. */ if( (*node)->narg > 0 ) { /* Note the op code for the node. */ op = (*node)->opcode; /* Fix up the argument nodes. Also note if all the arguments are constants. */ allcon = 1; for( i = 0; i < (*node)->narg; i++ ) { FixConstants( &( (*node)->arg[ i ] ), unity, status ); if( (*node)->arg[ i ]->con == AST__BAD ) allcon = 0; } /* If an OP_MULT nodes within a simplified tree has a constant argument, it will always be argument zero. If this is an OP_MULT node and arg[0] is constant and "unity" is non-zero and arg[1] is an OP_LDVAR, OP_POW or OP_SQRT node, replace the constant value by 1.0. */ if( unity && op == OP_MULT && (*node)->arg[ 0 ]->con != AST__BAD && ( (*node)->arg[ 1 ]->opcode == OP_LDVAR || (*node)->arg[ 1 ]->opcode == OP_SQRT || (*node)->arg[ 1 ]->opcode == OP_POW ) ) { (*node)->arg[ 0 ]->con = 1.0; } /* If the arguments of this node are all constants, replace the node by an OP_LDCON node which loads the resulting constant value. */ if( allcon ) { if( (*node)->narg > 0 ) { newnode = NewNode( NULL, OP_LDCON, status ); if( astOK ) { if( op == OP_LOG ) { if( (*node)->arg[ 0 ]->con > 0.0 ) { newcon = log10( (*node)->arg[ 0 ]->con ); } else { astError( AST__BADUN, "Illegal negative or zero constant " "value '%g' encountered.", status, (*node)->arg[ 0 ]->con ); } } else if( op == OP_LN ){ if( (*node)->arg[ 0 ]->con > 0.0 ) { newcon = log( (*node)->arg[ 0 ]->con ); } else { astError( AST__BADUN, "Illegal negative or zero constant value " "'%g' encountered.", status, (*node)->arg[ 0 ]->con ); } } else if( op == OP_EXP ){ newcon = exp( (*node)->arg[ 0 ]->con ); } else if( op == OP_SQRT ){ if( (*node)->arg[ 0 ]->con >= 0.0 ) { newcon = sqrt( (*node)->arg[ 0 ]->con ); } else { astError( AST__BADUN, "Illegal negative constant value " "'%g' encountered.", status, (*node)->arg[ 0 ]->con ); } } else if( op == OP_POW ){ if( (*node)->arg[ 0 ]->con >= 0.0 || (int) (*node)->arg[ 1 ]->con == (*node)->arg[ 1 ]->con ) { newcon = pow( (*node)->arg[ 0 ]->con, (*node)->arg[ 1 ]->con ); } else { astError( AST__BADUN, "Illegal negative constant value " "'%g' encountered.", status, (*node)->arg[ 0 ]->con ); } } else if( op == OP_DIV ){ if( (*node)->arg[ 1 ]->con != 0.0 ) { newcon = (*node)->arg[ 0 ]->con / (*node)->arg[ 1 ]->con; } else { astError( AST__BADUN, "Illegal zero constant value encountered." , status); } } else if( op == OP_MULT ){ newcon = (*node)->arg[ 0 ]->con * (*node)->arg[ 1 ]->con; } if( astOK ) newnode->con = newcon; } } } } /* If an error has occurred, free any new node. */ if( !astOK ) newnode = FreeTree( newnode, status ); /* If we have a replacement node, free the supplied tree and return a pointer to the new tree. */ if( newnode ) { FreeTree( *node, status ); *node = newnode; } } static UnitNode *FixUnits( UnitNode *node, UnitNode *test, int *status ) { /* * Name: * FixUnits * Purpose: * Assign a constant value to all units except for one. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *FixUnits( UnitNode *node, UnitNode *test, int *status ) * Class Membership: * Unit member function. * Description: * This function returns a copy of the supplied tree of UnitNodes. All * OP_LDVAR nodes within the copy which refer to units which differ * from those referred to by the supplied test node are replaced by * OP_LDCON nodes which load the constant value 1.0. * Parameters: * node * A pointer to the UnitNode at the head of the tree to be used. * test * A pointer to an OP_LDVAR node which defines the units which are * *not* to be replaced by a constant value of 1.0. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which is at the head of a tree of UnitNodes * which forms the required copy of th einput tree. * Notes: * - A NULL pointer is returned if an error has already occurred, or * if this function fails for any reason. */ /* Local Variables: */ int i; UnitNode *result; /* Initialise. */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Create a complete copy of the supplied tree. */ result = CopyTree( node, status ); /* Is the node at the head of the supplied tree an OP_LDVAR node? */ if( node->opcode == OP_LDVAR ) { /* Does it refer to a unit which differs from that of the test node? If so annul the copy created above and return a new OP_LDCON node which loads the constant value 1.0. */ if( strcmp( test->name, node->name ) ) { FreeTree( result, status ); result = NewNode( NULL, OP_LDCON, status ); if( astOK ) result->con = 1.0; } /* If the supplied node is not an OP_LDVAR node, check each argument of the head node. */ } else { for( i = 0; i < node->narg; i++ ) { /* Free the resources used to hold this argument in the tree copy created above. */ FreeTree( result->arg[ i ], status ); /* Create a new argument tree by calling this function recursively to fix units in the argument sub-trees. */ result->arg[ i ] = FixUnits( node->arg[ i ], test, status ); } } /* If an error has occurred, free any new tree. */ if( !astOK ) result = FreeTree( result, status ); /* Return the answer. */ return result; } static UnitNode *FreeTree( UnitNode *node, int *status ) { /* * Name: * FreeTree * Purpose: * Free resources used by a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *FreeTree( UnitNode *node, int *status ) * Class Membership: * Unit member function. * Description: * This function frees the memory used to store a tree of UnitNodes. * Parameters: * node * A pointer to the UnitNode at the head of the tree which is to be * freed. * status * Pointer to the inherited status variable. * Returned Value: * A NULL pointer is returned. * Notes: * - This function attempts to execute even if it is invoked with * the global error status set. */ /* Local Variables: */ int i; /* Check a node was supplied. */ if( node ) { /* Recursively free any argument nodes. */ if( node->arg ) { for( i = 0; i < node->narg; i++ ) { (node->arg)[ i ] = FreeTree( (node->arg)[ i ], status ); } node->arg = astFree( node->arg ); } /* Nullify other pointers for safety. */ node->unit = NULL; node->mult = NULL; /* Free the copy of the symbol string (if any). */ node->name = astFree( (char *) node->name ); /* Free the memory holding the node. */ node = astFree( node ); } /* Return a null pointer. */ return NULL; } static KnownUnit *GetKnownUnits( int lock, int *status ) { /* * Name: * GetKnownUnits * Purpose: * Get a pointer to the head of a linked list of known unit definitions. * Type: * Private function. * Synopsis: * #include "unit.h" * KnownUnit *GetKnownUnits( int lock, int *status ) * Class Membership: * Unit member function. * Description: * This function returns a pointer to the head of a linked list of known * unit definitions. The unit definitions are created as static module * variables if they have not previously been created. * Parameters: * lock * If non-zero, then lock a mutex prior to accessing the list of * known units. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the first known unit definition. * Notes: * - A NULL pointer is returned if it is invoked with the global error * status set, or if an error occurs. */ /* Local Variables: */ int iq; KnownUnit *result; /* Initialise. */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Ensure the known units list is only initialised once. */ if( lock ) { LOCK_MUTEX1 } /* If the linked list of KnownUnit structures describing the known units has not yet been created, create it now. A pointer to the head of the linked list is put into the static variable "known_units". */ if( !known_units ) { /* At the same time we store pointers to the units describing the basic quantities used in dimensional analysis. Initialise th index of the next such unit. */ iq = 0; /* Create definitions for the known units. First do all IAU basic units. We include "g" instead of "kg" because otherwise we would have to refer to a gramme as a milli-kilogramme. */ MakeKnownUnit( "g", "gram", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "m", "metre", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "s", "second", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "rad", "radian", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "K", "Kelvin", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "A", "Ampere", NULL, status ); MakeKnownUnit( "mol", "mole", NULL, status ); MakeKnownUnit( "cd", "candela", NULL, status ); /* Now do all IAU derived units. Unit definitions may only refer to units which have already been defined. */ MakeKnownUnit( "sr", "steradian", "rad rad", status ); MakeKnownUnit( "Hz", "Hertz", "1/s", status ); MakeKnownUnit( "N", "Newton", "kg m/s**2", status ); MakeKnownUnit( "J", "Joule", "N m", status ); MakeKnownUnit( "W", "Watt", "J/s", status ); MakeKnownUnit( "C", "Coulomb", "A s", status ); MakeKnownUnit( "V", "Volt", "J/C", status ); MakeKnownUnit( "Pa", "Pascal", "N/m**2", status ); MakeKnownUnit( "Ohm", "Ohm", "V/A", status ); MakeKnownUnit( "S", "Siemens", "A/V", status ); MakeKnownUnit( "F", "Farad", "C/V", status ); MakeKnownUnit( "Wb", "Weber", "V s", status ); MakeKnownUnit( "T", "Tesla", "Wb/m**2", status ); MakeKnownUnit( "H", "Henry", "Wb/A", status ); MakeKnownUnit( "lm", "lumen", "cd sr", status ); MakeKnownUnit( "lx", "lux", "lm/m**2", status ); /* Now do additional derived and basic units listed in the FITS-WCS paper. */ MakeKnownUnit( "deg", "degree", "pi/180 rad", status ); MakeKnownUnit( "arcmin", "arc-minute", "1/60 deg", status ); MakeKnownUnit( "arcsec", "arc-second", "1/3600 deg", status ); MakeKnownUnit( "mas", "milli-arcsecond", "1/3600000 deg", status ); MakeKnownUnit( "min", "minute", "60 s", status ); MakeKnownUnit( "h", "hour", "3600 s", status ); MakeKnownUnit( "d", "day", "86400 s", status ); MakeKnownUnit( "yr", "year", "31557600 s", status ); MakeKnownUnit( "a", "year", "31557600 s", status ); MakeKnownUnit( "eV", "electron-Volt", "1.60217733E-19 J", status ); MakeKnownUnit( "erg", "erg", "1.0E-7 J", status ); MakeKnownUnit( "Ry", "Rydberg", "13.605692 eV", status ); MakeKnownUnit( "solMass", "solar mass", "1.9891E30 kg", status ); MakeKnownUnit( "u", "unified atomic mass unit", "1.6605387E-27 kg", status ); MakeKnownUnit( "solLum", "solar luminosity", "3.8268E26 W", status ); MakeKnownUnit( "Angstrom", "Angstrom", "1.0E-10 m", status ); MakeKnownUnit( "micron", "micron", "1.0E-6 m", status ); MakeKnownUnit( "solRad", "solar radius", "6.9599E8 m", status ); MakeKnownUnit( "AU", "astronomical unit", "1.49598E11 m", status ); MakeKnownUnit( "lyr", "light year", "9.460730E15 m", status ); MakeKnownUnit( "pc", "parsec", "3.0867E16 m", status ); MakeKnownUnit( "count", "count", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "adu", "analogue-to-digital unit", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "photon", "photon", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "Jy", "Jansky", "1.0E-26 W /m**2 /Hz", status ); MakeKnownUnit( "mag", "magnitude", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "G", "Gauss", "1.0E-4 T", status ); MakeKnownUnit( "pixel", "pixel", NULL, status ); quant_units[ iq++ ] = known_units; MakeKnownUnit( "barn", "barn", "1.0E-28 m**2", status ); MakeKnownUnit( "D", "Debye", "(1.0E-29/3) C.m", status ); if( iq != NQUANT && astOK ) { astError( AST__INTER, "unit(GetKnownUnits): %d basic quantities " "noted but this should be %d (internal AST programming " "error).", status, iq, NQUANT ); } /* Unit aliases... */ MakeUnitAlias( "Angstrom", "Ang", status ); MakeUnitAlias( "count", "ct", status ); MakeUnitAlias( "photon", "ph", status ); MakeUnitAlias( "Jy", "Jan", status ); MakeUnitAlias( "pixel", "pix", status ); MakeUnitAlias( "s", "sec", status ); MakeUnitAlias( "m", "meter", status ); } /* If succesful, return the pointer to the head of the list. */ if( astOK ) result = known_units; /* Allow the next thread to proceed. */ if( lock ) { UNLOCK_MUTEX1 } /* Return the result. */ return result; } static Multiplier *GetMultipliers( int *status ) { /* * Name: * GetMultiplier * Purpose: * Get a pointer to the head of a linked list of multiplier definitions. * Type: * Private function. * Synopsis: * #include "unit.h" * Multiplier *Multipliers( void ) * Class Membership: * Unit member function. * Description: * This function returns a pointer to the head of a linked list of known * multiplier definitions. The multiplier definitions are created as * static module variables if they have not previously been created. * Returned Value: * A pointer to the first known multiplier definition. * Notes: * - A NULL pointer is returned if it is invoked with the global error * status set, or if an error occurs. */ /* Local Variables: */ Multiplier *result; Multiplier *mult; /* Initialise. */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Ensure the list is only initialised by one thread. */ LOCK_MUTEX2 /* If the linked list of Multiplier structures describing the known multipliers has not yet been created, create it now. A pointer to the head of the linked list is put into the static variable "multipliers". */ if( !multipliers ) { /* Define a macro to create a multiplier struncture and add it to the linked list of multiplier structures. */ #define MAKEMULT(s,sl,sc,lab,ll) \ mult = astMalloc( sizeof( Multiplier ) ); \ if( astOK ) { \ mult->sym = s; \ mult->symlen = sl; \ mult->lablen = ll; \ mult->scale = sc; \ mult->label = lab; \ mult->next = multipliers; \ multipliers = mult; \ } /* Use the above macro to create all the standard multipliers listed in the FITS WCS paper I. */ MAKEMULT("d",1,1.0E-1,"deci",4) MAKEMULT("c",1,1.0E-2,"centi",5) MAKEMULT("m",1,1.0E-3,"milli",5) MAKEMULT("u",1,1.0E-6,"micro",5) MAKEMULT("n",1,1.0E-9,"nano",4) MAKEMULT("p",1,1.0E-12,"pico",4) MAKEMULT("f",1,1.0E-15,"femto",5) MAKEMULT("a",1,1.0E-18,"atto",4) MAKEMULT("z",1,1.0E-21,"zepto",5) MAKEMULT("y",1,1.0E-24,"yocto",5) MAKEMULT("da",2,1.0E1,"deca",4) MAKEMULT("h",1,1.0E2,"hecto",5) MAKEMULT("k",1,1.0E3,"kilo",4) MAKEMULT("M",1,1.0E6,"mega",4) MAKEMULT("G",1,1.0E9,"giga",4) MAKEMULT("T",1,1.0E12,"tera",4) MAKEMULT("P",1,1.0E15,"peta",4) MAKEMULT("E",1,1.0E18,"exa",3) MAKEMULT("Z",1,1.0E21,"zetta",5) MAKEMULT("Y",1,1.0E24,"yotta",5) /* Undefine the macro. */ #undef MAKEMULT } /* If succesful, return the pointer to the head of the list. */ if( astOK ) result = multipliers; /* Allow the next thread to proceed. */ UNLOCK_MUTEX2 /* Return the result. */ return result; } static void InvertConstants( UnitNode **node, int *status ) { /* * Name: * InvertConstants * Purpose: * Take the reciprocal of all constants in a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * void InvertConstants( UnitNode **node, int *status ) * Class Membership: * Unit member function. * Description: * This function replaces constant unit coefficients by their reciprocal. * This is because a string such as "0.01 m" will be interpreted as * meaning "multiply a value in metres by 0.01 to get the value in the * required units", whereas what is actually meant is "use units of * 0.01 of a metre" which requires us to divide the value in metres by * 0.01, not multiply it. * Parameters: * node * The address of a pointer to the UnitNode at the head of the tree. * On exit the supplied tree is freed and a pointer to a new tree is * placed at the given address. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; UnitNode *newnode; int allcon; Oper op; /* Check inherited status and pointer. */ if( !astOK || !node || !(*node) ) return; /* Initiallially, we have no replacement node */ newnode = NULL; /* There is nothing to fix if the node has no arguments. */ if( (*node)->narg > 0 ) { /* Note the op code for the node. */ op = (*node)->opcode; /* Fix up the argument nodes. Also note if all the arguments are constants. */ allcon = 1; for( i = 0; i < (*node)->narg; i++ ) { InvertConstants( &( (*node)->arg[ i ] ), status ); if( (*node)->arg[ i ]->con == AST__BAD ) allcon = 0; } /* If all nodes are constant, there are no co-efficients to invert. */ if( !allcon ) { /* Iif this is a multiplication node, see if either of its arguments is a constant. If so, invert the constant. This is because a string like "0.01 m" means "each unit is 0.01 of a metre". Therefore, to transform a value in metres into required units means multiplying the metres value by 100.0 (i.e the reciprocal of 0.01), not 0.01. */ if( op == OP_MULT ) { for( i = 0; i < 2; i++ ) { if( (*node)->arg[ i ]->con != AST__BAD ) { if( (*node)->arg[ i ]->con != 0.0 ) { (*node)->arg[ i ]->con = 1.0/(*node)->arg[ i ]->con; } else { astError( AST__BADUN, "Illegal zero constant encountered." , status); } } } /* Likewise, check for division nodes in which the denominator is constant. */ } else if( op == OP_DIV ) { if( (*node)->arg[ 1 ]->con != AST__BAD ) { if( (*node)->arg[ 1 ]->con != 0.0 ) { (*node)->arg[ 1 ]->con = 1.0/(*node)->arg[ 1 ]->con; } else { astError( AST__BADUN, "Illegal zero constant encountered." , status); } } /* If this is a "pow" node check that the second argument is constant (required by FITS WCS paper I). */ } else if( op == OP_POW ) { if( (*node)->arg[ 1 ]->con == AST__BAD ) { astError( AST__BADUN, "Illegal variable exponent." , status); } } } } /* If an error has occurred, free any new node. */ if( !astOK ) newnode = FreeTree( newnode, status ); /* If we have a replacement node, free the supplied tree and return a pointer to the new tree. */ if( newnode ) { FreeTree( *node, status ); *node = newnode; } } static UnitNode *InvertTree( UnitNode *fwdnode, UnitNode *src, int *status ) { /* * Name: * InvertTree * Purpose: * Invert a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *InvertTree( UnitNode *fwdnode, UnitNode *src ) * Class Membership: * Unit member function. * Description: * This function inverts a tree of UnitNodes. The supplied tree should * have exactly one OP_LDVAR node. This will be the quantity represented * by the node at the head of the returned tree. * Parameters: * fwdnode * A pointer to the UnitNode at the head of the tree which is to be * inverted. * src * A pointer to a UnitNode which is to be used as the root of the * inverted tree. That is, the output from this node should form * the (one and only) varying input to the inverted tree. If the * supplied tree is succesfulyl inverted, the tree of which "src" * is the head will be contained within the returned inverted tree. * Therefore "src" only needs to be freed explicitly if this * function fails to invert the supplied tree for any reason. If * this function succeeds, then "src" will be freed as part of * freeing the returned inverted tree. * Returned Value: * A pointer to a UnitNode which forms the head of the inverted tree. * Algorithm: * The algorithm works through the supplied forward tree, from the head * to the roots. First, the supplied node at the head of the forward * tree is inverted. To be invertable, the supplied head node must have * exactly one varying argument (any other arguments must be fixed, * i.e. not vary). This varying argument becomes the output of the * inverted node. The other (fixed) arguments to the forward node are * also used as arguments to the inverted node. The supplied "src" node * is used as the single varying input to the inverted node. Having * inverted the supplied forward head node, this function is called * recursively to invert the lower parts of the forward tree (i.e. the * part of the forward tree which provided the varying input to node * which has just been inverted). * Notes: * - It is assumed that he supplied forward tree has been simplified * using SimplifyTree. This means that the tree contains no nodes with * the following op codes: OP_LOG, OP_SQRT. OP_DIV (SimplifyTree * converts these nodes into OP_LN, OP_POW and OP_MULT nodes). * - A value of NULL will be returned if this function is invoked with * the global error status set, or if it should fail for any reason. */ /* Local Variables: */ UnitNode *newnode; UnitNode *nextnode; UnitNode *result; UnitNode *node1; Oper fop; int varg; /* Initialise */ result = NULL; /* Check inherited status. */ if( !astOK ) return result; /* Initiallially, we have no replacement node */ newnode = NULL; nextnode = NULL; /* Save the op code at the head of the forward tree. */ fop = fwdnode->opcode; /* If the head of the forward tree is a OP_EXP node. Inverse of "exp(x)" is "ln(x)". */ if( fop == OP_EXP ) { newnode = NewNode( NULL, OP_LN, status ); if( astOK ) { newnode->arg[ 0 ] = src; nextnode = fwdnode->arg[ 0 ]; } /* If the head of the forward tree is a OP_LN node. Inverse of "ln(x)" is "exp(x)". */ } else if( fop == OP_LN ) { newnode = NewNode( NULL, OP_EXP, status ); if( astOK ) { newnode->arg[ 0 ] = src; nextnode = fwdnode->arg[ 0 ]; } /* If the head of the forward tree is a OP_POW node. Inverse of "x**k" is "x**(1/k)" */ } else if( fop == OP_POW ) { newnode = NewNode( NULL, OP_POW, status ); node1 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node1->con = 1.0/fwdnode->arg[ 1 ]->con; newnode->arg[ 0 ] = src; newnode->arg[ 1 ] = node1; nextnode = fwdnode->arg[ 0 ]; } /* If the head of the forward tree is a OP_MULT node... */ } else if( fop == OP_MULT ) { /* The node is only invertable if it has one constant node and one non-constant node. Get the index of the varying argument. */ if( fwdnode->arg[ 0 ]->con != AST__BAD && fwdnode->arg[ 1 ]->con == AST__BAD ) { varg = 1; } else if( fwdnode->arg[ 0 ]->con == AST__BAD && fwdnode->arg[ 1 ]->con != AST__BAD ) { varg = 0; } else { varg = -1; } if( varg != -1 ) { /* The inverse of "k*x" is "(1/k)*x" (we use MULT nodes instead of DIV nodes to maintain the standardisation implemented by SimplifyTree). */ newnode = NewNode( NULL, OP_MULT, status ); node1 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node1->con = 1.0/fwdnode->arg[ 1 - varg ]->con; newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = src; nextnode = fwdnode->arg[ varg ]; } } /* If the head of the forward tree is a OP_LDVAR node, there is nothing left to invert. SO return a pointer to the suppleid source node. */ } else if( fop == OP_LDVAR ) { result = src; nextnode = NULL; /* If the head of the forward tree is any other node (e.g. a OP_LDCON node), the tree cannot be inverted. */ } else { nextnode = NULL; } /* If we managed to invert the node at the head of the supplied tree, continue to invert its varying argument node (if any). */ if( nextnode && newnode ) result = InvertTree( nextnode, newnode, status ); /* If the tree could not be inverted, free the newnode. */ if( !result ) newnode = FreeTree( newnode, status ); /* If an error has occurred, free any new node. */ if( !astOK ) result = FreeTree( result, status ); /* Return the result. */ return result; } static void LocateUnits( UnitNode *node, UnitNode ***units, int *nunits, int *status ){ /* * Name: * LocateUnits * Purpose: * Locate the units used by a supplied tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * void LocateUnits( UnitNode *node, UnitNode ***units, int *nunits, int *status ) * Class Membership: * Unit member function. * Description: * This function locates the units used by a supplied tree of * UnitNodes. * Parameters: * node * A pointer to the UnitNode at the head of the tree to be searched. * units * The address at which is stored a pointer to an array of "*nunits" * elements. Each element of the array holds a pointer to a UnitNode. * The array is extended on exit to hold pointers to the OP_LDVAR nodes * within the supplied tree (i.e. nodes which represent named units, * either known or unknown). A node is only included in the returned * array if no other node for the same unit is already included in the * array. A NULL pointer should be supplied on the first invocation of * this function. * nunits * The address of an integer which holds the number of elements in * the array given by "*units". Updated on exit to included any * elements added to the array. Zero should be supplied on the first * invocation of this function. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; int found; /* Check the global error status. */ if( !astOK ) return; /* Is the node at the head of the supplied tree an OP_LDVAR node? */ if( node->opcode == OP_LDVAR ) { /* If an array was supplied, see if it already contains a pointer to a node which refers to the same units. */ found = 0; if( *units ) { for( i = 0; i < *nunits; i++ ) { if( !strcmp( (*units)[ i ]->name, node->name ) ) { found = 1; break; } } } /* If not, ensure the array is big enough and add a pointer to the supplied node to the array. */ if( !found ) { *units = astGrow( *units, *nunits + 1, sizeof( UnitNode * ) ); if( astOK ) (*units)[ (*nunits)++ ] = node; } /* If the supplied node is not an OP_LDVAR node, call this function recursively to search the argument sub-trees. */ } else { for( i = 0; i < node->narg; i++ ) { LocateUnits( node->arg[ i ], units, nunits, status ); } } } static const char *MakeExp( UnitNode *tree, int mathmap, int top, int *status ) { /* * Name: * MakeExp * Purpose: * Make an algebraic expression from a supplied tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * const char *MakeExp( UnitNode *tree, int mathmap, int top, int *status ) * Class Membership: * Unit member function. * Description: * This function produces a string holding an algebraic expression * corresponding to a supplied tree of UnitNodes. * Parameters: * tree * A pointer to the UnitNode at the head of the tree to be converted * into an algebraic expression. * mathmap * If zero, format as an axis label expression. If 1, format as a * MathMap expression. If 2, format as a FITS unit string. * top * Should be non-zero for a top-level entry to this function, and * zero for a recursive entry. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the cleaned expression, which should be freed using * astFree when no longer needed. * Notes: * - This function returns NULL if it is invoked with the global error * status set, or if it should fail for any reason. */ /* Local Variables: */ UnitNode *newtree; UnitNode *sunit; char *a; char *result; char buff[200]; const char *arg0; const char *arg1; const char *mtxt; int larg0; int larg1; int lbuff; int mlen; int par; int tlen; /* Check inherited status. */ result = NULL; if( !astOK ) return result; /* Modify the tree to make the resulting transformation functions more natural to human readers. */ newtree = CopyTree( tree, status ); ComplicateTree( &newtree, status ); /* If we are producing an axis label... */ if( !mathmap ) { /* Fix all multiplicative constants to 1.0 if they multiply an OP_LDVAR OP_SQRT or OP_POW node. This is on the assumption that the returned label should not include any simple unit scaling (e.g. if the output label would be "2.345*wavelength", we prefer simply to use "wavelength" since a scaled wavelength is still a wavelength - i.e. simple scaling does not change the dimensions of a quantity). */ FixConstants( &newtree, 1, status ); /* Simplify the tree again to get rid of the 1.0 terms which may have been introduced by the previous line (but do not re-introduce any standardisations - removing them was the reason for calling ComplicateTree). If this simplication introduces any changes, try fixing multiplicative constants again, and so on, until no more changes occur. */ while( SimplifyTree( &newtree, 0, status ) ) { FixConstants( &newtree, 1, status ); } } /* Produce a string describing the action performed by the UnitNode at the head of the supplied tree, and then invoke this function recursively to format any arguments of the head node. */ /* Constant valued nodes... just format the constant in a local buffer and then copy the buffer. */ if( newtree->con != AST__BAD ) { lbuff = sprintf( buff, "%.*g", DBL_DIG, newtree->con ); result = astStore( NULL, buff, lbuff + 1 ); /* "Load Variable Value" nodes - return the variable name. If this is a recursive call to this function, and we are producing a label, append a single space before and after the name. */ } else if( newtree->opcode == OP_LDVAR ) { tlen = strlen( newtree->name ); if( !mathmap && !top ){ result = astMalloc( tlen + 3 ); if( result ) { result[ 0 ] = ' '; memcpy( result + 1, newtree->name, tlen ); memcpy( result + tlen + 1, " ", 2 ); } } else if( mathmap == 2 ) { if( newtree->mult ) { mlen = newtree->mult->symlen; mtxt = newtree->mult->sym; } else { mlen = 0; mtxt = NULL; } result = astMalloc( tlen + 1 + mlen ); if( result ) { if( mtxt ) memcpy( result, mtxt, mlen ); memcpy( result + mlen, newtree->name, tlen + 1 ); } } else { result = astStore( NULL, newtree->name, tlen + 1 ); } /* Single argument functions... place the argument in parentheses after the function name. */ } else if( newtree->opcode == OP_LOG ) { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); if( mathmap == 1 ) { result = astMalloc( larg0 + 8 ); if( result ) memcpy( result, "log10(", 7 ); a = result + 6; } else { result = astMalloc( larg0 + 6 ); if( result ) memcpy( result, "log(", 5 ); a = result + 4; } if( result ){ memcpy( a, arg0, larg0 + 1 ); memcpy( a + larg0, ")", 2 ); } arg0 = astFree( (void *) arg0 ); } else if( newtree->opcode == OP_LN ) { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); if( mathmap == 1 ) { result = astMalloc( larg0 + 6 ); if( result ) memcpy( result, "log(", 5 ); a = result + 4; } else { result = astMalloc( larg0 + 5 ); if( result ) memcpy( result, "ln(", 4 ); a = result + 3; } if( astOK ){ memcpy( a, arg0, larg0 ); memcpy( a + larg0, ")", 2 ); } arg0 = astFree( (void *) arg0 ); } else if( newtree->opcode == OP_EXP ) { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); result = astMalloc( larg0 + 6 ); if( result ){ memcpy( result, "exp(", 5 ); memcpy( result + 4, arg0, larg0 ); memcpy( result + 4 + larg0, ")", 2 ); } arg0 = astFree( (void *) arg0 ); } else if( newtree->opcode == OP_SQRT ) { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); result = astMalloc( larg0 + 7 ); if( result ){ memcpy( result, "sqrt(", 6 ); memcpy( result + 5, arg0, larg0 ); memcpy( result + 5 + larg0, ")", 2 ); } arg0 = astFree( (void *) arg0 ); /* POW... the exponent (arg[1]) is always a constant and so does not need to be placed in parentheses. The first argument only needs to be placed in parentheses if it is a two arg node (except we also put it in parentheses if it is an OP_LDVAR node and "mathmap" is zero - this is because such OP_LDVAR nodes will correspond to axis labels which will have spaces before and after them which would look odd if not encloses in parentheses). */ } else if( newtree->opcode == OP_POW ) { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); arg1 = MakeExp( newtree->arg[ 1 ], mathmap, 0, status ); larg1 = strlen( arg1 ); if( newtree->arg[ 0 ]->narg == 2 || (newtree->arg[ 0 ]->opcode == OP_LDVAR && !mathmap) ) { par = 1; result = astMalloc( larg0 + larg1 + 7 ); if( result ) memcpy( result, "(", 2 ); a = result + 1; } else { par = 0; result = astMalloc( larg0 + larg1 + 5 ); a = result; } if( result ) { memcpy( a, arg0, larg0 ); a += larg0; if( par ) *(a++) = ')'; memcpy( a, "**", 3 ); a += 2; memcpy( a, arg1, larg1 ); a += larg1; *a = 0; } arg0 = astFree( (void *) arg0 ); arg1 = astFree( (void *) arg1 ); /* DIV... the first argument (numerator) never needs to be in parentheses. The second argument (denominator) only needs to be placed in parentheses if it is a MULT node. */ } else if( newtree->opcode == OP_DIV ) { if( mathmap == 2 && ( sunit = ModifyPrefix( newtree, status ) ) ) { result = (char *) MakeExp( sunit, mathmap, 0, status ); sunit = FreeTree( sunit, status ); } else { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); arg1 = MakeExp( newtree->arg[ 1 ], mathmap, 0, status ); larg1 = strlen( arg1 ); if( newtree->arg[ 1 ]->opcode == OP_MULT && strchr( arg1, '*' ) ) { par = 1; result = astMalloc( larg0 + larg1 + 4 ); } else { par = 0; result = astMalloc( larg0 + larg1 + 2 ); } if( result ) { memcpy( result, arg0, larg0 ); a = result + larg0; *(a++) = '/'; if( par ) *(a++) = '('; memcpy( a, arg1, larg1 ); a += larg1; if( par ) *(a++) = ')'; *a = 0; } arg0 = astFree( (void *) arg0 ); arg1 = astFree( (void *) arg1 ); } /* MULT... the second argument never needs to be in parentheses. The first argument only needs to be placed in parentheses if it is a DIV or POW node. */ } else if( newtree->opcode == OP_MULT ) { if( mathmap == 2 && ( sunit = ModifyPrefix( newtree, status ) ) ) { result = (char *) MakeExp( sunit, mathmap, 0, status ); sunit = FreeTree( sunit, status ); } else { arg0 = MakeExp( newtree->arg[ 0 ], mathmap, 0, status ); larg0 = strlen( arg0 ); arg1 = MakeExp( newtree->arg[ 1 ], mathmap, 0, status ); larg1 = strlen( arg1 ); /* If this is a top-level entry and we are producing an axis label, do not include any constant multiplicative terms. */ if( top && !mathmap ) { if( newtree->arg[ 0 ]->con != AST__BAD ) arg0 = astFree( (void *) arg0 ); if( newtree->arg[ 1 ]->con != AST__BAD ) arg1 = astFree( (void *) arg1 ); } /* If we have two arguments, concatentate them, placing the operands in parentheses if necessary. */ if( arg0 && arg1 ) { if( ( newtree->arg[ 0 ]->opcode == OP_DIV && strchr( arg0, '/' ) ) || ( newtree->arg[ 0 ]->opcode == OP_POW && strstr( arg0, "**" ) ) ) { par = 1; result = astMalloc( larg0 + larg1 + 4 ); if( result ) result[ 0 ] = '('; a = result + 1; } else { par = 0; result = astMalloc( larg0 + larg1 + 2 ); a = result; } if( result ) { memcpy( a, arg0, larg0 ); a += larg0; if( par ) *(a++) = ')'; *(a++) = '*'; memcpy( a, arg1, larg1 ); a += larg1; *a = 0; } arg0 = astFree( (void *) arg0 ); arg1 = astFree( (void *) arg1 ); /* If we do not have two arguments, just return the one we do have. */ } else if( arg0 ){ result = (char *) arg0; } else { result = (char *) arg1; } } } /* Free the complicated tree. */ newtree = FreeTree( newtree, status ); /* Free the returned string if an error has occurred. */ if( !astOK ) result = astFree( result ); /* Return the result. */ return (const char *) result; } static void MakeKnownUnit( const char *sym, const char *label, const char *exp, int *status ){ /* * Name: * MakeKnownUnit * Purpose: * Create a KnownUnit structure describing a known unit. * Type: * Private function. * Synopsis: * #include "unit.h" * void MakeKnownUnit( const char *sym, const char *label, const char *exp, int *status ) * Class Membership: * Unit member function. * Description: * This function creates a KnownUnit structure decribing a known unit, * and adds it to the head of the linked list of known units stored in * a module variable. * Parameters: * sym * A pointer to a string which can be used as a symbol to represent * the new named unit. Once defined, this symbol can be included within * the definition of other derived units. The string should contain * only alphabetical characters (no digits, spaces, punctuation, * etc). Symbols are case sensitive (e.g. "s" is second, but "S" is * Siemens). The string should not include any multiplier prefix. * label * Pointer to a null terminated string containing the label for * the required units. No restriction on content. * exp * This should be a pointer to a null terminated string containing * a definition of the required unit. See the description of the * "in" and "out" parameters for the astUnitMapper function. * * A NULL pointer or a blank string may supplied for "exp", which * is interpreted as a request for a new basic unit to be created with * the symbol and label given by the other parameters. * status * Pointer to the inherited status variable. * Notes: * - The supplied symbol and label strings are not copied. The * supplied pointers are simply stored in the returned structure. * Therefore the strings to which the pointers point should not be * modified after this function returned (in fact this function is * always called with literal strings for these arguments). */ /* Local Variables: */ KnownUnit *result; /* Check the global error status. */ if( !astOK ) return; /* Indicate that subsequent memory allocations may never be freed (other than by any AST exit handler). */ astBeginPM; /* Allocate memory for the structure, and check the returned pointer can be used safely. */ result = astMalloc( sizeof( KnownUnit ) ); if( astOK ) { /* In case of errors, first nullify the pointer to the next KnownUnit. */ result->next = NULL; /* Store the supplied label and symbol pointers. */ result->sym = sym; result->label = label; /* Store the length of the symbol (without the trailing null character). */ result->symlen = strlen( sym ); /* Store the length of the label (without the trailing null character). */ result->lablen = strlen( label ); /* Create a tree of UnitNodes describing the unit if an expression was supplied. */ result->head = exp ? CreateTree( exp, 1, 0, status ) : NULL; /* Unit aliases are replaced in use by the KnownUnit pointed to by the "use" component of the structure. Indicate this KnownUnitis not an alias by setting its "use" component NULL. */ result->use = NULL; } /* Mark the end of the section in which memory allocations may never be freed (other than by any AST exit handler). */ astEndPM; /* If an error has occurred, free any returned structure. */ if( !astOK ) { result->head = FreeTree( result->head, status ); result = astFree( result ) ; /* Otherwise, add the new KnownUnit to the head of the linked list of known units. */ } else { result->next = known_units; known_units = result; } } static AstMapping *MakeMapping( UnitNode *tree, int *status ) { /* * Name: * MakeMapping * Purpose: * Create a new Mapping from a given tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * AstMapping *MakeMapping( UnitNode *tree ) * Class Membership: * Unit member function. * Description: * This function creates a Mapping with a forward transformation equal * to the transformation described by the tree of UnitNodes. The head * node of the tree corresponds to the output of the Mapping. * Parameters: * tree * The UnitNode at the head of the tree to be used. It should have * exactly one OP_LDVAR node, and should have been simplified using * the SimplifyTree function. * Returned Value: * A pointer to the Mapping. Its Nin and Nout attributes will both be 1. * Notes: * - A value of NULL will be returned if this function is invoked with * the global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstMapping *result; UnitNode *inv; UnitNode *src; const char *fwdexp; char *fwdfun; const char *invexp; char *invfun; int lfwd; int linv; /* Initialise. */ result = NULL; /* Check the inherited status. */ if( !astOK ) return result; /* First see if a UnitMap can be used to represent the Mapping from input units to output units. This will be the case if the supplied tree consists of a aingle OP_LDVAR node (corresponding to the input units). */ if( tree->opcode == OP_LDVAR ) { result = (AstMapping *) astUnitMap( 1, "", status ); /* Now see if a UnitMap or ZoomMap can be used to represent the Mapping from input units to output units. This will be the case if the supplied tree consists of a OP_MULT node with one constant argument and on OP_LDVAR argument (corresponding to the input units). The standardisation done by SimplifyTree will have ensured that the constant will be argument 0 (and will also have converted "x/k" trees into "(1/k)*x" trees). */ } else if( tree->opcode == OP_MULT && tree->arg[ 0 ]->con != AST__BAD && tree->arg[ 1 ]->opcode == OP_LDVAR ) { if( tree->arg[ 0 ]->con == 1.0 ) { result = (AstMapping *) astUnitMap( 1, "", status ); } else { result = (AstMapping *) astZoomMap( 1, tree->arg[ 0 ]->con, "", status ); } /* For other trees we need to create a MathMap. */ } else { /* Format the supplied tree as an algebraic expression, and get its length. */ fwdexp = MakeExp( tree, 1, 1, status ); lfwd = strlen( fwdexp ); /* The MathMap constructor requires the forward and inverse transformation functions to be specified as equations (i.e. including an equals sign). We use the output variable name "output_units" (the astUnitMapper function creates the supplied tree usign the variable name "input_units" ). */ lfwd += 13; /* Invert the supplied tree and create an algebraic expression from it. */ src = NewNode( NULL, OP_LDVAR, status ); if( astOK ) src->name = astStore( NULL, "output_units", 13 ); inv = InvertTree( tree, src, status ); if( !inv ) { src = FreeTree( src, status ); astError( AST__BADUN, "MakeMapping(Unit): Failed to invert " "supplied tree '%s' (internal AST programming error).", status, fwdexp ); /* If inverted succesfully (which it should be since astUnitMapper should have checked this)... */ } else { /* Format the inverted tree as an algebraic expression, and get its length, adding on extra characters for the variable name ("input_units") and equals sign. */ invexp = MakeExp( inv, 1, 1, status ); linv = strlen( invexp ); linv += 12; /* Allocate memory for the transformation functions, plus an extra character for the trailing null. */ fwdfun = astMalloc( lfwd + 1 ); invfun = astMalloc( linv + 1 ); if( invfun ) { memcpy( fwdfun, "output_units=", 14 ); memcpy( invfun, "input_units=", 13 ); /* Append the expressions following the equals signs. */ strcpy( fwdfun + 13, fwdexp ); strcpy( invfun + 12, invexp ); /* Create the MathMap. */ result = (AstMapping *) astMathMap( 1, 1, 1, (const char **) &fwdfun, 1, (const char **) &invfun, "SimpFI=1,SimpIF=1", status ); } /* Free resources. */ inv = FreeTree( inv, status ); fwdfun = astFree( fwdfun ); invfun = astFree( invfun ); invexp = astFree( (void *) invexp ); } fwdexp = astFree( (void *) fwdexp ); } /* Free any result if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the answer. */ return result; } static UnitNode *MakeLabelTree( const char *lab, int nc, int *status ){ /* * Name: * MakeLabelTree * Purpose: * Convert an axis label into a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *MakeLabelTree( const char *lab, int nc, int *status ) * Class Membership: * Unit member function. * Description: * This function converts an axis label into a tree of UnitNodes. * It is assumed the supplied label represents some "basic" label * modified by the application of one or more single function arguments * and/or exponentiation operators. The (single) OP_LDVAR node in the * returned tree refers to the basic label (it is stored as the "name" * component of UnitNode structure). * Parameters: * lab * The label expression. * nc * The number of characters from "lab" to use. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which forms the head of a tree of UnitNodes * representing the supplied label expression. * Notes: * - A NULL value is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables: */ Oper op; UnitNode *result; char buff[ 10 ]; const char *c; const char *exp; int depth; int i; int oplen; int n; double con; /* Initialise */ result = NULL; oplen = 0; /* Check the global error status, and that we have a string. */ if ( !astOK || !lab || !nc ) return result; /* Get a pointer to the first non-blank character, and store the number of characters to examine (this excludes any trailing white space). */ exp = lab; while( isspace( *exp ) ) exp++; c = lab + nc - 1; while( c >= exp && isspace( *c ) ) c--; nc = c - exp + 1; /* Scan through the supplied string looking for the first pow operator at zero depth of nesting within parentheses. */ depth = 0; c = exp; i = 0; op = OP_NULL; while( i < nc && *c ){ /* If this character is an opening parenthesis, increment the depth of nesting. */ if( *c == '(' ) { depth++; /* If this character is an closing parenthesis, decrement the depth of nesting. Report an error if it ever goes negative. */ } else if( *c == ')' ) { depth--; if( depth < 0 && astOK ) { astError( AST__BADUN, "Missing opening parenthesis." , status); break; } /* Ignore all other characters unless they are at zero depth of nesting. Also ignore spaces. */ } else if( depth == 0 && !isspace( *c ) ) { /* Compare the next part of the string with each of the "pow" operators. */ if( !strncmp( c, "**", 2 ) ) { op = OP_POW; oplen = 2; } else if( *c == '^' ) { op = OP_POW; oplen = 1; } /* If an operator was found, break out of the loop. */ if( op != OP_NULL ) break; } /* Pass on to check the next character. */ i++; c++; } /* If a "pow" operator was found, the strings on either side of it should be valid unit expressions, in which case we use this routine recursively to create corresponding trees of UnitNodes. */ if( op != OP_NULL ) { /* Create a UnitNode for the operator. */ result = NewNode( NULL, op, status ); if( astOK ) { /* Create a tree of unit nodes from the string which precedes the binary operator. Report an error if it cannot be done. */ result->arg[ 0 ] = MakeLabelTree( exp, i, status ); if( !result->arg[ 0 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand before '%s'.", status, buff ); } /* Create a tree of unit nodes from the string which follows the binary operator. Report an error if it cannot be done. */ result->arg[ 1 ] = MakeLabelTree( c + oplen, nc - i - oplen, status ); if( !result->arg[ 1 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand after '%s'.", status, buff ); } } /* If no binary operator was found at depth zero, see if the supplied string starts with a function name (the only legal place for a function name given that the string has no binary operators at depth zero). */ } else { if( !strncmp( exp, "sqrt(", 5 ) || !strncmp( exp, "SQRT(", 5 ) ) { op = OP_SQRT; oplen = 4; } else if( !strncmp( exp, "exp(", 4 ) || !strncmp( exp, "EXP(", 4 ) ) { op = OP_EXP; oplen = 3; } else if( !strncmp( exp, "ln(", 3 ) || !strncmp( exp, "LN(", 3 ) ) { op = OP_LN; oplen = 2; } else if( !strncmp( exp, "log(", 4 ) || !strncmp( exp, "LOG(", 4 ) ) { op = OP_LOG; oplen = 3; } /* If a function was found, the string following the function name (including the opening parenthesis) should form a legal units expresssion (all the supported functions take a single argument and so we do not need to worry about comma-separated lists of function arguments). Use this routine recursively to create a tree of UnitNodes from the string which forms the function argument. */ if( op != OP_NULL ) { /* Create a UnitNode for the function. */ result = NewNode( NULL, op, status ); if( astOK ) { /* Create a tree of unit nodes from the string which follows the function name. Report an error if it cannot be done. */ result->arg[ 0 ] = MakeLabelTree( exp + oplen, nc - oplen, status ); if( !result->arg[ 0 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing argument for '%s'.", status, buff ); } } /* Arrive here if the supplied string does not contain a POW operator or function at depth zero. Check to see if the whole string is contained within parentheses, In which we interpret the contents of the parentheses as a units expression. It is safe simply to check the first and last characters (a string like "(fred)(Harry)" is not a legal possibility since there should be an operator in the middle).*/ } else if( nc > 0 && ( exp[ 0 ] == '(' && exp[ nc - 1 ] == ')' ) ) { result = MakeLabelTree( exp + 1, nc - 2, status ); /* Does the string begin with a numerical constant? */ } else if( ConStart( exp, &con, &n, status ) == 1 ) { /* If the entire string was a numerical constant, represent it by a LDCON node. */ if( n == nc ) { result = NewNode( NULL, OP_LDCON, status ); if( astOK ) result->con = con; /* If there was anything following the numerical constant, report an error. */ } else if( astOK ){ astError( AST__BADUN, "Missing operator after " "numerical string '%.*s'.", status, n, exp ); } /* The only legal possibility left is that the string represents the basic label. Create an OP_LDVAR node for it and store the basic label as the node name, omitting any enclosing white space. */ } else { result = NewNode( NULL, OP_LDVAR, status ); if( astOK ) { result->name = astStore( NULL, exp, nc + 1 ); if( astOK ) ( (char *) result->name)[ nc ] = 0; } } } /* Free any returned tree if an error has occurred. */ if( !astOK ) result = FreeTree( result, status ); /* Return the result. */ return result; } static UnitNode *MakeTree( const char *exp, int nc, int lock, int *status ){ /* * Name: * MakeTree * Purpose: * Convert an algebraic units expression into a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *MakeTree( const char *exp, int nc, int lock, int *status ) * Class Membership: * Unit member function. * Description: * This function converts an algebraic units expression into a tree of * UnitNodes. It is a service routine for CreateTree. The roots of the * returned tree (i.e. the LDVAR nodes) refer to the unit symbols * contained within the supplied expression (i.e. definitions of these * units are not grafted onto the tree in place of the original nodes, * as is done by CreateTree). * Parameters: * exp * The units expression. This should not include any leading or * trailing spaces. * nc * The number of characters from "exp" to use. * lock * Use a mutex to guard access to the KnownUnits list? * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a UnitNode which forms the head of a tree of UnitNodes * representing the supplied unit expression. * Notes: * - A NULL value is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables: */ KnownUnit *munit; KnownUnit *unit; Multiplier *mmult; Multiplier *mult; Oper op; UnitNode *result; char buff[ 10 ]; char d; const char *c; double con; int depth; int i; int l; int maxlen; int n; int oplen; int plural; /* Initialise */ result = NULL; /* Check the global error status, and that we have a string. */ if ( !astOK || !exp || nc <= 0 ) return result; /* Scan through the supplied string from the end to the start looking for the last multiplication or division operator at zero depth of nesting within parentheses. We go backwards through the string in order to give the correct priority to multiple division operators (i.e. "a/b/c" needs to be interpreted as "(a/b)/c", not "a/(b/c)"). */ op = OP_NULL; oplen = 1; depth = 0; c = exp + nc - 1; i = nc - 1; while( i >= 0 ){ /* If this character is an opening parenthesis, decrement the depth of nesting. Report an error if it ever goes negative. */ if( *c == '(' ) { depth--; if( depth < 0 && astOK ) { astError( AST__BADUN, "Missing closing parenthesis." , status); break; } /* An opening parenthesis at level zero must always be either the first character in the string, or be preceded by the name of a function, or be preceded by an operator. If none of these are true, assume there is an implicit multiplication operator before the parenthesis. */ if( depth == 0 && i > 0 ) { d = *( c - 1 ); if( d != '*' && d != '/' && d != '^' && d != '.' && d != ' ' && !EndsWith( c, i + 1, "sqrt(", status ) && !EndsWith( c, i + 1, "exp(", status ) && !EndsWith( c, i + 1, "ln(", status ) && !EndsWith( c, i + 1, "log(", status ) ) { op = OP_MULT; oplen = 0; break; } } /* If this character is an closing parenthesis, increment the depth of nesting. */ } else if( *c == ')' ) { depth++; /* A closing parenthesis at level zero must always be either the last character in the string, or be followed by an operator. If neither of these are true, assume there is an implicit multiplication operator. */ if( depth == 1 && i < nc - 1 ) { d = *(c+1); if( d != '*' && d != '/' && d != '^' && d != '.' && d != ' ') { op = OP_MULT; oplen = 0; /* Correct "i" so that it gives the length of the left hand operand of the implicit MULT operator, correct "c" so that it points to the first character in the right hand operand, and leave the loop. */ i++; c++; break; } } /* Ignore all other characters unless they are at zero depth of nesting. */ } else if( depth == 0 ) { /* Compare the next part of the string with each of the multiplication and division operators. */ if( *c == '/' ) { op = OP_DIV; } else if( *c == ' ' ) { op = OP_MULT; /* An asterisk is only treated as a multiplication symbol if it does not occur before or after another asterisk. */ } else if( *c == '*' ) { if( c == exp ) { if( *(c+1) != '*' ) op = OP_MULT; } else if( i == nc - 1 ) { if( *(c-1) != '*' ) op = OP_MULT; } else { if( *(c+1) != '*' && *(c-1) != '*' ) op = OP_MULT; } /* A dot is only treated as a multiplication symbol if it does not occur between two digits. */ } else if( *c == '.' ) { if( ( c == exp || !isdigit( *(c-1) ) ) && ( i == nc - 1 || !isdigit( *(c+1) ) ) ) { op = OP_MULT; } } } /* If an operator was found, break out of the loop. */ if( op != OP_NULL ) break; /* Pass on to check the next character. */ i--; c--; } /* If a multiplication or division operator was found, the strings on either side of it should be valid unit expressions, in which case we use this routine recursively to create corresponding trees of UnitNodes. */ if( op != OP_NULL ) { /* Create a UnitNode for the binary operator. */ result = NewNode( NULL, op, status ); if( astOK ) { /* Create a tree of unit nodes from the string which precedes the binary operator. Report an error if it cannot be done. */ result->arg[ 0 ] = MakeTree( exp, i, lock, status ); if( !result->arg[ 0 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand before '%s'.", status, buff ); } /* Create a tree of unit nodes from the string which follows the binary operator. Report an error if it cannot be done. */ result->arg[ 1 ] = MakeTree( c + oplen, nc - i - oplen, lock, status ); if( !result->arg[ 1 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand after '%s'.", status, buff ); } } /* If no multiplication or division operator was found at depth zero, check that the final depth of nesting was zero. Report an error if not. */ } else if( depth > 0 && astOK ) { astError( AST__BADUN, "Missing opening parenthesis." , status); /* Otherwise check for a "Pow" operator at depth zero. */ } else { /* Scan through the supplied string looking for the first pow operator at zero depth of nesting within parentheses. */ depth = 0; c = exp; i = 0; while( i < nc && *c ){ /* If this character is an opening parenthesis, increment the depth of nesting. */ if( *c == '(' ) { depth++; /* If this character is an closing parenthesis, decrement the depth of nesting. Report an error if it ever goes negative. */ } else if( *c == ')' ) { depth--; if( depth < 0 && astOK ) { astError( AST__BADUN, "Missing opening parenthesis." , status); break; } /* Ignore all other characters unless they are at zero depth of nesting. */ } else if( depth == 0 ) { /* Compare the next part of the string with each of the "pow" operators. */ if( !strncmp( c, "**", 2 ) ) { op = OP_POW; oplen = 2; } else if( *c == '^' ) { op = OP_POW; oplen = 1; } /* If an operator was found, break out of the loop. */ if( op != OP_NULL ) break; } /* Pass on to check the next character. */ i++; c++; } /* If a "pow" operator was found, the strings on either side of it should be valid unit expressions, in which case we use this routine recursively to create corresponding trees of UnitNodes. */ if( op != OP_NULL ) { /* Create a UnitNode for the operator. */ result = NewNode( NULL, op, status ); if( astOK ) { /* Create a tree of unit nodes from the string which precedes the binary operator. Report an error if it cannot be done. */ result->arg[ 0 ] = MakeTree( exp, i, lock, status ); if( !result->arg[ 0 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand before '%s'.", status, buff ); } /* Create a tree of unit nodes from the string which follows the binary operator. Report an error if it cannot be done. */ result->arg[ 1 ] = MakeTree( c + oplen, nc - i - oplen, lock, status ); if( !result->arg[ 1 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing operand after '%s'.", status, buff ); } } /* If no binary operator was found at depth zero, see if the supplied string starts with a function name (the only legal place for a function name given that the string has no binary operators at depth zero). */ } else { if( !strncmp( exp, "sqrt(", 5 ) || !strncmp( exp, "SQRT(", 5 ) ) { op = OP_SQRT; oplen = 4; } else if( !strncmp( exp, "exp(", 4 ) || !strncmp( exp, "EXP(", 4 ) ) { op = OP_EXP; oplen = 3; } else if( !strncmp( exp, "ln(", 3 ) || !strncmp( exp, "LN(", 3 ) ) { op = OP_LN; oplen = 2; } else if( !strncmp( exp, "log(", 4 ) || !strncmp( exp, "LOG(", 4 ) ) { op = OP_LOG; oplen = 3; } /* If a function was found, the string following the function name (including the opening parenthesis) should form a legal units expresssion (all the supported functions take a single argument and so we do not need to worry about comma-separated lists of function arguments). Use this routine recursively to create a tree of UnitNodes from the string which forms the function argument. */ if( op != OP_NULL ) { /* Create a UnitNode for the function. */ result = NewNode( NULL, op, status ); if( astOK ) { /* Create a tree of unit nodes from the string which follows the function name. Report an error if it cannot be done. */ result->arg[ 0 ] = MakeTree( exp + oplen, nc - oplen, lock, status ); if( !result->arg[ 0 ] && astOK ) { for( i = 0; i < oplen; i++ ) buff[ i ] = c[ i ]; buff[ oplen ] = 0; astError( AST__BADUN, "Missing argument for '%s'.", status, buff ); } } /* Arrive here if the supplied string does not contain a binary operator or function at depth zero. Check to see if the whole string is contained within parentheses, In which we interpret the contents of the parentheses as a units expression. It is safe simply to check the first and last characters (a string like "(fred)(Harry)" is not a legal possibility since there should be an operator in the middle).*/ } else if( exp[ 0 ] == '(' && exp[ nc - 1 ] == ')' ) { result = MakeTree( exp + 1, nc - 2, lock, status ); /* Does the string begin with a numerical constant? */ } else if( ConStart( exp, &con, &n, status ) == 1 ) { /* If the entire string was a numerical constant, represent it by a LDCON node. */ if( n == nc ) { result = NewNode( NULL, OP_LDCON, status ); if( astOK ) result->con = con; /* If there was anything following the numerical constant, report an error. */ } else if( astOK ){ astError( AST__BADUN, "Missing operator after " "numerical string '%.*s'.", status, n, exp ); } /* Does the string represent one of the named constants? If so represent it by a an appropriate operator. */ } else if( nc == 2 && ( !strncmp( exp, "pi", 2 ) || !strncmp( exp, "PI", 2 ) ) ) { result = NewNode( NULL, OP_LDPI, status ); } else if( nc == 1 && ( !strncmp( exp, "e", 1 ) || !strncmp( exp, "E", 1 ) ) ) { result = NewNode( NULL, OP_LDE, status ); /* The only legal possibility left is that the string represents the name of a basic unit, possibly prefixed by a multiplier character. */ } else { /* See if the string ends with the symbol for any of the known basic units. If it matches more than one basic unit, choose the longest. First ensure descriptions of the known units are available. */ mmult = NULL; plural = 0; while( 1 ) { unit = GetKnownUnits( lock, status ); maxlen = -1; munit = NULL; while( unit ) { if( SplitUnit( exp, nc, unit->sym, 1, &mult, &l, status ) ) { if( l > maxlen ) { maxlen = l; munit = unit; mmult = mult; } } unit = unit->next; } /* If the above did not produce a match, try matching the unit symbol case insensitive. */ if( !munit ) { unit = GetKnownUnits( lock, status ); while( unit ) { if( SplitUnit( exp, nc, unit->sym, 0, &mult, &l, status ) ) { if( l > maxlen ) { maxlen = l; munit = unit; mmult = mult; } } unit = unit->next; } } /* If the above did not produce a match, try matching the unit label case insensitive. */ if( !munit ) { unit = GetKnownUnits( lock, status ); while( unit ) { if( SplitUnit( exp, nc, unit->label, 0, &mult, &l, status ) ) { if( l > maxlen ) { maxlen = l; munit = unit; mmult = mult; } } unit = unit->next; } } /* If we still do not have a match, and if the string ends with "s", try removing the "s" (which could be a plural as in "Angstroms") and trying again. */ if( !munit && nc > 1 && !plural && ( exp[ nc - 1 ] == 's' || exp[ nc - 1 ] == 'S' ) ) { plural = 1; nc--; } else { break; } } if( plural ) nc++; /* If a known unit and multiplier combination was found, create an OP_LDVAR node from it. */ unit = munit; mult = mmult; if( unit ) { /* If the unit is an alias for another unit, it will have a non-NULL value for its "use" component.In this case, use the unit for which the identified unit is an alias. */ result = NewNode( NULL, OP_LDVAR, status ); if( astOK ) { result->unit = unit->use ? unit->use : unit; result->mult = mult; result->name = astStore( NULL, result->unit->sym, result->unit->symlen + 1 ); } /* If no known unit and multiplier combination was found, we assume the string represents a new user-defined basic unit, possibly preceded by a standard multiplier prefix. */ } else { /* Check the string to see if starts with a known multiplier prefix (but do not allow the multiplier to account for the entire string). */ mult = GetMultipliers( status ); c = exp; while( mult ) { n = nc - mult->symlen; if( n > 0 && !strncmp( exp, mult->sym, mult->symlen ) ) { c += mult->symlen; break; } mult = mult->next; } if( !mult ) n = nc; /* Check there are no illegal characters in the following string. */ for( i = 0; i < n && astOK; i++ ) { if( !isalpha( c[ i ] ) ) { astError( AST__BADUN, "Illegal character '%c' found.", status, c[ i ] ); break; } } /* If succesfull, create an OP_LDVAR node for th user-defined basic unit. */ if( astOK ) { result = NewNode( NULL, OP_LDVAR, status ); if( astOK ) { result->mult = mult; result->name = astStore( NULL, c, n + 1 ); if( astOK ) ( (char *) result->name)[ n ] = 0; } } } } } } /* Free any returned tree if an error has occurred. */ if( !astOK ) result = FreeTree( result, status ); /* Return the result. */ return result; } static void MakeUnitAlias( const char *sym, const char *alias, int *status ){ /* * Name: * MakeUnitAlias * Purpose: * Create a KnownUnit structure describing an alias for a known unit. * Type: * Private function. * Synopsis: * #include "unit.h" * void MakeUnitAlias( const char *sym, const char *alias, int *status ) * Class Membership: * Unit member function. * Description: * This function creates a KnownUnit structure decribing an alias for a * known unit, and adds it to the head of the linked list of known units * stored in a module variable. An alias is a KnownUnit which is * identical to an existing known but which has a different symbol. * Parameters: * sym * A pointer to the symbol string of an existing KnwonUnit. The string * should not include any multiplier prefix. * alias * A pointer to the symbol string to use as the alasi for the existing * KnownUnit. The string should not include any multiplier prefix. * status * Pointer to the inherited status variable. * Notes: * - The supplied symbol and label strings are not copied. The * supplied pointers are simply stored in the returned structure. * Therefore the strings to which the pointers point should not be * modified after this function returned (in fact this function is * always called with literal strings for these arguments). */ /* Local Variables: */ KnownUnit *unit; /* Check the global error status. */ if( !astOK ) return; /* Search the existing list of KnownUnits for the specified symbol. */ unit = known_units; while( unit ) { if( !strcmp( sym, unit->sym ) ) { /* Create a new KnownUnit for the alias. It will becomes the head of the known units chain. */ MakeKnownUnit( alias, unit->label, NULL, status ); /* Store a pointer to the KnownUnit which is to be used in place of the alias. */ known_units->use = unit; /* Leave the loop. */ break; } /* Move on to check the next existing KnownUnit. */ unit = unit->next; } /* Report an error if the supplied unit was not found. */ if( !unit ) { astError( AST__INTER, "MakeUnitAlias(Unit): Cannot find existing " "units \"%s\" to associate with the alias \"%s\" (AST " "internal programming error).", status, sym, alias ); } } static UnitNode *ModifyPrefix( UnitNode *old, int *status ) { /* * Name: * ModifyPrefix * Purpose: * Replace a MULT or DIV node with a LDVAR and suitable multiplier. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *ModifyPrefix( UnitNode *old, int *status ) * Class Membership: * Unit member function. * Description: * This function checks the supplied node. If it is a DIV or MULT node * in which one argument is an LDVAR and the other is a constant, then * its checks to see if the constant can be absorbed into the LDVAR by * changing the multiplier in the LDVAR node. If so, it returns a new * node which is an LDVAR with the modified multiplier. Otherwise it * returns NULL. * Parameters: * old * Pointer to an existing UnitNode to be checked. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new UnitNode. * Notes: * - A value of NULL will be returned if this function is invoked with * the global error status set, or if it should fail for any reason. */ /* Local Variables: */ Multiplier *mult; Multiplier *mmult; UnitNode *ldcon; UnitNode *ldvar; UnitNode *newtree; UnitNode *result; double con; double cmult; double r; double rmin; int recip; int changed; /* Initialise. */ result = NULL; /* Check the inherited status. */ if( !astOK ) return result; /* Indicate that we have not yet found any reason to return a changed node. */ changed = 0; /* Check the supplied node is a DIV or MULT node. */ if( old->opcode == OP_DIV || old->opcode == OP_MULT ) { /* Get a copy of the supplied tree which we can modify safely. */ newtree = CopyTree( old, status ); /* Identify the LDVAR argument (if any). */ if( newtree->arg[ 0 ]->opcode == OP_LDVAR ) { ldvar = newtree->arg[ 0 ]; } else if( newtree->arg[ 1 ]->opcode == OP_LDVAR ) { ldvar = newtree->arg[ 1 ]; } else { ldvar = NULL; } /* Identify the LDCON argument (if any). */ if( newtree->arg[ 0 ]->opcode == OP_LDCON ) { ldcon = newtree->arg[ 0 ]; } else if( newtree->arg[ 1 ]->opcode == OP_LDCON ) { ldcon = newtree->arg[ 1 ]; } else { ldcon = NULL; } /* If either was not found, return NULL. */ if( !ldvar || !ldcon ) { newtree = FreeTree( newtree, status ); /* Otherwise, extract the multiplier constant. If there is no multiplier, the constant is 1.0. */ } else { cmult = ldvar->mult ? ldvar->mult->scale: 1.0; /* Extract the constant. */ con = ldcon->con; /* Combine the multiplier and the constant. The resulting constant is a factor which is used to multiply the LDVAR quantity. If the original node is a DIV node in which the LDVAR is in the denominator, then flag that we need to reciprocate the new MULT node which represents "constant*LDVAR" before returning. */ if( newtree->opcode == OP_MULT ) { con = con*cmult; recip = 0; } else { con = cmult/con; recip = ( ldvar == newtree->arg[ 1 ] ); } /* Find the closest known multiplier to the new constant. */ rmin = ( con > 1 ) ? con : 1.0/con; mmult = NULL; mult = GetMultipliers( status ); while( mult ) { r = ( con > mult->scale) ? con/mult->scale : mult->scale/con; if( r < rmin ) { mmult = mult; rmin = r; } mult = mult->next; } /* Modify the constant to take account of the new multiplier chosen above. "mmult" will be NULL if the best multiplier is unity. */ if( mmult ) con = con/mmult->scale; /* If they have changed, associate the chosen multiplier with the LDVAR node, and the constant with the LDCON node. */ if( ldvar->mult != mmult ) { ldvar->mult = mmult; changed = 1; } if( ldcon->con != con ) { ldcon->con = con; changed = 1; } /* Unless the node is proportional to the reciprocal of the variable, the new node should be a MULT node (it may originally have been a DIV). */ if( !recip ) { if( newtree->opcode != OP_MULT ){ newtree->opcode = OP_MULT; changed = 1; } /* If the constant is 1.0 we can just return the LDVAR node by itself. */ if( fabs( con - 1.0 ) < 1.0E-6 ) { result = CopyTree( ldvar, status ); newtree = FreeTree( newtree, status ); changed = 1; /* Otherwise return the modified tree containing both LDVAR and LDCON nodes. */ } else { result = newtree; } /* If the node is proportional to the reciprocal of the variable, the new node will already be a DIV node and will have an LDCON as the first argument (numerator) and an LDVAR as the second argument (denominator). */ } else { /* The first argument (the numerator) should be the reciprocal of the constant found above. */ ldcon->con = 1.0/ldcon->con; if( !EQUAL( ldcon->con, old->arg[0]->con ) ) changed = 1; /* Return the modified tree containing both LDVAR and LDCON nodes. */ result = newtree; } } } /* If the new and old trees are equivalent, then we do not need to return it. */ if( !changed && result ) result = FreeTree( result, status ); /* Return the answer. */ return result; } static UnitNode *NewNode( UnitNode *old, Oper code, int *status ) { /* * Name: * NewNode * Purpose: * Create and initialise a new UnitNode. * Type: * Private function. * Synopsis: * #include "unit.h" * UnitNode *NewNode( UnitNode *old, Oper code, int *status ) * Class Membership: * Unit member function. * Description: * This function creates and initialises a new UnitNode, or * re-initialises an existing UnitNode to use a different op code. * Parameters: * old * Pointer to an existing UnitNode to be modified, or NULL to create * a new UnitNode. * code * The op code for the new UnitNode. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new UnitNode. * Notes: * - A value of NULL will be returned if this function is invoked with * the global error status set, or if it should fail for any reason. */ /* Local Variables: */ UnitNode **args; UnitNode *result; int i; /* Initialise. */ result = NULL; args = NULL; /* Check the inherited status. */ if( !astOK ) return result; /* If an existig UnitNode was supplied, free any memory used to hold pointers to its arguments. */ if( old ) { old->arg = astFree( old->arg ); result = old; /* Otherwise, allocate memory for a new structure. */ } else { result = astMalloc( sizeof( UnitNode ) ); } /* Check the pointer can be used safely. */ if( astOK ) { /* Initialise the members of the UnitNode structure. */ result->opcode = code; result->arg = NULL; result->con = AST__BAD; result->name = NULL; result->unit = NULL; result->mult = NULL; result->narg = 0; switch( code ){ case OP_LDPI: result->con = PI; break; case OP_LDE: result->con = E; break; case OP_LOG: case OP_LN: case OP_EXP: case OP_SQRT: result->narg = 1; break; case OP_POW: case OP_DIV: case OP_MULT: result->narg = 2; break; default: ; } /* Allocate memory for the UnitNode pointers which will locate the nodes forming the arguments to the new node. */ args = astMalloc( (result->narg)*sizeof( UnitNode * ) ); if( astOK ) { result->arg = args; /* Initialise the argument pointers to NULL. */ for( i = 0; i < result->narg; i++ ) args[ i ] = NULL; } } /* Free any result if an error occurred. */ if( !astOK ) { args = astFree( args ); result = astFree( result ); } /* Return the answer. */ return result; } static void RemakeTree( UnitNode **node, int *status ) { /* * Name: * RemakeTree * Purpose: * Replace derived units within a tree of UnitNodes by basic units. * Type: * Private function. * Synopsis: * #include "unit.h" * void RemakeTree( UnitNode **node, int *status ) * Class Membership: * Unit member function. * Description: * This function searches for LDVAR nodes (i.e. references to unit * symbols) within the given tree, and replaces each such node which * refers to known derived unit with a sub-tree of nodes which * define the derived unit in terms of known basic units. * Parameters: * node * The address of a pointer to the UnitNode at the head of the tree * which is to be simplified. On exit the supplied tree is freed and a * pointer to a new tree is placed at the given address. * status * Pointer to the inherited status variable. */ /* Local Variables: */ KnownUnit *unit; int i; UnitNode *newnode; /* Check inherited status. */ if( !astOK ) return; /* Initially, we have no replacement node */ newnode = NULL; /* If this is an LDVAR node... */ if( (*node)->opcode == OP_LDVAR ) { /* If the LDVAR node has a multiplier associated with it, we need to introduce a OP_MULT node to perform the scaling. */ if( (*node)->mult ) { newnode = NewNode( NULL, OP_MULT, status ); if( astOK ) { newnode->arg[0] = NewNode( NULL, OP_LDCON, status ); if( astOK ) { newnode->arg[0]->con = 1.0/(*node)->mult->scale; /* See if the node refers to a known unit. If not, or if the known unit is a basic unit (i.e. not a derived unit) use the supplied node for the second argument of the OP_MULT node (without the multiplier). Otherwise, use a copy of the tree which defines the derived unit. */ unit = (*node)->unit; if( unit && unit->head ) { newnode->arg[1] = CopyTree( unit->head, status ); } else { newnode->arg[1] = CopyTree( *node, status ); if( astOK ) newnode->arg[1]->mult = NULL; } } } /* If no multiplier is supplied, the replacement node is simply the tree which defines the unscaled unit (if known), or the original node (if unknown). */ } else { unit = (*node)->unit; if( unit && unit->head ) newnode = CopyTree( unit->head, status ); } /* If this is not an LDVAR Node, remake the sub-trees which form the arguments of this node. */ } else { for( i = 0; i < (*node)->narg; i++ ) { RemakeTree( &((*node)->arg[ i ]), status ); } } /* If an error has occurred, free any new node. */ if( !astOK ) newnode = FreeTree( newnode, status ); /* If we have a replacement node, free the supplied tree and return a pointer to the new tree. */ if( newnode ) { FreeTree( *node, status ); *node = newnode; } } static int ReplaceNode( UnitNode *target, UnitNode *old, UnitNode *new, int *status ) { /* * Name: * ReplaceNode * Purpose: * Replace a node within a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * int ReplaceNode( UnitNode *target, UnitNode *old, UnitNode *new, int *status ) * Class Membership: * Unit member function. * Description: * This function replaces a specified node within a tree of UnitNodes * with another given node. The original node is freed if found. * Parameters: * target * A pointer to the UnitNode at the head of the tree containing the * node to be replaced. * old * A pointer to the UnitNode to be replaced. * new * A pointer to the UnitNode to replace "old". * status * Pointer to the inherited status variable. * Return Value: * Non-zero if the "old" node was found and replaced (in which case * the "old" node will have been freed). * Notes: * - It is assumed that the "old" node occurs at most once within the * target tree. * - The node at the head of the target tree is not compared with the * "old" node. It is assumed the called will already have done this. * - A value of zero is returned if an error has already occurred, or * if this function fails for any reason. */ /* Local Variables: */ int i; int result; /* Initialise */ result = 0; /* Check inherited status. */ if( !astOK ) return result; /* Loop round the arguments of the node at the head of the target tree. Break out of the loop as soone as the old node is found. */ for( i = 0; i < target->narg; i++ ) { /* If this argument is the node to be replaced, free the old one and store the new one, and then leave the loop. */ if( target->arg[ i ] == old ) { FreeTree( old, status ); target->arg[ i ] = new; result = 1; break; /* Otherwise use this function recursively to search for the old node within the current argument. */ } else { if( ReplaceNode( target->arg[ i ], old, new, status ) ) break; } } /* If an error has occurred, return zero. */ if( !astOK ) result = 0; /* Return the answer. */ return result; } static int SimplifyTree( UnitNode **node, int std, int *status ) { /* * Name: * SimplifyTree * Purpose: * Simplify a tree of UnitNodes. * Type: * Private function. * Synopsis: * #include "unit.h" * int SimplifyTree( UnitNode **node, int std, int *status ) * Class Membership: * Unit member function. * Description: * This function simplifies a tree of UnitNodes. It is assumed that * all the OP_LDVAR nodes in the tree refer to the same basic unit. * A primary purpose of this function is to standardise the tree so * that trees which implement equivalent transformations but which * have different structures can be compared (for instance, so that * "2*x" and "x*2" are treated as equal trees). If "std" is non-zero, * reducing the complexity of the tree is only of secondary importance. * This explains why some "simplifications" actually produced trees which * are more complicated. * Parameters: * node * The address of a pointer to the UnitNode at the head of the tree * which is to be simplified. On exit the supplied tree is freed and a * pointer to a new tree is placed at the given address. * std * If non-zero, perform standardisations. Otherwise only perform * genuine simplifications. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if some change was made to the tree. */ /* Local Variables: */ int i; UnitNode *newnode; UnitNode *node1; UnitNode *node2; Oper op; UnitNode **factors; double *powers; int nfactor; double coeff; int result; /* Initialise */ result = 0; /* Check inherited status. */ if( !astOK ) return result; /* Initiallially, we have no replacement node. */ newnode = NULL; /* First replace any complex constant expressions any corresponding OP_LDCON nodes. */ FixConstants( node, 0, status ); /* Simplify the sub-trees corresponding to the arguments of the node at the head of the supplied tree. */ for( i = 0; i < (*node)->narg; i++ ) { if( SimplifyTree( &( (*node)->arg[ i ] ), std, status ) ) result = 1; } /* Now do specific simplifications appropriate to the nature of the node at the head of the tree. */ op = (*node)->opcode; /* Natural log */ /* =========== */ /* We standardise argument powers into coefficients of the LN value. */ if( op == OP_LN ) { /* If the argument is a OP_EXP node, they cancel out. Return a copy of the argument of OP_EXP node. */ if( (*node)->arg[ 0 ]->opcode == OP_EXP ) { newnode = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); /* If the argument is an OP_POW node, rearrange the nodes to represent k*ln(x) instead of ln(x**k) (note pow nodes always have a constant exponent - this is checked in InvertConstants). SQRT arguments will not occur because they will have been changed into POW nodes when the arguments of the supplied head node were simplified above. */ } else if( std && (*node)->arg[ 0 ]->opcode == OP_POW ) { newnode = NewNode( NULL, OP_MULT, status ); node1 = CopyTree( (*node)->arg[ 0 ]->arg[ 1 ], status ); node2 = NewNode( NULL, OP_LN, status ); if( astOK ) { node2->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = node2; } } /* Common log */ /* ========== */ /* We standardise natural logs into common logs. */ } else if( op == OP_LOG ) { if( std ) { newnode = NewNode( NULL, OP_DIV, status ); node1 = NewNode( NULL, OP_LN, status ); node2 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node1->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ], status ); node2->con = log( 10.0 ); newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = node2; } } /* Exponential */ /* =========== */ /* We prefer to minimise the number of EXP nodes, so, for instance, we do not change "exp(x*y)" to "exp(x)+exp(y)" (and the code for ADD nodes does the inverse conversion). */ } else if( op == OP_EXP ) { /* If the argument is an OP_LN node, they cancel out. Return a copy of the argument of the OP_LN node. Common log arguments will not occur because they will have been changed into natural logs when the arguments of the supplied head node were simplified above. */ if( (*node)->arg[ 0 ]->opcode == OP_LN ) { newnode = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); } /* Square root */ /* =========== */ /* We standardise sqrt nodes into pow nodes. */ } else if( op == OP_SQRT ) { if( std ) { newnode = NewNode( NULL, OP_POW, status ); node1 = CopyTree( (*node)->arg[ 0 ], status ); node2 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node2->con = 0.5; newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = node2; } } /* Exponentiation */ /* ============== */ /* We want to simplfy factors. So, for instance, (x*y)**k is converted to (x**k)*(y**k). */ } else if( op == OP_POW ) { /* If the first argument is an OP_EXP node, then change "(e**x)**k" into "e**(k*x)" */ if( (*node)->arg[ 0 ]->opcode == OP_EXP ) { newnode = NewNode( NULL, OP_EXP, status ); node1 = NewNode( NULL, OP_MULT, status ); if( astOK ) { node1->arg[ 0 ] = CopyTree( (*node)->arg[ 1 ], status ); node1->arg[ 1 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); newnode->arg[ 0 ] = node1; } /* "x**0" can be replaced by 1.0 */ } else if( (*node)->arg[ 1 ]->con == 0.0 ) { newnode = NewNode( NULL, OP_LDCON, status ); if( astOK ) newnode->con = 1.0; /* "x**1" can be replaced by x */ } else if( EQUAL( (*node)->arg[ 1 ]->con, 1.0 ) ) { newnode = CopyTree( (*node)->arg[ 0 ], status ); /* If the first argument is an OP_POW node, then change "(x**k1)**k2" into "x**(k1*k2)" */ } else if( (*node)->arg[ 0 ]->opcode == OP_POW ) { newnode = NewNode( NULL, OP_POW, status ); node1 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node1->con = ( (*node)->arg[ 0 ]->arg[ 1 ]->con )* ( (*node)->arg[ 1 ]->con ); newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); newnode->arg[ 1 ] = node1; } /* If the first argument is an OP_MULT node, then change "(x*y)**k" into "(x**(k))*(y**(k))" */ } else if( std && (*node)->arg[ 0 ]->opcode == OP_MULT ) { newnode = NewNode( NULL, OP_MULT, status ); node1 = NewNode( NULL, OP_POW, status ); if( astOK ) { node1->arg[ 1 ] = CopyTree( (*node)->arg[ 1 ], status ); node2 = CopyTree( node1, status ); node1->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 0 ], status ); node2->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ]->arg[ 1 ], status ); newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = node2; } } /* Division. */ /* ========= */ /* We standardise divisions into corresponding multiplications. */ } else if( op == OP_DIV ) { /* Division by 1 is removed. */ if( EQUAL( (*node)->arg[ 1 ]->con, 1.0 ) ){ newnode = CopyTree( (*node)->arg[ 0 ], status ); /* Division by any other constant (except zero) is turned into a multiplication by the reciprocal constant. */ } else if( (*node)->arg[ 1 ]->con != AST__BAD ) { if( (*node)->arg[ 1 ]->con != 0.0 ) { newnode = NewNode( NULL, OP_MULT, status ); node1 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node1->con = 1.0/(*node)->arg[ 1 ]->con; newnode->arg[ 0 ] = node1; newnode->arg[ 1 ] = CopyTree( (*node)->arg[ 0 ], status ); } } else { astError( AST__BADUN, "Simplifying a units expression" "requires a division by zero." , status); } /* Other divisions "x/y" are turned into "x*(y**(-1))" */ } else if( std ) { newnode = NewNode( NULL, OP_MULT, status ); node1 = NewNode( NULL, OP_POW, status ); node2 = NewNode( NULL, OP_LDCON, status ); if( astOK ) { node2->con = -1.0; node1->arg[ 0 ] = CopyTree( (*node)->arg[ 1 ], status ); node1->arg[ 1 ] = node2; newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 0 ], status ); newnode->arg[ 1 ] = node1; } } /* Multiplication */ /* ============== */ } else if( op == OP_MULT ) { /* If the right hand argument is constant, swap the arguments. */ if( (*node)->arg[ 1 ]->con != AST__BAD ) { newnode = NewNode( NULL, OP_MULT, status ); if( astOK ) { newnode->arg[ 0 ] = CopyTree( (*node)->arg[ 1 ], status ); newnode->arg[ 1 ] = CopyTree( (*node)->arg[ 0 ], status ); } /* Multiplication by zero produces a constant zero. */ } else if( (*node)->arg[ 0 ]->con == 0.0 ){ newnode = NewNode( NULL, OP_LDCON, status ); if( astOK ) newnode->con = 0.0; /* Multiplication by 1 is removed. */ } else if( EQUAL( (*node)->arg[ 0 ]->con, 1.0 ) ){ newnode = CopyTree( (*node)->arg[ 1 ], status ); /* For other MULT nodes, analyse the tree to find a list of all its factors with an associated power for each one, and an overall constant coefficient. */ } else if( std ) { FindFactors( (*node), &factors, &powers, &nfactor, &coeff, status ); /* Produce a new tree from these factors. The factors are standardised by ordering them alphabetically (after conversion to a character string). */ newnode = CombineFactors( factors, powers, nfactor, coeff, status ); /* Free resources */ factors = astFree( factors ); powers = astFree( powers ); } } /* If we have produced a new node which is identical to the old node, free it. Otherwise, indicate we have made some changes. */ if( newnode ) { if( !CmpTree( newnode, *node, 1, status ) ) { newnode = FreeTree( newnode, status ); } else { result = 1; } } /* If an error has occurred, free any new node. */ if( !astOK ) newnode = FreeTree( newnode, status ); /* If we have a replacement node, free the supplied tree and return a pointer to the new tree. */ if( newnode ) { FreeTree( *node, status ); *node = newnode; } /* If the above produced some change, try re-simplifying the tree. */ if( result ) SimplifyTree( node, std, status ); /* Return the result. */ return result; } static int SplitUnit( const char *str, int ls, const char *u, int cs, Multiplier **mult, int *l, int *status ) { /* * Name: * SplitUnit * Purpose: * Split a given string into unit name and multiplier. * Type: * Private function. * Synopsis: * #include "unit.h" * int SplitUnit( const char *str, int ls, const char *u, int cs, * Multiplier **mult, int *l, int *status ) * Class Membership: * Unit member function. * Description: * Returns non-zer0 if the supplied string ends with the supplied unit * name or label, and any leading string is a known multiplier. * Parameters: * str * The string to test, typically containing a multiplier and a unit * symbol or label. * ls * Number of characters to use from "str" (not including trailing null) * u * Pointer to the unit label or symbol string to be searched for. * cs * If non-zero, the test for "u" is case insensitive. * mult * Address of a location at which to return the multiplier at the * start of the supplied string. NULL is returned if the supplied * string does not match the supplied unit, or if the string * includes no multiplier. * l * Address of an int in which to return the length of "u". * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if "str" ends with "u" and starts with a null string or a * known multiplier string. */ /* Local Variables: */ int ret; int lm; int lu; /* Initialise */ ret = 0; *mult = NULL; *l = 0; /* Check inherited status. */ if( !astOK ) return ret; /* Find the number of characters in the supplied unit label or symbol. The difference between lu and ls must be the length of the multiplier. */ lu = strlen( u ); lm = ls - lu; /* Make sure "str" is not shorter than "u" */ if( lm >= 0 ) { /* Compare the end of "str" against "u" */ if( cs ? !strncmp( str + lm, u, lu ) : !Ustrncmp( str + lm, u, lu, status ) ) { ret = 1; /* If "str" ends with "u", see if it starts with a known multiplier */ if( lm > 0 ) { ret = 0; *mult = GetMultipliers( status ); while( *mult ) { if( (*mult)->symlen == lm && !strncmp( str, (*mult)->sym, lm ) ) { ret = 1; break; } *mult = (*mult)->next; } /* If not, try again using case-insensitive matching. */ if( !ret ) { *mult = GetMultipliers( status ); while( *mult ) { if( (*mult)->symlen == lm && !Ustrncmp( str, (*mult)->sym, lm, status ) ) { ret = 1; break; } *mult = (*mult)->next; } } /* If not, try again using case-insensitive matching against the multiplier label. */ if( !ret ) { *mult = GetMultipliers( status ); while( *mult ) { if( (*mult)->lablen == lm && !Ustrncmp( str, (*mult)->label, lm, status ) ) { ret = 1; break; } *mult = (*mult)->next; } } } } } *l = lu; return ret; } double astUnitAnalyser_( const char *in, double powers[9], int *status ){ /* *+ * Name: * astUnitAnalyser * Purpose: * Perform a dimensional analysis of a unti string. * Type: * Protected function. * Synopsis: * #include "unit.h" * double astUnitAnalyser_( const char *in, double powers[9] ) * Class Membership: * Unit member function. * Description: * This function parses the supplied units string if possible, and * returns a set of pwoers and a scaling factor which represent the * units string. * Parameters: * in * A string representation of the units, for instance "km/h". * powers * An array in which are returned the powers for each of the following * basic units (in the order shown): kilogramme, metre, second, radian, * Kelvin, count, adu, photon, magnitude, pixel. If the supplied unit * does not depend on a given basic unit a value of 0.0 will be returned * in the array. The returns values represent a system of units which is * a scaled form of the supplied units, expressed in the basic units of * m, kg, s, rad, K, count, adu, photon, mag and pixel. For instance, a * returned array of [1,0,-2,0,0,0,0,0,0] would represent "m/s**2". * Returned Value: * A scaling factor for the supplied units. The is the value, in the * units represented by the returned powers, which corresponds to a * value of 1.0 in the supplied units. * Notes: * - An error will be reported if the units string cannot be parsed * or refers to units or functions which cannot be analysed in this way. * - AST__BAD is returned if this function is invoked with the * global error status set or if it should fail for any reason. *- */ /* Local Variables: */ UnitNode *in_tree; double result; /* Initialise */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Parse the input units string, producing a tree of UnitNodes which represents the input units. A pointer to the UnitNode at the head of the tree is returned if succesfull. Report a context message if this fails. */ in_tree = CreateTree( in, 1, 1, status ); if( in_tree ) { /* Analyse the tree */ if( !DimAnal( in_tree, powers, &result, status ) && astOK ) { result = AST__BAD; astError( AST__BADUN, "astUnitAnalyser: Error analysing input " "units string '%s' (it may contain unsupported " "functions or dimensionless units).", status, in ); } /* Free the tree. */ in_tree = FreeTree( in_tree, status ); } else if( astOK ) { astError( AST__BADUN, "astUnitAnalyser: Error parsing input " "units string '%s'.", status, in ); } /* Return the result */ return result; } const char *astUnitLabel_( const char *sym, int *status ){ /* *+ * Name: * astUnitLabel * Purpose: * Return a string label for a given unit symbol. * Type: * Protected function. * Synopsis: * #include "unit.h" * const char *astUnitLabel( const char *sym ) * Class Membership: * Unit member function. * Description: * This function returns a pointer to a constant string containing a * descriptive label for the unit specified by the given unit symbol. * Parameters: * sym * A string holing a known unit symbol. * Returned Value: * A pointer to constant string holding a descriptive label for the * supplied unit. A NULL pointer is returned (without error) if the * supplied unit is unknown. * Notes: * - A NULL pointer is returned if this function is invoked with the * global error status set or if it should fail for any reason. *- */ /* Local Variables: */ const char *result; KnownUnit *unit; /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Ensure descriptions of the known units are available. */ unit = GetKnownUnits( 1, status ); /* Loop through the chain of known units looking for a unit with a symbol equal to the supplied string. If found, store a pointer to its label and break out of the loop. */ while( unit ) { if( !strcmp( sym, unit->sym ) ) { result = unit->label; break; } unit = unit->next; } /* Return the answer. */ return result; } AstMapping *astUnitMapper_( const char *in, const char *out, const char *in_lab, char **out_lab, int *status ){ /* *+ * Name: * astUnitMapper * Purpose: * Create a Mapping between two system of units. * Type: * Protected function. * Synopsis: * #include "unit.h" * AstMapping *astUnitMapper( const char *in, const char *out, * const char *in_lab, char **out_lab ) * Class Membership: * Unit member function. * Description: * This function creates a Mapping between two specified system of * units. It also modifes a supplied label (which is typically * the axis label associated with the input units) so that it includes * any functional change implied by the supplied "in" and "out" units. * Parameters: * in * A string representation of the input units, for instance "km/h". * See "Unit Representations:" below. * out * A string representation of the output units, for instance "m/s". * See "Unit Representations:" below. * in_lab * A label describing the quantity associated with the input units. * If the "in" string is the Units attribute of an Axis, then * "in_lab" should be the Label of the same Axis. May be supplied * NULL in which case "out_lab" is ignored. * out_lab * The address at which to return a pointer to a label describing the * quantity associated with the output units. For instance, if the * input and output units are "Hz" and "sqrt(Hz)", and the input * label is "Frequency", then the returned output label will be * "sqrt( Frequency )". The returned label is stored in dynamically * allocated memory which should be freed (using astFree) when no longer * needed. * Returned Value: * A pointer to a Mapping which can be used to transform values in the * "in" system of units into the "out" system of units. The Mapping * will have 1 input and 1 output. * Unit Representations: * The string supplied for "in" and "out" should represent a system of * units following the recommendations of the FITS WCS paper I * "Representation of World Coordinates in FITS" (Greisen & Calabretta). * Various commonly used variants are also allowed. * * To summarise, a string describing a system of units should be an * algebraic expression which combines one or more named units. The * following functions and operators may be used within these algebraic * expressions: * * - "*": multiplication. A period "." or space " " may also be used * to represent multiplication (a period is only interpreted as a * multiplication operator if it is not positioned between two digits, * and a space is only interpreted as a multiplication operator if it * occurs between two operands). * - "/": division. * - "**": exponentiation. The exponent (i.e. the operand following the * exponentiation operator) must be a constant. The symbol "^" is also * interpreted as an exponentiation operator. Exponentiation is also * implied by an integer following a unit name without any separator * (e.g. "cm2" is "cm^2"). * - log(): Common logarithm. * - ln(): Natural logarithm. * - sqrt(): Square root. * - exp(): Exponential. * * Function names are case insensitive. White space may be included * within an expression (note that white space between two operands * will be interpreted as a muiltiplication operator as described * above). Parentheses may be used to indicate the order in which * expressions are to be evaluated (normal mathematical precedence is * used otherwise). The following symbols may be used to represent * constants: * * - "pi" * - "e" * * These symbols are also case in-sensitive. * * The above operators and functions are used to combine together one * or more "unit symbols". The following base unit symbols are recognised: * * - "m": metre. * - "g": gram. * - "s": second. * - "rad": radian. * - "sr": steradian. * - "K": Kelvin. * - "mol": mole. * - "cd": candela. * * The following symbols for units derived fro the above basic units are * recognised: * * - "sec": second (1 s) * - "Hz": Hertz (1/s). * - "N": Newton (kg m/s**2). * - "J": Joule (N m). * - "W": Watt (J/s). * - "C": Coulomb (A s). * - "V": Volt (J/C). * - "Pa": Pascal (N/m**2). * - "Ohm": Ohm (V/A). * - "S": Siemens (A/V). * - "F": Farad (C/V). * - "Wb": Weber (V s). * - "T": Tesla (Wb/m**2). * - "H": Henry (Wb/A). * - "lm": lumen (cd sr). * - "lx": lux (lm/m**2). * - "deg": degree (pi/180 rad). * - "arcmin": arc-minute (1/60 deg). * - "arcsec": arc-second (1/3600 deg). * - "mas": milli-arcsecond (1/3600000 deg). * - "min": minute (60 s). * - "h": hour (3600 s). * - "d": day (86400 s). * - "yr": year (31557600 s). * - "a": year (31557600 s). * - "eV": electron-Volt (1.60217733E-19 J). * - "erg": erg (1.0E-7 J). * - "Ry": Rydberg (13.605692 eV). * - "solMass": solar mass (1.9891E30 kg). * - "u": unified atomic mass unit (1.6605387E-27 kg). * - "solLum": solar luminosity (3.8268E26 W). * - "Angstrom": Angstrom (1.0E-10 m). * - "Ang": Angstrom * - "A": Ampere * - "micron": micron (1.0E-6 m). * - "solRad": solar radius (6.9599E8 m). * - "AU": astronomical unit (1.49598E11 m). * - "lyr": light year (9.460730E15 m). * - "pc": parsec (3.0867E16 m). * - "count": count. * - "ct": count. * - "adu": analogue-to-digital converter unit. * - "photon": photon. * - "ph": photon. * - "Jy": Jansky (1.0E-26 W /m**2 /Hz). * - "Jan": Jansky * - "mag": magnitude. * - "G": Gauss (1.0E-4 T). * - "pixel": pixel. * - "pix": pixel. * - "barn": barn (1.0E-28 m**2). * - "D": Debye (1.0E-29/3 C.m). * * In addition, any other unknown unit symbol may be used (but of course * no mapping will be possible between unknown units). * * Unit symbols may be preceded with a numerical constant (for * instance "1000 m") or a standard multiplier symbol (for instance "km") * to represent some multiple of the unit. The following standard * multipliers are recognised: * * - "d": deci (1.0E-1) * - "c": centi (1.0E-2) * - "m": milli (1.0E-3) * - "u": micro (1.0E-6) * - "n": nano (1.0E-9) * - "p": pico (1.0E-12) * - "f": femto (1.0E-15) * - "a": atto (1.0E-18) * - "z": zepto (1.0E-21) * - "y": yocto (1.0E-24) * - "da": deca (1.0E1) * - "h": hecto (1.0E2) * - "k": kilo (1.0E3) * - "M": mega (1.0E6) * - "G": giga (1.0E9) * - "T": tera (1.0E12) * - "P": peta (1.0E15) * - "E": exa (1.0E18) * - "Z": zetta (1.0E21) * - "Y": yotta (1.0E24) * Notes: * - NULL values are returned without error if the supplied units are * incompatible (for instance, if the input and output units are "kg" * and "m" ). * - NULL values are returned if this function is invoked with the * global error status set or if it should fail for any reason. *- */ /* Local Variables: */ AstMapping *result; UnitNode **units; UnitNode *in_tree; UnitNode *intemp; UnitNode *inv; UnitNode *labtree; UnitNode *newtest; UnitNode *out_tree; UnitNode *outtemp; UnitNode *src; UnitNode *testtree; UnitNode *tmp; UnitNode *totaltree; UnitNode *totlabtree; const char *c; const char *exp; int i; int nc; int nunits; int ipass; /* Initialise */ result = NULL; if( in_lab ) *out_lab = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* A quick check for a common simple case: if the two strings are identical, return a UnitMap.*/ if( !strcmp( in, out ) ) { if( in_lab ) *out_lab = astStore( NULL, in_lab, strlen( in_lab ) + 1 ); return (AstMapping *) astUnitMap( 1, "", status ); } /* More initialisation. */ in_tree = NULL; out_tree = NULL; units = NULL; /* Parse the input units string, producing a tree of UnitNodes which represents the input units. A pointer to the UnitNode at the head of the tree is returned if succesfull. Report a context message if this fails. The returned tree contains branch nodes which correspond to operators or functions, and leaf nodes which represent constant values or named basic units (m, s, g, K, etc). Each branch node has one or more "arguments" (i.e. child nodes) which are operated on or combined by the branch node in some way to produce the nodes "value". This value is then used as an argument for the node's parent node (if any). If the string supplied by the user refers to any known derived units (e.g. "N", Newton) then each such unit is represented in the returned tree by a complete sub-tree in which the head node corresponds to the derived unit (e.g. "N") and the leaf nodes correspond to the basic units needed to define the derived unit ( for instance, "m", "s" and "g" - metres, seconds and grammes), or numerical constants. Thus every leaf node in the returned tree will be a basic unit (i.e. a unit which is not defined in terms of other units), or a numerical constant. */ in_tree = CreateTree( in, 1, 1, status ); if( !astOK ) astError( AST__BADUN, "astUnitMapper: Error parsing input " "units string '%s'.", status, in ); /* Do the same for the output units. */ if( astOK ) { out_tree = CreateTree( out, 1, 1, status ); if( !astOK ) astError( AST__BADUN, "astUnitMapper: Error parsing output " "units string '%s'.", status, out ); } /* If a blank string is supplied for both input and output units, then assume a UnitMap is the appropriate Mapping. */ if( !in_tree && !out_tree && astOK ) { result = (AstMapping *) astUnitMap( 1, "", status ); if( in_lab ) *out_lab = astStore( NULL, in_lab, strlen( in_lab ) + 1 ); /* Otherwise, if we have both input and output trees... */ } else if( in_tree && out_tree && astOK ) { /* Locate all the basic units used within either of these two trees. An array is formed in which each element is a pointer to a UnitNode contained within one of the trees created above. Each basic unit referred to in either tree will have a single entry in this array (even if the unit is referred to more than once). */ units = NULL; nunits = 0; LocateUnits( in_tree, &units, &nunits, status ); LocateUnits( out_tree, &units, &nunits, status ); /* Due to the simple nature of the simplification process in SimplifyTree, the following alogorithm sometimes fails to find a Mapping form input to output units, but can find a Mapping from output to input units. In this latter case, we can get the required Mapping from input to output simply by inverting the Mapign from output to input. So try first with the units in the original order. If this fails to find a Mapping, try again with the units swapped, and note that the final Mapping should be inverted before being used. */ for( ipass = 0; ipass < 2; ipass++ ){ if( ipass == 1 ) { tmp = in_tree; in_tree = out_tree; out_tree = tmp; } /* We are going to create a new tree of UnitNodes in which the head node corresponds to the requested output units, and which has a single non-constant leaf node corresponding to the input units. Initialise a pointer to this new tree to indicate that it has not yet been created. */ testtree = NULL; /* Loop round each basic unit used in the definition of either the input or the output units (i.e. the elements of the array created above by "LocateUnits"). The unit selected by this loop is referred to as the "current" unit. On each pass through this loop, we create a tree which is a candidate for the final required tree (the "test tree" pointed to by the testtree pointer initialised above). In order for a mapping to be possible between input and output units, the test tree created on each pass through this loop must be equivalent to the test tree for the previous pass (in other words, all the test trees must be equivalent). We break out of the loop (and return a NULL Mapping) as soon as we find a test tree which differs from the previous test tree. */ for( i = 0; i < nunits; i++ ) { /* Create copies of the trees describing the input and output units, in which all units other than the current unit are set to a constant value of 1. This is done by replacing OP_LDVAR nodes (i.e. nodes which "load" the value of a named basic unit) by OP_LDCON nodes (i.e. nodes which load a specified constant value) in the tree copy. */ intemp = FixUnits( in_tree, units[ i ], status ); outtemp = FixUnits( out_tree, units[ i ], status ); /* Simplify these trees. An important side-effect of this simplification is that trees are "standardised" which allows them to be compared for equivalence. A single mathematical expression can often be represented in many different ways (for instance "A/B" is equivalent to "(B**(-1))*A"). Standardisation is a process of forcing all equivalent representations into a single "standard" form. Without standardisation, trees representing the above two expressions would not be considered to be equivalent since thy would contain different nodes and have different structures. As a consequence of this standardisation, the "simplification" performed by SimplifyTree can sometimes actually make the tree more complicated (in terms of the number of nodes in the tree). */ SimplifyTree( &intemp, 1, status ); SimplifyTree( &outtemp, 1, status ); /* If either of the simplified trees does not depend on the current unit, then the node at the head of the simplified tree will have a constant value (because all the units other than the current unit have been fixed to a constant value of 1.0 above by FixUnits, leaving only the current unit to vary in value). If both simplified trees are constants, then neither tree depends on the current basic unit (i.e. references to the current basic unit cancel out within each string expression - for instance if converting from "m.s.Hz" to "km" and the current unit is "s", then the "s.Hz" term will cause the "s" units to cancel out). In this case ignore this basic unit and pass on to the next. */ if( outtemp->con != AST__BAD && intemp->con != AST__BAD ) { /* If just one simplified tree is constant, then the two units cannot match since one depends on the current basic unit and the other does not. Free any test tree from previous passes and break out of the loop. */ } else if( outtemp->con != AST__BAD || intemp->con != AST__BAD ) { intemp = FreeTree( intemp, status ); outtemp = FreeTree( outtemp, status ); testtree = FreeTree( testtree, status ); break; /* If neither simplified tree is constant, both depend on the current basic unit and so we can continue to see if their dependencies are equivalent. */ } else { /* We are going to create a new tree which is the inverse of the above simplified "intemp" tree. That is, the new tree will have a head node corresponding to the current unit, and a single non-constant leaf node corresponding to the input units. Create an OP_LDVAR node which can be used as the leaf node for this inverted tree. If the input tree is inverted successfully, this root node becomes part of the inverted tree, and so does not need to be freed explicitly (it will be freed when the inverted tree is freed). */ src = NewNode( NULL, OP_LDVAR, status ); if( astOK ) src->name = astStore( NULL, "input_units", 12 ); /* Now produce the inverted input tree. If the tree cannot be inverted, a null pointer is returned. Check for this. Otherwise a pointer to the UnitNode at the head of the inverted tree is returned. */ inv = InvertTree( intemp, src, status ); if( inv ) { /* Concatenate this tree (which goes from "input units" to "current unit") with the simplified output tree (which goes from "current unit" to "output units"), to get a new tree which goes from input units to output units. */ totaltree = ConcatTree( inv, outtemp, status ); /* Simplify this tree. */ SimplifyTree( &totaltree, 1, status ); /* Compare this simplified tree with the tree produced for the previous unit (if any). If they differ, we cannot map between the supplied units so annul the test tree and break out of the loop. If this is the first unit to be tested, use the total tree as the test tree for the next unit. */ if( testtree ) { if( CmpTree( totaltree, testtree, 0, status ) ) testtree = FreeTree( testtree, status ); totaltree = FreeTree( totaltree, status ); if( !testtree ) break; } else { testtree = totaltree; } } /* If the input tree was inverted, free the inverted tree. */ if( inv ) { inv = FreeTree( inv, status ); /* If the input tree could not be inverted, we cannot convert between input and output units. Free the node which was created to be the root of the inverted tree (and which has consequently not been incorporated into the inverted tree), free any testtree and break out of the loop. */ } else { src = FreeTree( src, status ); testtree = FreeTree( testtree, status ); break; } } /* Free the other trees. */ intemp = FreeTree( intemp, status ); outtemp = FreeTree( outtemp, status ); } /* If all the basic units used by either of the supplied system of units produced the same test tree, leave the "swap in and out units" loop. */ if( testtree ) break; } /* If the input and output units have been swapped, swap them back to their original order, and invert the test tree (if there is one). */ if( ipass > 0 ) { tmp = in_tree; in_tree = out_tree; out_tree = tmp; if( testtree ) { src = NewNode( NULL, OP_LDVAR, status ); if( astOK ) src->name = astStore( NULL, "input_units", 12 ); newtest = InvertTree( testtree, src, status ); FreeTree( testtree, status ); testtree = newtest; if( !newtest ) src = FreeTree( src, status ); } } /* If all the basic units used by either of the supplied system of units produced the same test tree, create a Mapping which is equivalent to the test tree and return it. */ if( testtree ) { result = MakeMapping( testtree, status ); /* We now go on to produce the output axis label from the supplied input axis label. Get a tree of UnitNodes which describes the supplied label associated with the input axis. The tree will have single OP_LDVAR node corresponding to the basic label (i.e. the label without any single argument functions or exponentiation operators applied). */ if( in_lab && astOK ) { /* Get a pointer to the first non-blank character, and store the number of characters to examine (this excludes any trailing white space). */ exp = in_lab; while( isspace( *exp ) ) exp++; c = exp + strlen( exp ) - 1; while( c >= exp && isspace( *c ) ) c--; nc = c - exp + 1; /* Create the tree. */ labtree = MakeLabelTree( exp, nc, status ); if( astOK ) { /* Concatenate this tree (which goes from "basic label" to "input label") with the test tree found above (which goes from "input units" to "output units"), to get a tree which goes from basic label to output label. */ totlabtree = ConcatTree( labtree, testtree, status ); /* Simplify this tree. */ SimplifyTree( &totlabtree, 1, status ); /* Create the output label from this tree. */ *out_lab = (char *) MakeExp( totlabtree, 0, 1, status ); /* Free the trees. */ totlabtree = FreeTree( totlabtree, status ); labtree = FreeTree( labtree, status ); /* Report a context error if the input label could not be parsed. */ } else { astError( AST__BADUN, "astUnitMapper: Error parsing axis " "label '%s'.", status, in_lab ); } } /* Free the units tree. */ testtree = FreeTree( testtree, status ); } } /* Free resources. */ in_tree = FreeTree( in_tree, status ); out_tree = FreeTree( out_tree, status ); units = astFree( units ); /* If an error has occurred, annul the returned Mapping. */ if( !astOK ) { result = astAnnul( result ); if( in_lab ) *out_lab = astFree( *out_lab ); } /* Return the result. */ return result; } const char *astUnitNormaliser_( const char *in, int *status ){ /* *+ * Name: * astUnitNormalizer * Purpose: * Normalise a unit string into FITS-WCS format. * Type: * Protected function. * Synopsis: * #include "unit.h" * const char *astUnitNormaliser( const char *in ) * Class Membership: * Unit member function. * Description: * This function returns a standard FITS-WCS form of the supplied unit * string. * Parameters: * in * A string representation of the units, for instance "km/h". * Returned Value: * A pointer to a dynamically allocated string holding the normalized * unit string. It should be freed using astFree when no longer needed. * Notes: * - An error will be reported if the units string cannot be parsed. * - NULL is returned if this function is invoked with the * global error status set or if it should fail for any reason. *- */ /* Local Variables: */ UnitNode *in_tree; double dval; const char *result; /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Parse the input units string, producing a tree of UnitNodes which represents the input units. A pointer to the UnitNode at the head of the tree is returned if succesfull. Report a context message if this fails. */ in_tree = CreateTree( in, 0, 1, status ); if( in_tree ) { /* Simplify the units expression, only doing genuine simplifications. */ SimplifyTree( &in_tree, 1, status ); /* Invert literal constant unit multipliers. This is because a constant of say 1000 for a unit of "m" means "multiply the value in metres by 1000", but a unit string of "1000 m" means "value in units of 1000 m" (i.e. *divide* the value in metres by 1000). */ InvertConstants( &in_tree, status ); /* Convert the tree into string form. */ result = MakeExp( in_tree, 2, 1, status ); /* If the result is a constant value, return a blank string. */ if( 1 == astSscanf( result, "%lg", &dval ) ) { *((char *) result) = 0; } /* Free the tree. */ in_tree = FreeTree( in_tree, status ); } else { astError( AST__BADUN, "astUnitNormaliser: Error parsing input " "units string '%s'.", status, in ); } /* Return the result */ return result; } static int Ustrcmp( const char *a, const char *b, int *status ){ /* * Name: * Ustrcmp * Purpose: * A case blind version of strcmp. * Type: * Private function. * Synopsis: * #include "unit.h" * int Ustrcmp( const char *a, const char *b, int *status ) * Class Membership: * Unit member function. * Description: * Returns 0 if there are no differences between the two strings, and 1 * otherwise. Comparisons are case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference between * the two strings, whereas "strcmp" does. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Loop round each character. */ while( 1 ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } static int Ustrncmp( const char *a, const char *b, size_t n, int *status ){ /* * Name: * Ustrncmp * Purpose: * A case blind version of strncmp. * Type: * Private function. * Synopsis: * #include "unit.h" * int Ustrncmp( const char *a, const char *b, size_t n, int *status ) * Class Membership: * Unit member function. * Description: * Returns 0 if there are no differences between the first "n" * characters of the two strings, and 1 otherwise. Comparisons are * case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * n * The maximum number of characters to compare. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference between * the two strings, whereas "strncmp" does. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int i; /* Character index */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Check pointer have been supplied. */ if( !a || !b ) return ret; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Compare up to "n" characters. */ for( i = 0; i < (int) n; i++ ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } /* The rest of this file contains functions which are of use for debugging this module. They are usually commented out. static const char *DisplayTree( UnitNode *node, int ind ) { int i; char buf[200]; const char *result; char *a; const char *arg[ 2 ]; int rl; int slen; const opsym[ 100 ]; result = ""; for( i = 0; i < ind; i++ ) buf[ i ] = ' '; buf[ ind ] = 0; if( !node ) { printf( "%s \n", buf ); } else { printf( "%s Code: '%s' (%d)\n", buf, OpName( node->opcode ), node->opcode ); printf( "%s Narg: %d\n", buf, node->narg ); printf( "%s Constant: %g\n", buf, node->con ); printf( "%s Name: %s\n", buf, node->name?node->name:"" ); printf( "%s Unit: %s\n", buf, node->unit?node->unit->sym:"" ); printf( "%s Mult: %s\n", buf, node->mult?node->mult->sym:"" ); OpSym( node, opsym ); slen = strlen( opsym ); rl = slen; if( node->narg == 0 ) { result = astMalloc( rl + 1 ); if( astOK ) strcpy( (char *) result, opsym ); } else if( node->narg == 1 ) { rl += 2; printf( "%s Arg 0:\n", buf ); arg[ 0 ] = DisplayTree( (node->arg)[ 0 ], ind + 2 ); rl += strlen( arg[ 0 ] ); result = astMalloc( rl + 1 ); if( astOK ) { a = (char *) result; strcpy( a, opsym ); a += slen; *(a++) = '('; strcpy( a, arg[0] ); a += strlen( arg[ 0 ] ); *(a++) = ')'; } } else { rl += 4; for( i = 0; i < node->narg; i++ ) { printf( "%s Arg %d:\n", buf, i ); arg[ i ] = DisplayTree( (node->arg)[ i ], ind + 2 ); rl += strlen( arg[ i ] ); } result = astMalloc( rl + 1 ); if( astOK ) { a = (char *) result; *(a++) = '('; strcpy( a, arg[0] ); a += strlen( arg[ 0 ] ); *(a++) = ')'; strcpy( a, opsym ); a += slen; *(a++) = '('; strcpy( a, arg[1] ); a += strlen( arg[ 1 ] ); *(a++) = ')'; } } } if( !astOK ) { astFree( (void *) result ); result = ""; } return result; } static const char *OpName( Oper op ) { const char *name; if( op == OP_LDCON ) { name = "LDCON"; } else if( op == OP_LDVAR ) { name = "LDVAR"; } else if( op == OP_LOG ) { name = "LOG"; } else if( op == OP_LN ) { name = "LN"; } else if( op == OP_EXP ) { name = "EXP"; } else if( op == OP_SQRT ) { name = "SQRT"; } else if( op == OP_POW ) { name = "POW"; } else if( op == OP_DIV ) { name = "DIV"; } else if( op == OP_MULT ) { name = "MULT"; } else if( op == OP_LDPI ) { name = "LDPI"; } else if( op == OP_LDE ) { name = "LDE"; } else if( op == OP_NULL ) { name = "NULL"; } else { name = ""; } return name; } static void OpSym( UnitNode *node, char *buff ) { const char *sym = NULL; if( node->con != AST__BAD ) { sprintf( buff, "%g", node->con ); } else if( node->opcode == OP_LDVAR ) { sym = node->name; } else if( node->opcode == OP_LOG ) { sym = "log"; } else if( node->opcode == OP_LN ) { sym = "ln"; } else if( node->opcode == OP_EXP ) { sym = "exp"; } else if( node->opcode == OP_SQRT ) { sym = "sqrt"; } else if( node->opcode == OP_POW ) { sym = "**"; } else if( node->opcode == OP_DIV ) { sym = "/"; } else if( node->opcode == OP_MULT ) { sym = "*"; } else if( node->opcode == OP_NULL ) { sym = "NULL"; } else { sym = ""; } if( sym ) strcpy( buff, sym ); } static const char *TreeExp( UnitNode *node ) { char buff[ 100 ]; char buff2[ 100 ]; if( node->narg == 0 ) { OpSym( node, buff ); } else if( node->narg == 1 ) { OpSym( node, buff2 ); sprintf( buff, "%s(%s)", buff2, TreeExp( node->arg[ 0 ] ) ); } else if( node->narg == 2 ) { OpSym( node, buff2 ); sprintf( buff, "(%s)%s(%s)", TreeExp( node->arg[ 0 ] ), buff2, TreeExp( node->arg[ 1 ] ) ); } return astStore( NULL, buff, strlen( buff ) + 1 ); } */ ./ast-7.3.3/fstcresourceprofile.c0000644000175000017500000000731612262533650015405 0ustar olesoles/* *+ * Name: * fstcresourceprofile.c * Purpose: * Define a FORTRAN 77 interface to the AST StcResourceProfile class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the StcResourceProfile class. * Routines Defined: * AST_ISASTCRESOURCEPROFILE * AST_STCRESOURCEPROFILE * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-NOV-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "object.h" /* Basic AST Object management functions */ #include "stcresourceprofile.h" /* C interface to the StcResourceProfile class */ F77_LOGICAL_FUNCTION(ast_isastcresourceprofile)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASTCRESOURCEPROFILE", NULL, 0 ); astWatchSTATUS( RESULT = astIsAStcResourceProfile( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_stcresourceprofile)( INTEGER(REG), INTEGER(NCOORDS), INTEGER_ARRAY(COORDS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(REG) GENPTR_INTEGER(NCOORDS) GENPTR_CHARACTER(OPTIONS) GENPTR_INTEGER_ARRAY(COORDS) AstKeyMap **coords; F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_STCRESOURCEPROFILE", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } /* Convert supplied integers to pointers. */ coords = astMalloc( sizeof( AstKeyMap * )*(size_t)( *NCOORDS )); if( astOK ) { for( i = 0; i < *NCOORDS; i++ ) { coords[ i ] = (AstKeyMap *) astMakePointer( astI2P( COORDS[ i ] )); } } RESULT = astP2I( astStcResourceProfile( astI2P( *REG ), *NCOORDS, coords, "%s", options ) ); astFree( coords ); astFree( options ); ) return RESULT; } ./ast-7.3.3/finterval.c0000644000175000017500000000644612262533650013312 0ustar olesoles/* *+ * Name: * finterval.c * Purpose: * Define a FORTRAN 77 interface to the AST Interval class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Interval class. * Routines Defined: * AST_ISAINTERVAL * AST_INTERVAL * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 31-AUG-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "interval.h" /* C interface to the Interval class */ F77_LOGICAL_FUNCTION(ast_isainterval)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAINTERVAL", NULL, 0 ); astWatchSTATUS( RESULT = astIsAInterval( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_interval)( INTEGER(FRAME), DOUBLE_ARRAY(LBND), DOUBLE_ARRAY(UBND), INTEGER(UNC), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_DOUBLE_ARRAY(LBND) GENPTR_DOUBLE_ARRAY(UBND) GENPTR_INTEGER(UNC) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_INTERVAL", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astInterval( astI2P( *FRAME ), LBND, UBND, astI2P( *UNC ), "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/switchmap.c0000644000175000017500000031120412262533650013306 0ustar olesoles/* *class++ * Name: * SwitchMap * Purpose: * A Mapping that encapsulates a set of alternate Mappings. * Constructor Function: c astSwitchMap f AST_SWITCHMAP * Description: * A SwitchMap is a Mapping which represents a set of alternate * Mappings, each of which is used to transform positions within a * particular region of the input or output coordinate system of the * SwitchMap. * * A SwitchMap can encapsulate any number of Mappings, but they must * all have the same number of inputs (Nin attribute value) and the * same number of outputs (Nout attribute value). The SwitchMap itself * inherits these same values for its Nin and Nout attributes. Each of * these Mappings represents a "route" through the switch, and are * referred to as "route" Mappings below. Each route Mapping transforms * positions between the input and output coordinate space of the entire * SwitchMap, but only one Mapping will be used to transform any given * position. The selection of the appropriate route Mapping to use with * any given input position is made by another Mapping, called the * "selector" Mapping. Each SwitchMap encapsulates two selector * Mappings in addition to its route Mappings; one for use with the * SwitchMap's forward transformation (called the "forward selector * Mapping"), and one for use with the SwitchMap's inverse transformation * (called the "inverse selector Mapping"). The forward selector Mapping * must have the same number of inputs as the route Mappings, but * should have only one output. Likewise, the inverse selector Mapping * must have the same number of outputs as the route Mappings, but * should have only one input. * * When the SwitchMap is used to transform a position in the forward * direction (from input to output), each supplied input position is * first transformed by the forward transformation of the forward selector * Mapping. This produces a single output value for each input position * referred to as the selector value. The nearest integer to the selector * value is found, and is used to index the array of route Mappings (the * first supplied route Mapping has index 1, the second route Mapping has * index 2, etc). If the nearest integer to the selector value is less * than 1 or greater than the number of route Mappings, then the SwitchMap * output position is set to a value of AST__BAD on every axis. Otherwise, * the forward transformation of the selected route Mapping is used to * transform the supplied input position to produce the SwitchMap output * position. * * When the SwitchMap is used to transform a position in the inverse * direction (from "output" to "input"), each supplied "output" position * is first transformed by the inverse transformation of the inverse * selector Mapping. This produces a selector value for each "output" * position. Again, the nearest integer to the selector value is found, * and is used to index the array of route Mappings. If this selector * index value is within the bounds of the array of route Mappings, then * the inverse transformation of the selected route Mapping is used to * transform the supplied "output" position to produce the SwitchMap * "input" position. If the selector index value is outside the bounds * of the array of route Mappings, then the SwitchMap "input" position is * set to a value of AST__BAD on every axis. * * In practice, appropriate selector Mappings should be chosen to * associate a different route Mapping with each region of coordinate * space. Note that the SelectorMap class of Mapping is particularly * appropriate for this purpose. * * If a compound Mapping contains a SwitchMap in series with its own * inverse, the combination of the two adjacent SwitchMaps will be * replaced by a UnitMap when the compound Mapping is simplified using c astSimplify. f AST_SIMPLIFY. * Inheritance: * The SwitchMap class inherits from the Mapping class. * Attributes: * The SwitchMap class does not define any new attributes beyond those * which are applicable to all Mappings. * Functions: c The SwitchMap class does not define any new functions beyond those f The SwitchMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 13-MAR-2006 (DSB): * Original version. * 17-MAR-2006 (DSB): * Guard against AST__BAD selector values. * 9-MAY-2006 (DSB): * Check selector Mapping pointers are not NULL before calling * astEqual in Equal. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SwitchMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate Mappings (parent class) */ #include "unitmap.h" /* Unit Mappings */ #include "channel.h" /* I/O channels */ #include "switchmap.h" /* Interface definition for this class */ #include "frame.h" /* Frames */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SwitchMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SwitchMap,Class_Init) #define class_vtab astGLOBAL(SwitchMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSwitchMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSwitchMap *astSwitchMapId_( void *, void *, int, void **, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *RemoveRegions( AstMapping *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static double Rate( AstMapping *, double *, int, int, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetObjSize( AstObject *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static AstMapping *GetSelector( AstSwitchMap *, int, int *, int * ); static AstMapping *GetRoute( AstSwitchMap *, double, int *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two SwitchMaps are equivalent. * Type: * Private function. * Synopsis: * #include "switchmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * SwitchMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two SwitchMaps are equivalent. * Parameters: * this * Pointer to the first Object (a SwitchMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the SwitchMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstMapping *fsmap1; AstMapping *fsmap2; AstMapping *ismap1; AstMapping *ismap2; AstMapping *rmap1; AstMapping *rmap2; AstSwitchMap *that; AstSwitchMap *this; int fsinv1; int fsinv2; int isinv1; int i; int isinv2; int nroute; int result; int rinv1; int rinv2; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two SwitchMap structures. */ this = (AstSwitchMap *) this_object; that = (AstSwitchMap *) that_object; /* Check the second object is a SwitchMap. We know the first is a SwitchMap since we have arrived at this implementation of the virtual function. */ if( astIsASwitchMap( that ) ) { /* Check they have the same number of route mappings. */ nroute = this->nroute; if( that->nroute == nroute ) { /* Get the forward selector Mappings from the two SwitchMaps. */ fsmap1 = GetSelector( this, 1, &fsinv1, status ); fsmap2 = GetSelector( that, 1, &fsinv2, status ); /* Are they equal? */ if( ( !fsmap1 && !fsmap2 ) || ( fsmap1 && fsmap2 && astEqual( fsmap1, fsmap2 ) ) ) { /* Get the inverse selector Mappings from the two SwitchMaps. */ ismap1 = GetSelector( this, 0, &isinv1, status ); ismap2 = GetSelector( that, 0, &isinv2, status ); /* Are they equal? */ if( ( !ismap1 && !ismap2 ) || ( ismap1 && ismap2 && astEqual( ismap1, ismap2 ) ) ) { /* Loop over the route mappings, breaking as soon as two unequal route Mappings are found. Re-instate the original values for the route Mapping Invert flag after testing the route Mappings for equality. */ result = 1; for( i = 0; result && i < nroute; i++ ) { rmap1 = GetRoute( this, (double) ( i + 1 ), &rinv1, status ); rmap2 = GetRoute( that, (double) ( i + 1 ), &rinv2, status ); if( !astEqual( rmap1, rmap2 ) ) result = 0; astSetInvert( rmap2, rinv2 ); astSetInvert( rmap1, rinv1 ); } } /* Reinstate the invert flags for the inverse selector Mappings. Ensure this is done in the opposite order to which the selector Mappings were obtained (in case they are in fact the same Mapping). */ if( ismap2 ) astSetInvert( ismap2, isinv2 ); if( ismap1 ) astSetInvert( ismap1, isinv1 ); } /* Reinstate the invert flags for the forward selector Mappings. Ensure this is done in the oppsote order to which the selector Mappings were obtained (in case they are in fact the same Mapping). */ if( fsmap2 ) astSetInvert( fsmap2, fsinv2 ); if( fsmap1 ) astSetInvert( fsmap1, fsinv1 ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "switchmap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * SwitchMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied SwitchMap, * in bytes. * Parameters: * this * Pointer to the SwitchMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSwitchMap *this; int i; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the SwitchMap structure. */ this = (AstSwitchMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by this class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->fsmap ); result += astGetObjSize( this->ismap ); for( i = 0; i < this->nroute; i++ ) { result += astGetObjSize( this->routemap[ i ] ); } result += astGetObjSize( this->routeinv ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static AstMapping *GetRoute( AstSwitchMap *this, double sel, int *inv, int *status ){ /* * Name: * GetRoute * Purpose: * Return a pointer to a route Mapping, handling all Invert flags. * Type: * Private function. * Synopsis: * #include "switchmap.h" * AstMapping *GetRoute( AstSwitchMap *this, double sel, int *inv, int *status ) * Class Membership: * SwitchMap method. * Description: * This function returns a pointer to a route Mapping (specified by a * floating point selector value) for the given SwitchMap, taking account * of the state of the Invert flag of both the route Mapping and the * SwitchMap. * Parameters: * this * Pointer to the SwitchMap. * sel * The selector value. The nearest integer value (minus 1) is used * to index the array of route Mappings stored in the SwitchMap. A * NULL pointer is returned if the selector value is out of range. * inv * Pointer to an int in which to return the original value of the * Invert flag of the returned Mapping. The astSetInvert method * should be used to re-instate this value once all use of the Mapping * has been completed. * status * Pointer to the inherited status variable. * Returns: * A pointer to the route Mapping to use. Note, the returned pointer * should NOT be annulled when no longer needed. NULL is returned * (without error) if the SwitchMap does not have a route Mapping for the * requested selector value. The forward transformation of the * returned Mapping will implenment the forward transformation of the * required route Mapping (and vice-versa). */ /* Local Variables: */ AstMapping *ret; int rindex; /* Initialise */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* Check selector value is good. */ if( sel != AST__BAD ) { /* Convert the supplied floating point selector value into an integer index into the array of route Mappings held in the supplied SwitchMap. */ rindex = (int)( sel + 0.5 ) - 1; /* Return the null pointer if the index is out of range. */ if( rindex >= 0 && rindex < this->nroute ) { /* Get the required route Mapping. */ ret = ( this->routemap )[ rindex ]; /* Return its original invert flag. */ *inv = astGetInvert( ret ); /* Set the Invert flag back to the value it had when the SwitchMap was created. */ astSetInvert( ret, this->routeinv[ rindex ] ); /* If the SwitchMap has since been inverted, also invert the returned route Mapping, so that the forward transformation of the returned Mapping implements the forward transformation of the supplied SwitchMap (and vice-versa). */ if( astGetInvert( this ) ) astInvert( ret ); } } /* Return the pointer. */ return ret; } static AstMapping *GetSelector( AstSwitchMap *this, int fwd, int *inv, int *status ){ /* * Name: * GetSelector * Purpose: * Return a pointer to a selector Mapping, handling all Invert flags. * Type: * Private function. * Synopsis: * #include "switchmap.h" * AstMapping *GetSelector( AstSwitchMap *this, int fwd, int *inv, int *status ) * Class Membership: * SwitchMap method. * Description: * This function returns a pointer to either the forward or inverse * selector Mapping for the given SwitchMap, taking account of the * state of the Invert flag of bothe the selector Mapping and the * SwitchMap. * Parameters: * this * Pointer to the SwitchMap. * fwd * If non-zero, return the forward selector Mapping. Otherwise, * return the inverse selector Mapping. * inv * Pointer to an int in which to return the original value of the * Invert flag of the returned Mapping. The astSetInvert method * should be used to re-instate this value once all use of the Mapping * has been completed. * status * Pointer to the inherited status variable. * Returns: * A pointer to the selector Mapping to use. Note, the returned pointer * should NOT be annulled when no longer needed. NULL is returned * (without error) if the SwitchMap does not have a Mapping for the * requested selector. */ /* Local Variables: */ AstMapping *ret; int swinv; /* Initialise */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* See if the SwitchMap has been inverted. */ swinv = astGetInvert( this ); /* If the SwitchMap has been inverted, the forward and inverse selector Mappings should be reversed. */ if( ( !swinv && !fwd ) || ( swinv && fwd ) ){ ret = this->ismap; if( ret ) { *inv = astGetInvert( ret ); astSetInvert( ret, this->isinv ); } } else { ret = this->fsmap; if( ret ) { *inv = astGetInvert( ret ); astSetInvert( ret, this->fsinv ); } } if( ret && swinv ) astInvert( ret ); /* Return the pointer. */ return ret; } void astInitSwitchMapVtab_( AstSwitchMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSwitchMapVtab * Purpose: * Initialise a virtual function table for a SwitchMap. * Type: * Protected function. * Synopsis: * #include "switchmap.h" * void astInitSwitchMapVtab( AstSwitchMapVtab *vtab, const char *name ) * Class Membership: * SwitchMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SwitchMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASwitchMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* None. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; mapping->Rate = Rate; mapping->RemoveRegions = RemoveRegions; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "SwitchMap", "Alternate regionalised Mapping" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * SwitchMap member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstSwitchMap *this; /* Pointer to SwitchMap structure */ int i; /* Loop count */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the SwitchMap structure. */ this = (AstSwitchMap *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->fsmap, mode, extra, fail ); if( !result ) result = astManageLock( this->ismap, mode, extra, fail ); for( i = 0; i < this->nroute; i++ ) { if( !result ) result = astManageLock( this->routemap[ i ], mode, extra, fail ); } return result; } #endif static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a SwitchMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * SwitchMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated SwitchMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated SwitchMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated SwitchMap which is to be merged with * its neighbours. This should be a cloned copy of the SwitchMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * SwitchMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated SwitchMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstSwitchMap *map; AstMapping *new; int i; int nroute; int result; int fsinv_old; int isinv_old; int *rinv_old; AstMapping *sfsmap; AstMapping *sismap; int simp; AstMapping **srmap; AstSwitchMap *swneb; int ilo; int equal; /* Initialise.*/ result = -1; /* Check the inherited status. */ if ( !astOK ) return result; /* Get a pointer to this SwitchMap, and note the number of route Mappings. */ map = (AstSwitchMap *) this; nroute = map->nroute; /* Temporarily put the Invert flag of all encapsulated Mappings (both route and selector) back to the values they had when the SwitchMap was created, noting their current values so that they can be re-instated later. If the SwitchMap itself has been inverted, swap all the original invert flags. */ if( map->fsmap ) { fsinv_old = astGetInvert( map->fsmap ); astSetInvert( map->fsmap, map->fsinv ); } else { fsinv_old = 0; } if( map->ismap ) { isinv_old = astGetInvert( map->ismap ); astSetInvert( map->ismap, map->isinv ); } else { isinv_old = 0; } rinv_old = astMalloc( sizeof( int )*nroute ); if( astOK ) { for( i = 0; i < nroute; i++ ) { rinv_old[ i ] = astGetInvert( map->routemap[ i ] ); astSetInvert( map->routemap[ i ], map->routeinv[ i ] ); } } /* If possible, merge the SwitchMap with a neighbouring SwitchMap. */ /* =============================================================== */ /* Only do this if we are combining the Mappings in series. */ if( series ) { /* Is the higher neighbour a SwitchMap? If so get a pointer to it, and note the index of the lower of the two adjacent SwitchMaps. */ if( where < ( *nmap - 1 ) && astIsASwitchMap( ( *map_list )[ where + 1 ] ) ){ swneb = (AstSwitchMap *) ( *map_list )[ where + 1 ]; ilo = where; /* If not, is the lower neighbour a SwitchMap? If so get a pointer to it, and note the index of the lower of the two adjacent SwitchMaps. */ } else if( where > 0 && astIsASwitchMap( ( *map_list )[ where - 1 ] ) ){ swneb = (AstSwitchMap *) ( *map_list )[ where - 1 ]; ilo = where - 1; } else { swneb = NULL; } /* If a neighbouring SwitchMap was found, we can replace the pair by a UnitMap if the two SwitchMaps are equal but have opposite values for their Invert flags. Temporarily invert the neighbour, then compare the two SwitchMaps for equality, then re-invert the neighbour. */ if( swneb ) { astInvert( swneb ); equal = astEqual( map, swneb ); astInvert( swneb ); /* If the two SwitchMaps are equal but opposite, annul the first of the two Mappings, and replace it with a UnitMap. Also set the invert flag. */ if( equal ) { new = (AstMapping *) astUnitMap( astGetNin( ( *map_list )[ ilo ] ), "", status ); (void) astAnnul( ( *map_list )[ ilo ] ); ( *map_list )[ ilo ] = new; ( *invert_list )[ ilo ] = 0; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ ilo + 1 ] ); for ( i = ilo + 2; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = where; } } } /* Attempt to simplify the SwitchMap on its own. */ /* ============================================= */ /* Only do this if no change was made above. */ if( result == -1 ) { /* If the SwitchMap is inverted, create an equal SwitchMap which is not inverted. To do this, invert and swap the selector Mappings, and invert all the route Mappings. We use astSetInvert rather than astInvert because two or more more stored pointers may point to the same Mapping in which case that Mapping would be inverted more than once with unpredictable results. */ if( ( *invert_list )[ where ] ) { if( map->fsmap ) astSetInvert( map->fsmap, !(map->fsinv) ); if( map->ismap ) astSetInvert( map->ismap, !(map->isinv) ); for( i = 0; i < nroute; i++ ) { astSetInvert( map->routemap[ i ], !(map->routeinv[ i ]) ); } new = (AstMapping *) astSwitchMap( map->ismap, map->fsmap, nroute, (void **) map->routemap, "", status ); (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) new; ( *invert_list )[ where ] = 0; result = where; /* Otherwise, try to simplify each of the encapsulated Mappings, noting if any simplification takes place. */ } else { sfsmap = ( map->fsmap ) ? astSimplify( map->fsmap ) : NULL; sismap = ( map->ismap ) ? astSimplify( map->ismap ) : NULL; simp = ( sfsmap != map->fsmap ) || ( sismap != map->ismap ); srmap = astMalloc( sizeof( AstMapping * )*nroute ); if( astOK ) { for( i = 0; i < nroute; i++ ) { srmap[ i ] = astSimplify( map->routemap[ i ] ); simp = simp || ( srmap[ i ] != map->routemap[ i ] ); } } /* If any simplification took place, construct a new SwitchMap from these simplified Mappings. */ if( simp ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) astSwitchMap( sfsmap, sismap, nroute, (void **) srmap, "", status ); result = where; } /* Release resources. */ if( sfsmap ) sfsmap = astAnnul( sfsmap ); if( sismap ) sismap = astAnnul( sismap ); if( srmap ) { for( i = 0; i < nroute; i++ ) srmap[ i ] = astAnnul( srmap[ i ] ); srmap = astFree( srmap ); } } } /* Re-instate the original Invert values for the encapsulated Mappings. */ if( map->fsmap ) astSetInvert( map->fsmap, fsinv_old ); if( map->ismap ) astSetInvert( map->ismap, isinv_old ); if( rinv_old ) { for( i = 0; i < nroute; i++ ) { astSetInvert( map->routemap[ i ], rinv_old[ i ] ); } rinv_old = astFree( rinv_old ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){ /* * Name: * Rate * Purpose: * Calculate the rate of change of a Mapping output. * Type: * Private function. * Synopsis: * #include "switchmap.h" * result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ) * Class Membership: * SwitchMap member function (overrides the astRate method inherited * from the Mapping class ). * Description: * This function returns the rate of change of a specified output of * the supplied Mapping with respect to a specified input, at a * specified input position. Also evaluates the second derivative. * Parameters: * this * Pointer to the Mapping to be applied. * at * The address of an array holding the axis values at the position * at which the rate of change is to be evaluated. The number of * elements in this array should equal the number of inputs to the * Mapping. * ax1 * The index of the Mapping output for which the rate of change is to * be found (output numbering starts at 0 for the first output). * ax2 * The index of the Mapping input which is to be varied in order to * find the rate of change (input numbering starts at 0 for the first * input). * status * Pointer to the inherited status variable. * Returned Value: * The rate of change of Mapping output "ax1" with respect to input * "ax2", evaluated at "at", or AST__BAD if the value cannot be * calculated. */ /* Local Variables: */ AstSwitchMap *map; AstMapping *smap; AstMapping *rmap; double result; double sel; int fsinv; int rinv; int nin; /* Initialise. */ result = AST__BAD; /* Check inherited status */ if( !astOK ) return result; /* Get a pointer to the SwitchMap structure. */ map = (AstSwitchMap *) this; /* Get a pointer to the effective foward selector Mapping, and its current invert flag (this takes account of whether the SwtichMap has been inverted or not). This call resets the selector's invert flag temporarily back to the value it had when the SwitchMap was created. */ smap = GetSelector( map, 1, &fsinv, status ); /* If the SwitchMap has no forward selector Mapping, return AST__BAD. */ if( smap ) { /* Get the number of inputs */ nin = astGetNin( smap ); /* Transform the supplied position using the selector Mapping. The output value is the selector value that indicates which route Mapping to use. */ astTranN( smap, 1, nin, 1, at, 1, 1, 1, &sel ); /* Get the index of the route Mapping to use, and check it is valid (if not, return AST__BAD if not). This takes account of whether the SwitchMap has been inverted, and also temporarily re-instates the original value of the route Mapping's Invert flag . */ rmap = GetRoute( map, sel, &rinv, status ); if( rmap ) { /* Use the astRate method of the route Mapping. */ result = astRate( rmap, at, ax1, ax2 ); /* Reset the Invert flag for the route Mapping. */ astSetInvert( rmap, rinv ); } /* Reset the Invert flag for the selector Mapping. */ astSetInvert( smap, fsinv ); } /* Return the result. */ return result; } static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) { /* * Name: * RemoveRegions * Purpose: * Remove any Regions from a Mapping. * Type: * Private function. * Synopsis: * #include "switchmap.h" * AstMapping *RemoveRegions( AstMapping *this, int *status ) * Class Membership: * SwitchMap method (over-rides the astRemoveRegions method inherited * from the Mapping class). * Description: * This function searches the supplied Mapping (which may be a * compound Mapping such as a SwitchMap) for any component Mappings * that are instances of the AST Region class. It then creates a new * Mapping from which all Regions have been removed. If a Region * cannot simply be removed (for instance, if it is a component of a * parallel SwitchMap), then it is replaced with an equivalent UnitMap * in the returned Mapping. * * The implementation provided by the SwitchMap class invokes the * astRemoveRegions method on all the component Mappings, and joins * the results together into a new SwitchMap. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the modified mapping. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstMapping **temp; /* Array of new route Mappings */ AstMapping *newfsmap; /* New forward selector Mapping */ AstMapping *newismap; /* New inverse selector Mapping */ AstMapping *result; /* Result pointer to return */ AstSwitchMap *new; /* Pointer to new SwitchMap */ AstSwitchMap *this; /* Pointer to SwitchMap structure */ int changed; /* Has any mapping been changed? */ int i; /* Loop count */ int nax; /* Number of Frame axes */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the SwitchMap. */ this = (AstSwitchMap *) this_mapping; /* Allocate an array to hold the modified Mapping pointers. */ temp = astMalloc( sizeof( AstMapping *)*( this->nroute ) ); if( astOK ) { /* Invoke the astRemoveRegions method on all the component Mappings. */ changed = 0; for( i = 0; i < this->nroute; i++ ) { temp[ i ] = astRemoveRegions( this->routemap[ i ] ); /* Note if any Mapping was changed. */ if( temp[ i ] != this->routemap[ i ] ) { changed = 1; /* The implementation of the astRemoveRegions method provided by the Region class returns a Frame rather than a UnitMap. But we need Mappings here, not Frames. So if the new Mapping is a Frame, replace it with an equivalent UnitMap. */ if( astIsAFrame( temp[ i ] ) ) { nax = astGetNin( temp[ i ] ); (void) astAnnul( temp[ i ] ); temp[ i ] = (AstMapping *) astUnitMap( nax, " ", status ); } } } /* And on the other ancillary Mappings */ if( this->fsmap ) { newfsmap = astRemoveRegions( this->fsmap ); if( newfsmap != this->fsmap ) { changed = 1; if( astIsAFrame( newfsmap ) ) { nax = astGetNin( newfsmap ); (void) astAnnul( newfsmap ); newfsmap = (AstMapping *) astUnitMap( nax, " ", status ); } } } else { newfsmap = NULL; } if( this->ismap ) { newismap = astRemoveRegions( this->ismap ); if( newismap != this->ismap ) { changed = 1; if( astIsAFrame( newismap ) ) { nax = astGetNin( newismap ); (void) astAnnul( newismap ); newismap = (AstMapping *) astUnitMap( nax, " ", status ); } } } else { newismap = NULL; } /* If no component was modified, just return a clone of the supplied pointer. */ if( ! changed ) { result = astClone( this ); /* Otherwise, we need to create a new Mapping to return. We take a deep copy of the supplied SwitchMap and then modify the Mappings so that we retain any extra information in the supplied SwitchMap. */ } else { new = astCopy( this ); for( i = 0; i < this->nroute; i++ ) { (void) astAnnul( new->routemap[ i ] ); new->routemap[ i ] = astClone( temp[ i ] ); } if( newfsmap ) { (void) astAnnul( new->fsmap ); new->fsmap = astClone( newfsmap ); } if( newismap ) { (void) astAnnul( new->ismap ); new->ismap = astClone( newismap ); } result = (AstMapping *) new; } /* Free resources. */ for( i = 0; i < this->nroute; i++ ) { temp[ i ] = astAnnul( temp[ i ] ); } if( newfsmap ) newfsmap = astAnnul( newfsmap ); if( newismap ) newismap = astAnnul( newismap ); } temp = astFree( temp ); /* Annul the returned Mapping if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } int astSwitchList_( AstSwitchMap *this, int invert, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* *+ * Name: * astSwitchList * Purpose: * Extract the selector and route Mappings from a SwitchMap. * Type: * Protected function. * Synopsis: * #include "switchmap.h" * int astSwitchList( AstSwitchMap *this, int invert, int *nmap, * AstMapping ***map_list, int **invert_list ) * Class Membership: * SwitchMap member function. * Description: * This function extracts the route and selector Mappings form a * SwitchMap. * Parameters: * this * Pointer to the SwitchMap to be decomposed (it is not actually * modified by this function). * invert * The value to which the SwitchMap's Invert attribute is to be * (notionally) set before performing the decomposition. Normally, * the value supplied here will be the actual Invert value obtained * from the SwitchMap (e.g. using astGetInvert). Sometimes, however, * when a SwitchMap is encapsulated within another structure, that * structure may retain an Invert value (in order to prevent external * interference) which should be used instead. * * Note that the actual Invert value of the SwitchMap supplied is * not used (or modified) by this function. * nmap * The address of an int in which to return a count of the number of * individual Mappings in the decomposition. The supplied value is * ignored. * map_list * Address of a pointer to an array of Mapping pointers. The value * supplied on entry is ignored. On exit, it points at a dynamically * allocated array containing Mapping pointers ("*nmap" in number) that * result from the decomposition requested. * * The returned Mapping pointers returned will identify the following * sequence of Mappings; forward selector mapping (or NULL if the * SwitchMap has no forward selector Mapping), inverse selector * mapping (or NULL if the SwitchMap has no inverse selector Mapping), * the route Mappings in the order they were supplied when the * SwitchMap was constructed. * * All the Mapping pointers returned by this function should be * annulled by the caller, using astAnnul, when no longer * required. The dynamic array holding these pointers should * also be freed, using astFree. * invert_list * Address of a pointer to an array of int. The value supplied on * entry is ignored. On exit, it points at a dynamically allocated * array containing Invert attribute values ("*nmap" in number) that * result from the decomposition requested. * * The returned Invert values returned identify the values which must * be assigned to the Invert attributes of the corresponding * Mappings (whose pointers are in the "*map_list" array) before * they are applied. Note that these values may differ from the * actual Invert attribute values of these Mappings, which are * not relevant. * * The dynamic array holding these values should be freed by the * caller, using astFree, when no longer required. * Returned Value: * The number of route Mappings stored in the SwitchMap. * Notes: * - It is unspecified to what extent the original SwitchMap and the * individual (decomposed) Mappings are inter-dependent. Consequently, * the individual Mappings cannot be modified without risking * modification of the original SwitchMap. * - If this function is invoked with the global error status set, * or if it should fail for any reason, then the *nmap value, the * list of Mapping pointers and the list of Invert values will all * be returned unchanged. *- */ /* Local Variables: */ AstMapping *map; /* Pointer to Mapping to return */ int inv; /* Original Invert flag for Mapping */ int i; /* Route Mapping index */ int oldinv; /* Original Invert flag for SwitchMap */ int result; /* Returned value */ /* Check the global error status. */ if ( !astOK ) return 0; /* Store the numbe of route Mappings */ result = this->nroute; *nmap = result + 2; /* Allocate the required arrays. */ *map_list = astMalloc( sizeof( AstMapping * )*(size_t) *nmap ); *invert_list = astMalloc( sizeof( int )*(size_t) *nmap ); /* Check the pointers can be used safely. */ if( astOK ) { /* Temporaily set the requested Invert flag for the SwitchMap. */ oldinv = astGetInvert( this ); astSetInvert( this, invert ); /* Get the forward selector Mapping. */ map = GetSelector( this, 1, &inv, status ); /* If the SwitchMap has a forward selector Mapping, return a clone of the Mapping pointer, and the invert flag to be used with it, then re-instate the original invert flag value (which was modified by GetSelector). */ if( map ) { ( *map_list )[ 0 ] = astClone( map ); ( *invert_list )[ 0 ] = astGetInvert( map ); astSetInvert( map, inv ); /* If the SwitchMap does not has a forward selector Mapping, return a NULL pointer. */ } else { ( *map_list )[ 0 ] = NULL; ( *invert_list )[ 0 ] = 0; } /* Likewise, get and return the inverse selector Mapping.*/ map = GetSelector( this, 0, &inv, status ); if( map ) { ( *map_list )[ 1 ] = astClone( map ); ( *invert_list )[ 1 ] = astGetInvert( map ); astSetInvert( map, inv ); } else { ( *map_list )[ 1 ] = NULL; ( *invert_list )[ 1 ] = 0; } /* Loop round all route Mappings. */ for( i = 0; i < result; i++ ){ /* Get the next route Mapping. */ map = GetRoute( this, (double) i + 1.0, &inv, status ); /* If the SwitchMap has a route Mapping for the current selector value, return a clone of the Mapping pointer, and the invert flag to be used with it, then re-instate the original invert flag value (which was modified by GetRoute). */ if( map ) { ( *map_list )[ i + 2 ] = astClone( map ); ( *invert_list )[ i + 2 ] = astGetInvert( map ); astSetInvert( map, inv ); /* If the SwitchMap does not has a route Mapping for the current selector value, return a NULL pointer. */ } else { ( *map_list )[ i + 2 ] = NULL; ( *invert_list )[ i + 2 ] = 0; } } /* Re-instate the original Ivert flag for the SwitchMap. */ astSetInvert( this, oldinv ); } /* If an error has occurred, free the returned arrays. */ if( !astOK ) { *map_list = astFree( *map_list ); *invert_list= astFree( *invert_list ); result= 0; *nmap = 0; } /* Return the result */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a SwitchMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "switchmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * SwitchMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a SwitchMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required Mapping. * This implies applying each of the SwitchMap's component Mappings in turn, * either in series or in parallel. * Parameters: * this * Pointer to the SwitchMap. * in * Pointer to the PointSet associated with the input coordinate values. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the SwitchMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstMapping *rmap; AstMapping *selmap; AstPointSet *ps1; AstPointSet *ps1a; AstPointSet *ps2; AstPointSet *ps2a; AstPointSet *result; AstPointSet *selps; AstSwitchMap *map; double **in_ptr; double **out_ptr; double **ptr1; double **ptr2; double **sel_ptr; double *outv; double *sel; int *popmap; int iroute; int ipoint; int j; int k; int maxpop; int ncin; int ncout; int npoint; int nroute; int rindex; int rinv; int selinv; int totpop; /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the SwitchMap. */ map = (AstSwitchMap *) this; /* Apply the parent Mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We now extend the parent astTransform method by applying the component Mappings of the SwitchMap to generate the output coordinate values. */ /* Get the number of input and output coords. */ if( forward ) { ncin = astGetNin( this ); ncout = astGetNout( this ); } else { ncin = astGetNout( this ); ncout = astGetNin( this ); } /* Get the appropriate selector Mapping. */ selmap = GetSelector( map, forward, &selinv, status ); /* Transform the supplied positions using the above selector Mapping. */ selps = astTransform( selmap, in, forward, NULL ); /* Get a pointer to the array holding the selector value. */ sel_ptr = astGetPoints( selps ); /* Get a pointer to the array holding the input values. */ in_ptr = astGetPoints( in ); /* Get a pointer to the array in which to store the results, and the total number of points being transformed. */ out_ptr = astGetPoints( result ); npoint = astGetNpoint( result ); /* We now count how many positions are to be tranformed by each of the route Mappings. */ nroute = map->nroute; popmap = astMalloc( sizeof( int )*nroute ); if( astOK ) { for( iroute = 0; iroute < nroute; iroute++ ) popmap[ iroute ] = 0; sel = sel_ptr[ 0 ]; for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) { if( *sel != AST__BAD ) { rindex = (int)( *sel + 0.5 ) - 1; if( rindex >= 0 && rindex < nroute ) ( popmap[ rindex ] )++; } } /* Find the number of points transformed by the most popular route Mapping. Also find the total number of points transformed by any route Mapping. */ totpop = 0; maxpop = 0; for( iroute = 0; iroute < nroute; iroute++ ) { if( popmap[ iroute ] > maxpop ) maxpop = popmap[ iroute ]; totpop += popmap[ iroute ]; } if( maxpop == 0 ) maxpop = 1; /* If some of the points are not transformed by any route Mapping. Initialise the whole output array to hold AST__BAD at every point. */ if( totpop < npoint ) { for( j = 0; j < ncout; j++ ) { outv = out_ptr[ j ]; for( ipoint = 0; ipoint < npoint; ipoint++ ) *(outv++) = AST__BAD; } } /* Create a PointSet large enough to hold all the supplied positions which are to be transformed by the most popular route Mapping. */ ps1 = astPointSet( maxpop, ncin, "", status ); ptr1 = astGetPoints( ps1 ); /* Create a PointSet large enough to hold all the output positions created by the most popular route Mapping. */ ps2 = astPointSet( maxpop, ncout, "", status ); ptr2 = astGetPoints( ps2 ); if( astOK ) { /* Loop round each route Mapping which is used by at least 1 point. */ for( iroute = 0; iroute < nroute; iroute++ ) { if( popmap[ iroute ] >0 ) { rmap = GetRoute( map, (double)( iroute + 1 ), &rinv, status ); /* Construct two PointSets of the correct size to hold the input and output points to be processed with the current route Mapping. We re-use the memory allocated for the largest route Mapping's PointSet. */ if( popmap[ iroute ] != maxpop ) { ps1a = astPointSet( popmap[ iroute ], ncin, "", status ); astSetPoints( ps1a, ptr1 ); ps2a = astPointSet( popmap[ iroute ], ncout, "", status ); astSetPoints( ps2a, ptr2 ); } else { ps1a = astClone( ps1 ); ps2a = astClone( ps2 ); } /* Fill the input PointSet with the input positions which are to be transformed using the current route Mapping. */ sel = sel_ptr[ 0 ]; k = 0; for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) { if( *sel != AST__BAD ) { rindex = (int)( *sel + 0.5 ) - 1; if( rindex == iroute ) { for( j = 0; j < ncin; j++ ) { ptr1[ j ][ k ] = in_ptr[ j ][ ipoint ]; } k++; } } } /* Use the route Mapping to transform this PointSet. */ (void) astTransform( rmap, ps1a, forward, ps2a ); /* Copy the axis values from the resulting PointSet back into the results array. */ sel = sel_ptr[ 0 ]; k = 0; for( ipoint = 0; ipoint < npoint; ipoint++,sel++ ) { if( *sel != AST__BAD ) { rindex = (int)( *sel + 0.5 ) - 1; if( rindex == iroute ) { for( j = 0; j < ncout; j++ ) { out_ptr[ j ][ ipoint ] = ptr2[ j ][ k ]; } k++; } } } /* Free resources. */ ps1a = astAnnul( ps1a ); ps2a = astAnnul( ps2a ); /* Re-instate the Invert flag for the route Mapping. */ astSetInvert( rmap, rinv ); } } } /* Free resources. */ ps1 = astAnnul( ps1 ); ps2 = astAnnul( ps2 ); } selps = astAnnul( selps ); popmap = astFree( popmap ); /* Re-instate the Invert flag of the selector Mapping. */ astSetInvert( selmap, selinv ); /* If an error occurred, clean up by deleting the output PointSet (if allocated by this function) and setting a NULL result pointer. */ if ( !astOK ) { if ( !out ) result = astDelete( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for SwitchMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for SwitchMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Mappings within the SwitchMap. */ /* Local Variables: */ AstSwitchMap *in; /* Pointer to input SwitchMap */ AstSwitchMap *out; /* Pointer to output SwitchMap */ int i; /* Loop count */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output SwitchMaps. */ in = (AstSwitchMap *) objin; out = (AstSwitchMap *) objout; /* For safety, start by clearing any references to the input component Mappings,etc, from the output SwitchMap. */ out->fsmap = NULL; out->ismap = NULL; out->routemap = NULL; out->routeinv = NULL; /* Make copies of these Mappings, etc, and store pointers to them in the output SwitchMap structure. */ if( in->fsmap ) out->fsmap = astCopy( in->fsmap ); if( in->ismap ) out->ismap = astCopy( in->ismap ); out->routemap = astMalloc( sizeof( AstMapping * )*( in->nroute ) ); out->routeinv = astMalloc( sizeof( int )*( in->nroute ) ); if( astOK ) { for( i = 0; i < in->nroute; i++ ) { out->routemap[ i ] = astCopy( in->routemap[ i ] ); out->routeinv[ i ] = in->routeinv[ i ]; } } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for SwitchMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for SwitchMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstSwitchMap *this; /* Pointer to SwitchMap */ int i; /* Obtain a pointer to the SwitchMap structure. */ this = (AstSwitchMap *) obj; /* Free dynamically allocated resources. */ if( this->fsmap ) this->fsmap = astAnnul( this->fsmap ); if( this->ismap ) this->ismap = astAnnul( this->ismap ); for( i = 0; i < this->nroute; i++ ) { this->routemap[ i ] = astAnnul( this->routemap[ i ] ); } this->routemap = astFree( this->routemap ); this->routeinv = astFree( this->routeinv ); /* Clear the remaining SwitchMap variables. */ this->nroute = 0; this->fsinv = 0; this->isinv = 0; } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SwitchMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the SwitchMap class to an output Channel. * Parameters: * this * Pointer to the SwitchMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSwitchMap *this; int ival; int set; int i; char buf[ 20 ]; /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SwitchMap structure. */ this = (AstSwitchMap *) this_object; /* Write out values representing the instance variables for the SwitchMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Forward selector Mapping */ /* ------------------------ */ if( this->fsmap ) { astWriteObject( channel, "FSMap", 1, 1, this->fsmap, "Forward selector Mapping" ); /* Forward selector Invert flag. */ /* ----------------------------- */ ival = this->fsinv; set = ( ival != 0 ); astWriteInt( channel, "FSInv", set, 0, ival, ival ? "Fwd selector used in inverse direction" : "Fwd selector used in forward direction" ); } /* Inverse selector Mapping */ /* ------------------------ */ if( this->ismap ) { astWriteObject( channel, "ISMap", 1, 1, this->ismap, "Inverse selector Mapping" ); /* Forward selector Invert flag. */ /* ----------------------------- */ ival = this->isinv; set = ( ival != 0 ); astWriteInt( channel, "ISInv", set, 0, ival, ival ? "Inv selector used in inverse direction" : "Inv selector used in forward direction" ); } /* Loop to dump each route Mapping and its invert flag. */ /* ---------------------------------------------------- */ for( i = 0; i < this->nroute; i++ ) { sprintf( buf, "RMap%d", i + 1 ); astWriteObject( channel, buf, 1, 1, this->routemap[ i ], "Route Mapping" ); ival = this->routeinv[ i ]; set = ( ival != 0 ); sprintf( buf, "RInv%d", i + 1 ); astWriteInt( channel, buf, set, 0, ival, ival ? "Route Mapping used in inverse direction" : "Route Mapping used in forward direction" ); } } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASwitchMap and astCheckSwitchMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SwitchMap,Mapping) astMAKE_CHECK(SwitchMap) AstSwitchMap *astSwitchMap_( void *fsmap_void, void *ismap_void, int nroute, void **routemaps_void, const char *options, int *status, ...) { /* *+ * Name: * astSwitchMap * Purpose: * Create a SwitchMap. * Type: * Protected function. * Synopsis: * #include "switchmap.h" * AstSwitchMap *astSwitchMap( AstMapping *fsmap, AstMapping *ismap, * int nroute, AstMapping **routemaps, * const char *options, ... ) * Class Membership: * SwitchMap constructor. * Description: * This function creates a new SwitchMap and optionally initialises its * attributes. * Parameters: * fsmap * Pointer to the forward selector Mapping * ismap * Pointer to the inverse selector Mapping * nroute * The number of route Mappings. * routemaps * An array of pointers to the route Mappings. * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new SwitchMap. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new SwitchMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic SwitchMap constructor which is * available via the protected interface to the SwitchMap class. A * public interface is provided by the astSwitchMapId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "map1" and "map2" parameters are of type (void *) and are * converted and validated within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSwitchMap *new; /* Pointer to new SwitchMap */ AstMapping *fsmap; /* Pointer to fwd selector Mapping */ AstMapping *ismap; /* Pointer to inv selector Mapping */ AstMapping **routemaps; /* Array of route Mapping pointers */ int i; /* Route Mappings index */ va_list args; /* Variable argument list */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return new; /* Report an error if no route Mappings have been supplied. */ if( nroute <= 0 ) astError( AST__BDPAR, "astSwitchMap(SwitchMap): " "Bad number of route Mappings (%d) specified.", status, nroute ); /* Otherwise create an array to hold the route Mapping pointers. */ routemaps = astMalloc( sizeof( AstMapping * )*nroute ); /* Obtain and validate pointers to the Mapping structures provided. */ if( astOK ) { fsmap = fsmap_void ? astCheckMapping( fsmap_void ) : NULL; ismap = ismap_void ? astCheckMapping( ismap_void ) : NULL; for( i = 0; i < nroute; i++ ) { routemaps[ i ] = astCheckMapping( routemaps_void[ i ] ); } } if ( astOK ) { /* Initialise the SwitchMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSwitchMap( NULL, sizeof( AstSwitchMap ), !class_init, &class_vtab, "SwitchMap", fsmap, ismap, nroute, routemaps ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SwitchMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Free memory used to hold the route Mapping pointers. */ routemaps = astFree( routemaps ); /* Return a pointer to the new SwitchMap. */ return new; } AstSwitchMap *astSwitchMapId_( void *fsmap_void, void *ismap_void, int nroute, void **routemaps_void, const char *options, ... ) { /* *++ * Name: c astSwitchMap f AST_SWITCHMAP * Purpose: * Create a SwitchMap. * Type: * Public function. * Synopsis: c #include "switchmap.h" c AstSwitchMap *astSwitchMap( AstMapping *fsmap, AstMapping *ismap, c int nroute, AstMapping *routemaps[], c const char *options, ... ) f RESULT = AST_SWITCHMAP( FSMAP, ISMAP, NROUTE, ROUTEMAPS, OPTIONS, f STATUS ) * Class Membership: * SwitchMap constructor. * Description: * This function creates a new SwitchMap and optionally initialises * its attributes. * * A SwitchMap is a Mapping which represents a set of alternate * Mappings, each of which is used to transform positions within a * particular region of the input or output coordinate system of the * SwitchMap. * * A SwitchMap can encapsulate any number of Mappings, but they must * all have the same number of inputs (Nin attribute value) and the * same number of outputs (Nout attribute value). The SwitchMap itself * inherits these same values for its Nin and Nout attributes. Each of * these Mappings represents a "route" through the switch, and are * referred to as "route" Mappings below. Each route Mapping transforms * positions between the input and output coordinate space of the entire * SwitchMap, but only one Mapping will be used to transform any given * position. The selection of the appropriate route Mapping to use with * any given input position is made by another Mapping, called the * "selector" Mapping. Each SwitchMap encapsulates two selector * Mappings in addition to its route Mappings; one for use with the * SwitchMap's forward transformation (called the "forward selector * Mapping"), and one for use with the SwitchMap's inverse transformation * (called the "inverse selector Mapping"). The forward selector Mapping * must have the same number of inputs as the route Mappings, but * should have only one output. Likewise, the inverse selector Mapping * must have the same number of outputs as the route Mappings, but * should have only one input. * * When the SwitchMap is used to transform a position in the forward * direction (from input to output), each supplied input position is * first transformed by the forward transformation of the forward selector * Mapping. This produces a single output value for each input position * referred to as the selector value. The nearest integer to the selector * value is found, and is used to index the array of route Mappings (the * first supplied route Mapping has index 1, the second route Mapping has * index 2, etc). If the nearest integer to the selector value is less * than 1 or greater than the number of route Mappings, then the SwitchMap * output position is set to a value of AST__BAD on every axis. Otherwise, * the forward transformation of the selected route Mapping is used to * transform the supplied input position to produce the SwitchMap output * position. * * When the SwitchMap is used to transform a position in the inverse * direction (from "output" to "input"), each supplied "output" position * is first transformed by the inverse transformation of the inverse * selector Mapping. This produces a selector value for each "output" * position. Again, the nearest integer to the selector value is found, * and is used to index the array of route Mappings. If this selector * index value is within the bounds of the array of route Mappings, then * the inverse transformation of the selected route Mapping is used to * transform the supplied "output" position to produce the SwitchMap * "input" position. If the selector index value is outside the bounds * of the array of route Mappings, then the SwitchMap "input" position is * set to a value of AST__BAD on every axis. * * In practice, appropriate selector Mappings should be chosen to * associate a different route Mapping with each region of coordinate * space. Note that the SelectorMap class of Mapping is particularly * appropriate for this purpose. * * If a compound Mapping contains a SwitchMap in series with its own * inverse, the combination of the two adjacent SwitchMaps will be * replaced by a UnitMap when the compound Mapping is simplified using c astSimplify. f AST_SIMPLIFY. * Parameters: c fsmap f FSMAP = INTEGER (Given) * Pointer to the forward selector Mapping. This must have a * defined forward transformation, but need not have a defined * inverse transformation. It must have one output, and the number of * inputs must match the number of inputs of each of the supplied * route Mappings. c NULL f AST__NULL * may be supplied, in which case the SwitchMap will have an undefined * forward Mapping. c ismap f ISMAP = INTEGER (Given) * Pointer to the inverse selector Mapping. This must have a * defined inverse transformation, but need not have a defined * forward transformation. It must have one input, and the number of * outputs must match the number of outputs of each of the supplied * route Mappings. c NULL f AST__NULL * may be supplied, in which case the SwitchMap will have an undefined * inverse Mapping. c nroute f NROUTE = INTEGER (Given) * The number of supplied route Mappings. c routemaps f ROUTEMAPS( NROUTE ) = INTEGER (Given) * An array of pointers to the route Mappings. All the supplied * route Mappings must have common values for the Nin and Nout * attributes, and these values define the number of inputs and * outputs of the SwitchMap. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SwitchMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SwitchMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSwitchMap() f AST_SWITCHMAP = INTEGER * A pointer to the new SwitchMap. * Notes: c - Note that the component Mappings supplied are not copied by c astSwitchMap (the new SwitchMap simply retains a reference to c them). They may continue to be used for other purposes, but c should not be deleted. If a SwitchMap containing a copy of its c component Mappings is required, then a copy of the SwitchMap should c be made using astCopy. f - Note that the component Mappings supplied are not copied by f AST_SWITCHMAP (the new SwitchMap simply retains a reference to f them). They may continue to be used for other purposes, but f should not be deleted. If a SwitchMap containing a copy of its f component Mappings is required, then a copy of the SwitchMap should f be made using AST_COPY. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astSwitchMap constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astSwitchMap_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - Because no checking or casting of arguments is performed * before the function is invoked, the "map1" and "map2" parameters * are of type (void *) and are converted from an ID value to a * pointer and validated within the function itself. * - The variable argument list also prevents this function from * invoking astSwitchMap_ directly, so it must be a re-implementation * of it in all respects, except for the conversions between IDs * and pointers on input/output of Objects. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSwitchMap *new; /* Pointer to new SwitchMap */ AstMapping *fsmap; /* Pointer to fwd selector Mapping */ AstMapping *ismap; /* Pointer to inv selector Mapping */ AstMapping **routemaps; /* Array of route Mapping pointers */ int i; /* Route Mappings index */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = NULL; /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return new; /* Report an error if no route Mappings have been supplied. */ if( nroute <= 0 ) astError( AST__BDPAR, "astSwitchMap(SwitchMap): " " Bad number of route Mappings (%d) specified.", status, nroute ); /* Otherwise create an array to hold the route Mapping pointers. */ routemaps = astMalloc( sizeof( AstMapping * )*nroute ); /* Obtain and validate pointers to the Mapping structures provided. */ if( astOK ) { fsmap = fsmap_void ? astCheckMapping( astMakePointer(fsmap_void) ) : NULL; ismap = ismap_void ? astCheckMapping( astMakePointer(ismap_void) ) : NULL; for( i = 0; i < nroute; i++ ) { routemaps[ i ] = astVerifyMapping( astMakePointer(routemaps_void[ i ]) ); } } if ( astOK ) { /* Initialise the SwitchMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSwitchMap( NULL, sizeof( AstSwitchMap ), !class_init, &class_vtab, "SwitchMap", fsmap, ismap, nroute, routemaps ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SwitchMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Free memory used to hold the route Mapping pointers. */ routemaps = astFree( routemaps ); /* Return an ID value for the new SwitchMap. */ return astMakeId( new ); } AstSwitchMap *astInitSwitchMap_( void *mem, size_t size, int init, AstSwitchMapVtab *vtab, const char *name, AstMapping *fsmap, AstMapping *ismap, int nroute, AstMapping **routemaps, int *status ) { /* *+ * Name: * astInitSwitchMap * Purpose: * Initialise a SwitchMap. * Type: * Protected function. * Synopsis: * #include "switchmap.h" * AstSwitchMap *astInitSwitchMap( void *mem, size_t size, int init, * AstSwitchMapVtab *vtab, const char *name, * AstMapping *fsmap, AstMapping *ismap, * int nroute, AstMapping **routemaps ) * Class Membership: * SwitchMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new SwitchMap object. It allocates memory (if necessary) to * accommodate the SwitchMap plus any additional data associated with the * derived class. It then initialises a SwitchMap structure at the start * of this memory. If the "init" flag is set, it also initialises the * contents of a virtual function table for a SwitchMap at the start of * the memory passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SwitchMap is to be initialised. * This must be of sufficient size to accommodate the SwitchMap data * (sizeof(SwitchMap)) plus any data used by the derived class. If a * value of NULL is given, this function will allocate the memory itself * using the "size" parameter to determine its size. * size * The amount of memory used by the SwitchMap (plus derived class * data). This will be used to allocate memory if a value of NULL is * given for the "mem" parameter. This value is also stored in the * SwitchMap structure, so a valid value must be supplied even if not * required for allocating memory. * init * A logical flag indicating if the SwitchMap's virtual function table * is to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new SwitchMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * fsmap * Pointer to the forward selector Mapping. * ismap * Pointer to the inverse selector Mapping. * nroute * The number of route Mappings supplied. * routemaps * An array holdiong pointers to the route Mappings. * Returned Value: * A pointer to the new SwitchMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstSwitchMap *new; /* Pointer to new SwitchMap */ int i; /* Loop count */ int nin; /* No. input coordinates for SwitchMap */ int nout; /* No. output coordinates for SwitchMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSwitchMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Check that all route Mappings have common values for Nin and Nout.*/ nin = astGetNin( routemaps[ 0 ] ); nout = astGetNout( routemaps[ 0 ] ); for( i = 1; i < nroute; i++ ) { if( nin != astGetNin( routemaps[ i ] ) ){ if( astOK ) { astError( AST__BADNI, "astInitSwitchMap(%s): Route Mapping " "number %d has %d input(s) but the first route " "Mapping has %d input(s).", status, name, i + 1, astGetNin( routemaps[ i ] ), nin ); } } else if( nout != astGetNout( routemaps[ i ] ) ){ if( astOK ) { astError( AST__BADNO, "astInitSwitchMap(%s): Route Mapping " "number %d has %d output(s) but the first route " "Mapping has %d output(s).", status, name, i + 1, astGetNin( routemaps[ i ] ), nin ); } } } /* If supplied, report an error if fsmap has no forward transformation, or if it has an incorrect number of inputs or output. */ if( fsmap && astOK ) { if( !astGetTranForward( fsmap ) ) { astError( AST__INTRD, "astInitSwitchMap(%s): The forward selector Mapping " "is not able to transform coordinates in the forward direction.", status, name ); } else if( astGetNin( fsmap ) != nin ){ astError( AST__BADNI, "astInitSwitchMap(%s): The forward selector " "Mapping has %d input(s) but the SwitchMap has %d " "input(s).", status, name, astGetNin( fsmap ), nin ); } else if( astGetNout( fsmap ) != 1 ){ astError( AST__BADNO, "astInitSwitchMap(%s): The forward selector " "Mapping has %d outputs but should only have 1.", status, name, astGetNout( fsmap ) ); } } /* If supplied, report an error if ismap has no inverse transformation, or if it has an incorrect number of inputs or outputs. */ if( ismap && astOK ) { if( !astGetTranInverse( ismap ) ) { astError( AST__INTRD, "astInitSwitchMap(%s): The inverse selector Mapping " "is not able to transform coordinates in the inverse direction.", status, name ); } else if( nout != astGetNout( ismap ) ){ astError( AST__BADNO, "astInitSwitchMap(%s): The inverse selector " "Mapping has %d output(s) but the SwitchMap has %d " "output(s).", status, name, astGetNout( ismap ), nout ); } else if( astGetNin( ismap ) != 1 ){ astError( AST__BADNI, "astInitSwitchMap(%s): The inverse selector " "Mapping has %d inputs but should only have 1.", status, name, astGetNin( ismap ) ); } } /* Report an error if neither ismap nor fsmap were supplied. */ if( !fsmap && !ismap && astOK ) { astError( AST__INTRD, "astInitSwitchMap(%s): No selector Mappings " "supplied.", status, name ); } /* Initialise a Mapping structure (the parent class) as the first component within the SwitchMap structure, allocating memory if necessary. Specify the number of input and output coordinates and in which directions the Mapping should be defined. */ if ( astOK ) { new = (AstSwitchMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, nin, nout, ( fsmap != NULL ), ( ismap != NULL ) ); if ( astOK ) { /* Initialise the SwitchMap data. */ /* --------------------------- */ /* Store pointers to the selector Mappings. */ new->fsmap = fsmap ? astClone( fsmap ) : NULL; new->ismap = ismap ? astClone( ismap ) : NULL; /* Save the initial values of the inversion flags for these Mappings. */ new->fsinv = fsmap ? astGetInvert( fsmap ) : 0; new->isinv = ismap ? astGetInvert( ismap ) : 0; /* Create arrays for the route Mappings. */ new->routemap = astMalloc( sizeof( AstMapping * )*nroute ); new->routeinv = astMalloc( sizeof( int )*nroute ); /* Store pointers to the route Mappings and their invert flags. */ if( astOK ) { new->nroute = nroute; for( i = 0; i < nroute; i++ ) { new->routemap[ i ] = astClone( routemaps[ i ] ); new->routeinv[ i ] = astGetInvert( routemaps[ i ] ); } } else { new->nroute = 0; } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new object. */ return new; } AstSwitchMap *astLoadSwitchMap_( void *mem, size_t size, AstSwitchMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSwitchMap * Purpose: * Load a SwitchMap. * Type: * Protected function. * Synopsis: * #include "switchmap.h" * AstSwitchMap *astLoadSwitchMap( void *mem, size_t size, * AstSwitchMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * SwitchMap loader. * Description: * This function is provided to load a new SwitchMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SwitchMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a SwitchMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the SwitchMap is to be * loaded. This must be of sufficient size to accommodate the * SwitchMap data (sizeof(SwitchMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SwitchMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SwitchMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSwitchMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SwitchMap. If this is NULL, a pointer to * the (static) virtual function table for the SwitchMap class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SwitchMap" is used instead. * Returned Value: * A pointer to the new SwitchMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSwitchMap *new; AstMapping *rmap; int i; char buf[ 20 ]; /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SwitchMap. In this case the SwitchMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSwitchMap ); vtab = &class_vtab; name = "SwitchMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSwitchMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SwitchMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SwitchMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Forward Selector Mapping and its Invert flag. */ /* --------------------------------------------- */ new->fsmap = astReadObject( channel, "fsmap", NULL ); new->fsinv = astReadInt( channel, "fsinv", 0 ); new->fsinv = ( new->fsinv != 0 ); /* Inverse Selector Mapping and its Invert flag. */ /* --------------------------------------------- */ new->ismap = astReadObject( channel, "ismap", NULL ); new->isinv = astReadInt( channel, "isinv", new->fsinv ); new->isinv = ( new->isinv != 0 ); /* Loop to load each route Mapping and its invert flag. */ /* ---------------------------------------------------- */ new->routemap = NULL; new->routeinv = NULL; i = 0; while( astOK ) { sprintf( buf, "rmap%d", i + 1 ); rmap = astReadObject( channel, buf, NULL ); if( rmap ) { new->routemap = astGrow( new->routemap, i + 1, sizeof( AstMapping *) ); new->routeinv = astGrow( new->routeinv, i + 1, sizeof( int ) ); if( astOK ) { new->routemap[ i ] = rmap; sprintf( buf, "rinv%d", i + 1 ); new->routeinv[ i ] = astReadInt( channel, buf, 0 ); new->routeinv[ i ] = ( new->routeinv[ i ] != 0 ); i++; } } else { break; } } /* Number of route Mappings. */ new->nroute = i; /* If an error occurred, clean up by deleting the new SwitchMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new SwitchMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ /* None. */ ./ast-7.3.3/stccatalogentrylocation.h0000644000175000017500000001676212262533650016266 0ustar olesoles#if !defined( STCCATALOGENTRYLOCATION_INCLUDED ) /* Include this file only once */ #define STCCATALOGENTRYLOCATION_INCLUDED /* *+ * Name: * stccatalogentrylocation.h * Type: * C include file. * Purpose: * Define the interface to the StcCatalogEntryLocation class. * Invocation: * #include "stccatalogentrylocation.h" * Description: * This include file defines the interface to the StcCatalogEntryLocation class * and provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The StcCatalogEntryLocation class is a sub-class of Stc used to describe * the coverage of the datasets contained in some VO resource. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * Inheritance: * The StcCatalogEntryLocation class inherits from the Stc class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 26-NOV-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "stc.h" /* Coordinate stcs (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* StcCatalogEntryLocation structure. */ /* ----------------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstStcCatalogEntryLocation { /* Attributes inherited from the parent class. */ AstStc stc; /* Parent class structure */ } AstStcCatalogEntryLocation; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstStcCatalogEntryLocationVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstStcVtab stc_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ } AstStcCatalogEntryLocationVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstStcCatalogEntryLocationGlobals { AstStcCatalogEntryLocationVtab Class_Vtab; int Class_Init; } AstStcCatalogEntryLocationGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitStcCatalogEntryLocationGlobals_( AstStcCatalogEntryLocationGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(StcCatalogEntryLocation) /* Check class membership */ astPROTO_ISA(StcCatalogEntryLocation) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstStcCatalogEntryLocation *astStcCatalogEntryLocation_( void *, int, AstKeyMap **, const char *, int *, ...); #else AstStcCatalogEntryLocation *astStcCatalogEntryLocationId_( void *, int, AstKeyMap **, const char *, ... )__attribute__((format(printf,4,5))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstStcCatalogEntryLocation *astInitStcCatalogEntryLocation_( void *, size_t, int, AstStcCatalogEntryLocationVtab *, const char *, AstRegion *, int, AstKeyMap **, int * ); /* Vtab initialiser. */ void astInitStcCatalogEntryLocationVtab_( AstStcCatalogEntryLocationVtab *, const char *, int * ); /* Loader. */ AstStcCatalogEntryLocation *astLoadStcCatalogEntryLocation_( void *, size_t, AstStcCatalogEntryLocationVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckStcCatalogEntryLocation(this) astINVOKE_CHECK(StcCatalogEntryLocation,this,0) #define astVerifyStcCatalogEntryLocation(this) astINVOKE_CHECK(StcCatalogEntryLocation,this,1) /* Test class membership. */ #define astIsAStcCatalogEntryLocation(this) astINVOKE_ISA(StcCatalogEntryLocation,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astStcCatalogEntryLocation astINVOKE(F,astStcCatalogEntryLocation_) #else #define astStcCatalogEntryLocation astINVOKE(F,astStcCatalogEntryLocationId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitStcCatalogEntryLocation(mem,size,init,vtab,name,region,ncoords,coords) \ astINVOKE(O,astInitStcCatalogEntryLocation_(mem,size,init,vtab,name,region,ncoords,coords,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitStcCatalogEntryLocationVtab(vtab,name) astINVOKE(V,astInitStcCatalogEntryLocationVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadStcCatalogEntryLocation(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadStcCatalogEntryLocation_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckStcCatalogEntryLocation to validate StcCatalogEntryLocation pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #endif #endif ./ast-7.3.3/makeh0000644000175000017500000002162212262533650012155 0ustar olesoles#!/usr/bin/perl #+ # Name: # makeh # Purpose: # Generate the contents of the "ast.h" header file. # Type: # Perl script. # Invocation: # makeh file_list # Description: # This script processes private header files used within the AST library # in order to extract the public information they contain. This information # is produced in a form suitable for use in the public "ast.h" header file, # which defines the public interface to the library. # Parameters: # file_list # A space-separated list of the private AST header files whose public # information is to be extracted. # Result: # The contents of the "ast.h" header file are written to standard output. # Notes: # - This script is specific to the AST library and contains some knowledge # of the input file contents. # History: # 10-JAN-2005 (DSB): # Added second argument (mode) to the mkdir invocation which creates # the temporary directory. # 2-MAR-2006 (DSB): # Check for "config.h" as well as # 6-JAN-2010 (DSB): # Add work-around for GCC 4.4.2 problem - the pre-processor seesm to simply # throw away backslshes that escape newlines in the input header file. Reported # by Bryan Irby at GSFC. # 27-JUL-2011 (DSB): # Include the process ID in the name of the temporary directory and # file, so that simultaneous invocations of this script do not trample # all over each other. #- ( $#ARGV >= 0 ) || Usage(); # Test whether we need to include config.h in the result. $need_config_h = 0; # Location of source files (makefile variable $(srcdir)). # This is most typically '.', but can be different. $srcdir = '.'; while ( $ARGV[0] =~ /^-/ ) { if ( $ARGV[0] eq '-s' ) { shift @ARGV; ( $#ARGV >= 0 ) || Usage(); $srcdir = $ARGV[0]; shift @ARGV; } else { Usage(); } } # Create a scratch directory. $tmpdir="/tmp/makeh-$$.tmp"; unless ( -d $tmpdir && -w $tmpdir ) { if ( -e $tmpdir ) { die "Temp $tmpdir exists, but is unwritable or is not a directory\n"; } mkdir $tmpdir, 0777 || die "Failed to create temporary directory $tmpdir\n"; } # Open each input file. foreach $file ( @ARGV ) { protect_copy_file( $file ); } # Open a pipe to a script (in the current directory) which runs the C # preprocessor and direct its output to a scratch file. open( CC, "| ./ast_cpp >/tmp/ast-$$.h" ) || die "Can't open pipe to C preprocessor (cpp)"; if ( $need_config_h ) { # Include this directory's config.h, unescaped, in the output. We # need to pay attention to the values in this file, but don't want # them unexpanded in the final ast.h. chomp($cwd = `pwd`); print(CC "#include \"$cwd/config.h\"\n"); } # Before including each file, write an underlined heading in the form of # C comments (with comment characters suitably protected so that they will # be passed unchanged by cpp). foreach $file ( @ARGV ) { $comment = $file; $comment =~ s|^.*/||; $comment =~ s|.h$||; print( CC "/_* " . $comment . ". *_/\n" ); $comment =~ s/./=/g; print( CC "/_* " . $comment . "= *_/\n" ); # Write #include "xxx.h" lines to cpp so that it includes (and # preprocesses) each of the temporary files created above in turn. $tmp_file = $file; $tmp_file =~ s|^.*/||; printf(CC "#include \"%s/%s\"\n", $tmpdir, $tmp_file); }; # Close the pipe to cpp. close( CC ) || die "C preprocessor (cpp) error"; # Remove the temporary directory and the files it contains. print( stderr `rm -r $tmpdir` ); # Write the output preamble. print( '#if !defined(AST_INCLUDED) #define AST_INCLUDED /* *+ * Name: * ast.h * Purpose: * Define the public C interface to the AST library. * Language: * ANSI C * Type of Module: * C header file. * Description: * This file defines the public C interface to the AST library. It contains * all the type definitions, function prototypes, macro definitions, etc. * needed to use the library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (STARLINK) * RFWS: R.F. Warren-Smith (STARLINK) * {enter_new_authors_here} * History: * ' ); # Add the current date at this point. ( $sec, $min, $hour, $mday, $mon, $year ) = localtime; print( $mday, '-', ( 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' )[ $mon ], '-', ( $year > 95 ? 1900 : 2000 ) + $year ); print( ' (makeh): * Original version, generated automatically from the internal header * files by the "makeh" script. * {enter_changes_here} *- */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif ' ); # Open the scratch file created above and read it. $space = 0; open( TEMP, " ) { # Remove the underscores from the protected lines and macros. s/^_#include(\s)/#include$1/; s/^_#define(\s)/#define$1/; s/___LINE__/__LINE__/g; s/___FILE__/__FILE__/g; # Also un-protect protected comments. s|/_\*|/*|g; s|\*_/|*/|g; # Convert multiple blank lines (cpp creates lots of these) into single blank # lines. if ( /^\s*$/ ) { $space = 1; } else { # Remove additional unwanted lines that cpp creates. if ( ! /^# \d+/ ) { if ( $space ) { print( "\n" ) }; $space = 0; # Output the lines we want to keep. print; } } } # Write closing output lines. print( ' #endif ' ); # Close and remove the scratch file. close( TEMP ); unlink "/tmp/ast-$$.h"; sub protect_copy_file { my $file = shift; open( INCLUDE, "$srcdir/$file" ) || die "Can't open input file " . $srcdir/$file; # Inicate we have no deferred text to write out. $total = ""; # Open an output file with the same name in the temporary directory. $tmp_file = $file; $tmp_file =~ s|^.*/||; open( TEMP, ">$tmpdir/$tmp_file" ); # Read the input file and detect "#include <...>" lines, extracting the name # of the header file being included. line: while ( ) { # Omit any config.h includes, and note that we saw this if (/^\s*\#\s*include\s+/ || /^\s*\#\s*include\s+"config.h"/) { $need_config_h = 1; next line; } if ( ( $header ) = /^\#include\s+<(.+)>/ ) { # If this system header file has already been included, ignore it and go on to # the next input line. next line if $done{ $header }++; # Otherwise, protect the #include with an underscore to prevent the file # actually being included. s/^/_/; } # Also protect "#define ..." lines, to prevent macro substitution being # performed by the C preprocessor. Do not do this to lines of the form # "#define XXX_INCLUDED" because these are still needed to determine which # AST header files get included. if ( /^\#define\s/ ) { if ( ! /^\#define\s+\w*_INCLUDED/ ) { s/^/_/ }; } # Similarly add underscores to protect standard C macros. s/__LINE__/___LINE__/g; s/__FILE__/___FILE__/g; # Some pre-processors (e.g. GCC 4.4.2) seem to simply throw away trailing # backslashes used to concatenate consecutive lines, producing two # independent lines in the output rather than one. This completely fouls # up the resulting header file. To avoid this, we concatenate such lines # explicitly, before writing them out to the temporary output file. # If the current line ends with an escaped newline, remove the escape # character and newline, and concatenate it with any previously deferred # lines. if( /^(.*)\\\s*$/ ) { $total .= $1; # If the current line does not end with an escaped newline, concatenate it # with any previously deferred lines, and write the total string out. Then # reset the total string to indicate we have no deferred text. } else { $total .= $_; print TEMP $total; $total = ""; } } # Close each file when done. close( INCLUDE ); close( TEMP ); } sub Usage { print STDERR "$0 [-s srcdir] file...\n"; exit (1); } ./ast-7.3.3/skyframe.c0000644000175000017500000146402012262533650013136 0ustar olesoles/* *class++ * Name: * SkyFrame * Purpose: * Celestial coordinate system description. * Constructor Function: c astSkyFrame f AST_SKYFRAME * Description: * A SkyFrame is a specialised form of Frame which describes * celestial longitude/latitude coordinate systems. The particular * celestial coordinate system to be represented is specified by * setting the SkyFrame's System attribute (currently, the default * is ICRS) qualified, as necessary, by a mean Equinox value and/or * an Epoch. * * For each of the supported celestial coordinate systems, a SkyFrame * can apply an optional shift of origin to create a coordinate system * representing offsets within the celestial coordinate system from some * specified reference point. This offset coordinate system can also be * rotated to define new longitude and latitude axes. See attributes * SkyRef, SkyRefIs, SkyRefP and AlignOffset. * * All the coordinate values used by a SkyFrame are in * radians. These may be formatted in more conventional ways for c display by using astFormat. f display by using AST_FORMAT. * Inheritance: * The SkyFrame class inherits from the Frame class. * Attributes: * In addition to those attributes common to all Frames, every * SkyFrame also has the following attributes: * * - AlignOffset: Align SkyFrames using the offset coordinate system? * - AsTime(axis): Format celestial coordinates as times? * - Equinox: Epoch of the mean equinox * - IsLatAxis: Is the specified axis the latitude axis? * - IsLonAxis: Is the specified axis the longitude axis? * - LatAxis: Index of the latitude axis * - LonAxis: Index of the longitude axis * - NegLon: Display longitude values in the range [-pi,pi]? * - Projection: Sky projection description. * - SkyRef: Position defining location of the offset coordinate system * - SkyRefIs: Selects the nature of the offset coordinate system * - SkyRefP: Position defining orientation of the offset coordinate system * Functions: * In addition to those c functions f routines * applicable to all Frames, the following c functions f routines * may also be applied to all SkyFrames: * c - astSkyOffsetMap: Obtain a Mapping from absolute to offset coordinates f - AST_SKYOFFSETMAP: Obtain a Mapping from absolute to offset coordinates * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2010 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * BEC: Brad Cavanagh (JAC, Hawaii) * History: * 4-MAR-1996 (RFWS): * Original version. * 17-MAY-1996 (RFWS): * Tidied up, etc. * 31-JUL-1996 (RFWS): * Added support for attributes and a public interface. * 11-SEP-1996 (RFWS): * Added Gap (written by DSB). * 24-SEP-1996 (RFWS): * Added I/O facilities. * 27-FEB-1997 (RFWS): * Improved the public prologues. * 27-MAY-1997 (RFWS): * Modified to use a new public interface to the SlaMap class * and to use the astSimplify method to remove redundant * conversions. * 16-JUN-1997 (RFWS): * Fixed bug in axis associations returned by astMatch if axes * were swapped. * 16-JUL-1997 (RFWS): * Added Projection attribute. * 14-NOV-1997 (RFWS): * Corrected the omission of axis permutations from astNorm. * 21-JAN-1998 (RFWS): * Ensure that Title and Domain values appropriate to a SkyFrame * are preserved if a Frame result is generated by SubFrame. * 26-FEB-1998 (RFWS): * Over-ride the astUnformat method. * 3-APR-2001 (DSB): * Added "Unknown" option for the System attribute. Added read-only * attributes LatAxis and LonAxis. * 21-JUN-2001 (DSB): * Added astAngle and astOffset2. * 4-SEP-2001 (DSB): * Added NegLon attribute, and astResolve method. * 9-SEP-2001 (DSB): * Added astBear method. * 21-SEP-2001 (DSB): * Removed astBear method. * 10-OCT-2002 (DSB): * Moved definitions of macros for SkyFrame system values from * this file into skyframe.h. * 24-OCT-2002 (DSB): * Modified MakeSkyMapping so that any two SkyFrames with system=unknown * are assumed to be related by a UnitMap. previously, they were * considered to be unrelated, resulting in no ability to convert from * one to the other. This could result for instance in astConvert * being unable to find a maping from a SkyFrame to itself. * 15-NOV-2002 (DSB): * Moved System and Epoch attributes to the Frame class. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitSkyFrameVtab * method. * 11-JUN-2003 (DSB): * Added ICRS option for System attribute, and made it the default * in place of FK5. * 27-SEP-2003 (DSB): * Added HELIOECLIPTIC option for System attribute. * 19-APR-2004 (DSB): * Added SkyRef, SkyRefIs, SkyRefP and AlignOffset attributes. * 8-SEP-2004 (DSB): * Added astResolvePoints method. * 2-DEC-2004 (DSB): * Added System "J2000" * 27-JAN-2005 (DSB): * Fix memory leaks in astLoadSkyFrame_ and Match. * 7-APR-2005 (DSB): * Allow SkyRefIs to be set to "Ignored". * 12-MAY-2005 (DSB): * Override astNormBox method. * 15-AUG-2005 (DSB): * Added AZEL system. * 13-SEP-2005 (DSB): * Override astClearSystem so that SkyRef/SkyRefPcan be converted * from the original System to the default System. * 19-SEP-2005 (DSB): * Changed default for SkyRefIs from ORIGIN to IGNORED. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 22-FEB-2006 (DSB): * Store the Local Apparent Sidereal Time in the SkyFrame structure * in order to avoid expensive re-computations. * 22-AUG-2006 (DSB): * Ensure the cached Local Apparent Siderial Time is initialised * when initialising or loading a SkyFrame. * 22-SEP-2006 (DSB): * Report an error in SetSystem if it is not possible to convert * from old to new systems. * 3-OCT-2006 (DSB): * Added Equation of Equinoxes to the SkyFrame structure. * 6-OCT-2006 (DSB): * - Guard against annulling null pointers in subFrame. * - Add Dut1 attribute * - Use linear approximation for LAST over short periods (less * than 0.001 of a day) * - Remove Equation of Equinoxes from the SkyFrame structure. * 10-OCT-2006 (DSB): * Use "AlOff" instead of "AlignOffset" as the external channel name * for the AlignOffset attribute. The longer form exceeded the * limit that can be used by the Channel class. * 14-OCT-2006 (DSB): * - Move Dut1 attribute to the Frame class. * - Use the TimeFrame class to do the TDB->LAST conversions. * 17-JAN-2007 (DSB): * - Use a UnitMap to align offset coordinate systems in two * SkyFrames, regardless of other attribute values. * - Only align in offset coordinates if both target and template * have a non-zero value for AlignOffset. * 23-JAN-2007 (DSB): * Modified so that a SkyFrame can be used as a template to find a * SkyFrame contained within a CmpFrame. This involves changes in * Match and the removal of the local versions of SetMaxAxes and * SetMinAxes. * 4-JUL-2007 (DSB): * Modified GetLast to use the correct solar to sidereal conversion * factor. As a consequence the largest acceptable epoch gap before * the LAST needs to be recalculated has been increased. * 11-JUL-2007 (DSB): * Override astSetEpoch and astClearEpoch by implementations which * update the LAST value stored in the SkyFrame. * 7-AUG-2007 (DSB): * - Set a value for the CentreZero attribute when extracting a * SkyAxis from a SkyFrame in function SubFrame. * - In SubFrame, clear extended attributes such as System after * all axis attributes have been "fixated. * 30-AUG-2007 (DSB): * Override astSetDut1 and astClearDut1 by implementations which * update the LAST value stored in the SkyFrame. * 31-AUG-2007 (DSB): * - Cache the magnitude of the diurnal aberration vector in the * SkyFrame structure for use when correcting for diurnal aberration. * - Modify the azel conversions to include correction for diurnal * aberration. * - Override astClearObsLat and astSetObsLat by implementations which * reset the magnitude of the diurnal aberration vector. * 3-SEP-2007 (DSB): * In SubFrame, since AlignSystem is extended by the SkyFrame class * it needs to be cleared before invoking the parent SubFrame * method in cases where the result Frame is not a SkyFrame. * 2-OCT-2007 (DSB): * In Overlay, clear AlignSystem as well as System before calling * the parent overlay method. * 10-OCT-2007 (DSB): * In MakeSkyMapping, correct the usage of variables "system" and * "align_sys" when aligning in AZEL. * 18-OCT-2007 (DSB): * Compare target and template AlignSystem values in Match, rather * than comparing target and result AlignSystem values in MakeSkyMapping * (since result is basically a copy of target). * 27-NOV-2007 (DSB): * - Modify SetSystem to ensure that SkyRef and SkyRefP position are * always transformed as absolute values, rather than as offset * values. * - Modify SubMatch so that a value of zero is assumed for * AlignOffset when restoring thre integrity of a FrameSet. * 15-DEC-2008 (DSB): * Improve calculation of approximate Local Apparent Sidereal time * by finding and using the ratio of solar to sidereal time * independently for each approximation period. * 14-JAN-2009 (DSB): * Override the astIntersect method. * 21-JAN-2009 (DSB): * Fix mis-use of results buffers for GetFormat and GetAttrib. * 16-JUN-2009 (DSB): * All sky coordinate systems currently supported by SkyFrame are * left handed. So fix GetDirection method to return zero for all * longitude axes and 1 for all latitude axes. * 18-JUN-2009 (DSB): * Incorporate the new ObsAlt attribute. * 23-SEP-2009 (DSB): * Allow some rounding error when checking for changes in SetObsLon * and SetDut1. This reduces the number of times the expensive * calculation of LAST is performed. * 24-SEP-2009 (DSB); * Create a static cache of LAST values stored in the class virtual * function table. These are used in preference to calculating a new * value from scratch. * 25-SEP-2009 (DSB); * Do not calculate LAST until it is needed. * 12-OCT-2009 (DSB); * - Handle 2.PI->0 discontinuity in cached LAST values. * 12-OCT-2009 (BEC); * - Fix bug in caching LAST value. * 31-OCT-2009 (DSB); * Correct SetCachedLAST to handle cases where the epoch to be * stored is smaller than any epoch already in the table. * 24-NOV-2009 (DSB): * - In CalcLast, only use end values form the table of stored * LAST values if the corresponding epochs are within 0.001 of * a second of the required epoch (this tolerance used to be * 0.1 seconds). * - Do not clear the cached LAST value in SetEpoch and ClearEpoch. * 8-MAR-2010 (DSB): * Add astSkyOffsetMap method. * 7-APR-2010 (DSB): * Add IsLatAxis and IsLonAxis attributes. * 11-MAY-2010 (DSB): * In SetSystem, clear SkyRefP as well as SkyRef. * 22-MAR-2011 (DSB): * Override astFrameGrid method. * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. * 23-MAY-2011 (DSB): * Truncate returned PointSet in function FrameGrid to exclude unused points. * 24-MAY-2011 (DSB): * When clearing or setting the System attribute, clear SkyRef rather * than reporting an error if the Mapping from the old System to the * new System is unknown. * 30-NOV-2011 (DSB): * When aligning two SkyFrames in the system specified by AlignSystem, * do not assume inappropriate default equinox values for systems * that are not referred to the equinox specified by the Equinox attribute. * 26-APR-2012 (DSB): * - Correct Dump function so that any axis permutation is taken into * account when dumping SkyFrame attributes that have a separate value * for each axis (e.g. SkyRef and SkyRefP). * - Take axis permutation into account when setting a new value * for attributes that have a separate value for each axis (e.g. * SkyRef and SkyRefP). * - Remove the code that overrides ClearEpoch and SetEpoch (these * overrides have not been needed since the changes made on * 24/11/2009). * 27-APR-2012 (DSB): * - Correct astLoadSkyFrame function so that any axis permutation is * taken into account when loading SkyFrame attributes that have a * separate value for each axis. * 25-JUL-2013 (DSB): * Use a single table of cached LAST values for all threads, rather * than a separate table for each thread. The problem with a table per * thread is that if you have N threads, each table contains only * one N'th of the total number of cached values, resulting in * poorer accuracy, and small variations in interpolated LAST value * depending on the way the cached values are distributed amongst the * N threads. * 6-AST-2013 (DSB): * Fix the use of the read-write lock that is used to serialise * access to the table of cached LAST values. This bug could * cause occasional problems where an AST pointer would became * invalid for no apparent reason. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SkyFrame /* Define the first and last acceptable System values. */ #define FIRST_SYSTEM AST__FK4 #define LAST_SYSTEM AST__AZEL /* Speed of light (AU per day) (from SLA_AOPPA) */ #define C 173.14463331 /* Ratio between solar and sidereal time (from SLA_AOPPA) */ #define SOLSID 1.00273790935 /* Define values for the different values of the SkyRefIs attribute. */ #define POLE_STRING "Pole" #define ORIGIN_STRING "Origin" #define IGNORED_STRING "Ignored" /* Define other numerical constants for use in this module. */ #define GETATTRIB_BUFF_LEN 200 #define GETFORMAT_BUFF_LEN 50 #define GETLABEL_BUFF_LEN 40 #define GETSYMBOL_BUFF_LEN 20 #define GETTITLE_BUFF_LEN 200 /* A macro which returns a flag indicating if the supplied system is references to the equinox specified by the Equinox attribute. */ #define EQREF(system) \ ((system==AST__FK4||system==AST__FK4_NO_E||system==AST__FK5||system==AST__ECLIPTIC)?1:0) /* * * Name: * MAKE_CLEAR * Purpose: * Implement a method to clear a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "skyframe.h" * MAKE_CLEAR(attr,component,assign,nval) * Class Membership: * Defined by the SkyFrame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Clear( AstSkyFrame *this, int axis ) * * and an external interface function of the form: * * void astClear_( AstSkyFrame *this, int axis ) * * which implement a method for clearing a single value in a specified * multi-valued attribute for an axis of a SkyFrame. * Parameters: * attr * The name of the attribute to be cleared, as it appears in the function * name (e.g. Label in "astClearLabelAt"). * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to assign to the component * to clear its value. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_CLEAR(attr,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Clear##attr( AstSkyFrame *this, int axis, int *status ) { \ \ int axis_p; \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate and permute the axis index. */ \ axis_p = astValidateAxis( this, axis, 1, "astClear" #attr ); \ \ /* Assign the "clear" value. */ \ if( astOK ) { \ this->component[ axis_p ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astClear##attr##_( AstSkyFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,SkyFrame,Clear##attr))( this, axis, status ); \ } /* * * Name: * MAKE_GET * Purpose: * Implement a method to get a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "skyframe.h" * MAKE_GET(attr,type,bad_value,assign,nval) * Class Membership: * Defined by the SkyFrame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( AstSkyFrame *this, int axis ) * * and an external interface function of the form: * * astGet_( AstSkyFrame *this, int axis ) * * which implement a method for getting a single value from a specified * multi-valued attribute for an axis of a SkyFrame. * Parameters: * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astGetLabel"). * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. This can * use the string "axis" to represent the zero-based value index. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_GET(attr,type,bad_value,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type Get##attr( AstSkyFrame *this, int axis, int *status ) { \ int axis_p; /* Permuted axis index */ \ type result; /* Result to be returned */ \ \ /* Initialise */\ result = (bad_value); \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate and permute the axis index. */ \ axis_p = astValidateAxis( this, axis, 1, "astGet" #attr ); \ \ /* Assign the result value. */ \ if( astOK ) { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ type astGet##attr##_( AstSkyFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,SkyFrame,Get##attr))( this, axis, status ); \ } /* * * Name: * MAKE_SET * Purpose: * Implement a method to set a single value in a multi-valued attribute * for a SkyFrame. * Type: * Private macro. * Synopsis: * #include "skyframe.h" * MAKE_SET(attr,type,component,assign,nval) * Class Membership: * Defined by the SkyFrame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( AstSkyFrame *this, int axis, value ) * * and an external interface function of the form: * * void astSet_( AstSkyFrame *this, int axis, value ) * * which implement a method for setting a single value in a specified * multi-valued attribute for a SkyFrame. * Parameters: * attr * The name of the attribute to be set, as it appears in the function * name (e.g. Label in "astSetLabelAt"). * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_SET(attr,type,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Set##attr( AstSkyFrame *this, int axis, type value, int *status ) { \ \ int axis_p; \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate and permute the axis index. */ \ axis_p = astValidateAxis( this, axis, 1, "astSet" #attr ); \ \ /* Store the new value in the structure component. */ \ if( astOK ) { \ this->component[ axis_p ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astSet##attr##_( AstSkyFrame *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,SkyFrame,Set##attr))( this, axis, value, status ); \ } /* * * Name: * MAKE_TEST * Purpose: * Implement a method to test if a single value has been set in a * multi-valued attribute for a class. * Type: * Private macro. * Synopsis: * #include "skyframe.h" * MAKE_TEST(attr,assign,nval) * Class Membership: * Defined by the SkyFrame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static int Test( AstSkyFrame *this, int axis ) * * and an external interface function of the form: * * int astTest_( AstSkyFrame *this, int axis ) * * which implement a method for testing if a single value in a specified * multi-valued attribute has been set for a class. * Parameters: * attr * The name of the attribute to be tested, as it appears in the function * name (e.g. Label in "astTestLabelAt"). * assign * An expression that evaluates to 0 or 1, to be used as the returned * value. This can use the string "axis" to represent the zero-based * index of the value within the attribute. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_TEST(attr,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static int Test##attr( AstSkyFrame *this, int axis, int *status ) { \ int result; /* Value to return */ \ int axis_p; /* Permuted axis index */ \ \ /* Initialise */ \ result =0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate and permute the axis index. */ \ axis_p = astValidateAxis( this, axis, 1, "astTest" #attr ); \ \ /* Assign the result value. */ \ if( astOK ) { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ int astTest##attr##_( AstSkyFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,SkyFrame,Test##attr))( this, axis, status ); \ } /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points (for AST__BAD) */ #include "unitmap.h" /* Unit Mappings */ #include "permmap.h" /* Coordinate permutations */ #include "cmpmap.h" /* Compound Mappings */ #include "slamap.h" /* SLALIB sky coordinate Mappings */ #include "timemap.h" /* Time conversions */ #include "skyaxis.h" /* Sky axes */ #include "frame.h" /* Parent Frame class */ #include "matrixmap.h" /* Matrix multiplication */ #include "sphmap.h" /* Cartesian<->Spherical transformations */ #include "skyframe.h" /* Interface definition for this class */ #include "pal.h" /* SLALIB library interface */ #include "wcsmap.h" /* Factors of PI */ #include "timeframe.h" /* Time system transformations */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Type Definitions. */ /* ================= */ /* Cached Line structure. */ /* ---------------------- */ /* This structure contains information describing a line segment within a SkyFrame. It differs from the AstLineDef defined in frame.h because positions are represented by 3D (x,y,z) cartesian coords rather than 2D (long,lat) coords. */ typedef struct SkyLineDef { AstFrame *frame; /* Pointer to Frame in which the line is defined */ double length; /* Line length */ int infinite; /* Disregard the start and end of the line? */ double start[3]; /* Unit vector defining start of line */ double end[3]; /* Unit vector defining end of line */ double dir[3]; /* Unit vector defining line direction */ double q[3]; /* Unit vector perpendicular to line */ double start_2d[2]; double end_2d[2]; } SkyLineDef; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are used or extended by this class. */ static AstSystemType (* parent_getalignsystem)( AstFrame *, int * ); static AstSystemType (* parent_getsystem)( AstFrame *, int * ); static const char *(* parent_format)( AstFrame *, int, double, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static const char *(* parent_getdomain)( AstFrame *, int * ); static const char *(* parent_getformat)( AstFrame *, int, int * ); static const char *(* parent_getlabel)( AstFrame *, int, int * ); static const char *(* parent_getsymbol)( AstFrame *, int, int * ); static const char *(* parent_gettitle)( AstFrame *, int * ); static const char *(* parent_getunit)( AstFrame *, int, int * ); static double (* parent_gap)( AstFrame *, int, double, int *, int * ); static double (* parent_getbottom)( AstFrame *, int, int * ); static double (* parent_getepoch)( AstFrame *, int * ); static double (* parent_gettop)( AstFrame *, int, int * ); static int (* parent_getdirection)( AstFrame *, int, int * ); static int (* parent_getobjsize)( AstObject *, int * ); static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static int (* parent_testformat)( AstFrame *, int, int * ); static int (* parent_unformat)( AstFrame *, int, const char *, double *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_cleardut1)( AstFrame *, int * ); static void (* parent_clearformat)( AstFrame *, int, int * ); static void (* parent_clearobsalt)( AstFrame *, int * ); static void (* parent_clearobslat)( AstFrame *, int * ); static void (* parent_clearobslon)( AstFrame *, int * ); static void (* parent_clearsystem)( AstFrame *, int * ); static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_setdut1)( AstFrame *, double, int * ); static void (* parent_setformat)( AstFrame *, int, const char *, int * ); static void (* parent_setobsalt)( AstFrame *, double, int * ); static void (* parent_setobslat)( AstFrame *, double, int * ); static void (* parent_setobslon)( AstFrame *, double, int * ); static void (* parent_setsystem)( AstFrame *, AstSystemType, int * ); /* Factors for converting between hours, degrees and radians. */ static double hr2rad; static double deg2rad; static double pi; static double piby2; /* Table of cached Local Apparent Sidereal Time values and corresponding epochs. */ static int nlast_tables = 0; static AstSkyLastTable **last_tables = NULL; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->GetFormat_Buff[ 0 ] = 0; \ globals->GetLabel_Buff[ 0 ] = 0; \ globals->GetSymbol_Buff[ 0 ] = 0; \ globals->GetTitle_Buff[ 0 ] = 0; \ globals->GetTitle_Buff2[ 0 ] = 0; \ globals->TDBFrame = NULL; \ globals->LASTFrame = NULL; \ /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SkyFrame) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SkyFrame,Class_Init) #define class_vtab astGLOBAL(SkyFrame,Class_Vtab) #define getattrib_buff astGLOBAL(SkyFrame,GetAttrib_Buff) #define getformat_buff astGLOBAL(SkyFrame,GetFormat_Buff) #define getlabel_buff astGLOBAL(SkyFrame,GetLabel_Buff) #define getsymbol_buff astGLOBAL(SkyFrame,GetSymbol_Buff) #define gettitle_buff astGLOBAL(SkyFrame,GetTitle_Buff) #define gettitle_buff2 astGLOBAL(SkyFrame,GetTitle_Buff2) #define tdbframe astGLOBAL(SkyFrame,TDBFrame) #define lastframe astGLOBAL(SkyFrame,LASTFrame) static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); /* A read-write lock used to protect the table of cached LAST values so that multiple threads can read simultaneously so long as no threads are writing to the table. */ static pthread_rwlock_t rwlock1=PTHREAD_RWLOCK_INITIALIZER; #define LOCK_WLOCK1 pthread_rwlock_wrlock( &rwlock1 ); #define LOCK_RLOCK1 pthread_rwlock_rdlock( &rwlock1 ); #define UNLOCK_RWLOCK1 pthread_rwlock_unlock( &rwlock1 ); /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Buffer returned by GetAttrib. */ static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ]; /* Buffer returned by GetFormat. */ static char getformat_buff[ GETFORMAT_BUFF_LEN + 1 ]; /* Default GetLabel string buffer */ static char getlabel_buff[ GETLABEL_BUFF_LEN + 1 ]; /* Default GetSymbol buffer */ static char getsymbol_buff[ GETSYMBOL_BUFF_LEN + 1 ]; /* Default Title string buffer */ static char gettitle_buff[ AST__SKYFRAME_GETTITLE_BUFF_LEN + 1 ]; static char gettitle_buff2[ AST__SKYFRAME_GETTITLE_BUFF_LEN + 1 ]; /* TimeFrames for doing TDB<->LAST conversions. */ static AstTimeFrame *tdbframe = NULL; static AstTimeFrame *lastframe = NULL; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSkyFrameVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #define LOCK_WLOCK1 #define LOCK_RLOCK1 #define UNLOCK_RWLOCK1 #endif /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * ); static AstMapping *SkyOffsetMap( AstSkyFrame *, int * ); static AstPointSet *FrameGrid( AstFrame *, int, const double *, const double *, int * ); static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * ); static AstSystemType GetAlignSystem( AstFrame *, int * ); static AstSystemType GetSystem( AstFrame *, int * ); static AstSystemType SystemCode( AstFrame *, const char *, int * ); static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * ); static const char *Format( AstFrame *, int, double, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetDomain( AstFrame *, int * ); static const char *GetFormat( AstFrame *, int, int * ); static const char *GetLabel( AstFrame *, int, int * ); static const char *GetProjection( AstSkyFrame *, int * ); static const char *GetSymbol( AstFrame *, int, int * ); static const char *GetTitle( AstFrame *, int * ); static const char *GetUnit( AstFrame *, int, int * ); static const char *SystemString( AstFrame *, AstSystemType, int * ); static double Angle( AstFrame *, const double[], const double[], const double[], int * ); static double CalcLAST( AstSkyFrame *, double, double, double, double, double, int * ); static double Distance( AstFrame *, const double[], const double[], int * ); static double Gap( AstFrame *, int, double, int *, int * ); static double GetBottom( AstFrame *, int, int * ); static double GetCachedLAST( AstSkyFrame *, double, double, double, double, double, int * ); static double GetEpoch( AstFrame *, int * ); static double GetEquinox( AstSkyFrame *, int * ); static void SetCachedLAST( AstSkyFrame *, double, double, double, double, double, double, int * ); static void SetLast( AstSkyFrame *, int * ); static double GetTop( AstFrame *, int, int * ); static double Offset2( AstFrame *, const double[2], double, double, double[2], int * ); static double GetDiurab( AstSkyFrame *, int * ); static double GetLAST( AstSkyFrame *, int * ); static int GetActiveUnit( AstFrame *, int * ); static int GetAsTime( AstSkyFrame *, int, int * ); static int GetDirection( AstFrame *, int, int * ); static int GetIsLatAxis( AstSkyFrame *, int, int * ); static int GetIsLonAxis( AstSkyFrame *, int, int * ); static int GetLatAxis( AstSkyFrame *, int * ); static int GetLonAxis( AstSkyFrame *, int * ); static int GetNegLon( AstSkyFrame *, int * ); static int GetObjSize( AstObject *, int * ); static int IsEquatorial( AstSystemType, int * ); static int LineContains( AstFrame *, AstLineDef *, int, double *, int * ); static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * ); static int LineIncludes( SkyLineDef *, double[3], int * ); static int MakeSkyMapping( AstSkyFrame *, AstSkyFrame *, AstSystemType, AstMapping **, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int TestActiveUnit( AstFrame *, int * ); static int TestAsTime( AstSkyFrame *, int, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int TestEquinox( AstSkyFrame *, int * ); static int TestNegLon( AstSkyFrame *, int * ); static int TestProjection( AstSkyFrame *, int * ); static int Unformat( AstFrame *, int, const char *, double *, int * ); static void ClearAsTime( AstSkyFrame *, int, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void ClearDut1( AstFrame *, int * ); static void ClearEquinox( AstSkyFrame *, int * ); static void ClearNegLon( AstSkyFrame *, int * ); static void ClearObsAlt( AstFrame *, int * ); static void ClearObsLat( AstFrame *, int * ); static void ClearObsLon( AstFrame *, int * ); static void ClearProjection( AstSkyFrame *, int * ); static void ClearSystem( AstFrame *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * ); static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * ); static void MatchAxesX( AstFrame *, AstFrame *, int *, int * ); static void Norm( AstFrame *, double[], int * ); static void NormBox( AstFrame *, double[], double[], AstMapping *, int * ); static void Offset( AstFrame *, const double[], const double[], double, double[], int * ); static void Overlay( AstFrame *, const int *, AstFrame *, int * ); static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); static void SetAsTime( AstSkyFrame *, int, int, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SetDut1( AstFrame *, double, int * ); static void SetEquinox( AstSkyFrame *, double, int * ); static void SetNegLon( AstSkyFrame *, int, int * ); static void SetObsAlt( AstFrame *, double, int * ); static void SetObsLat( AstFrame *, double, int * ); static void SetObsLon( AstFrame *, double, int * ); static void SetProjection( AstSkyFrame *, const char *, int * ); static void SetSystem( AstFrame *, AstSystemType, int * ); static void Shapp( double, double *, double *, double, double *, int * ); static void Shcal( double, double, double, double *, double *, int * ); static void VerifyMSMAttrs( AstSkyFrame *, AstSkyFrame *, int, const char *, const char *, int * ); static double GetSkyRef( AstSkyFrame *, int, int * ); static int TestSkyRef( AstSkyFrame *, int, int * ); static void SetSkyRef( AstSkyFrame *, int, double, int * ); static void ClearSkyRef( AstSkyFrame *, int, int * ); static double GetSkyRefP( AstSkyFrame *, int, int * ); static int TestSkyRefP( AstSkyFrame *, int, int * ); static void SetSkyRefP( AstSkyFrame *, int, double, int * ); static void ClearSkyRefP( AstSkyFrame *, int, int * ); static int GetSkyRefIs( AstSkyFrame *, int * ); static int TestSkyRefIs( AstSkyFrame *, int * ); static void SetSkyRefIs( AstSkyFrame *, int, int * ); static void ClearSkyRefIs( AstSkyFrame *, int * ); static int GetAlignOffset( AstSkyFrame *, int * ); static int TestAlignOffset( AstSkyFrame *, int * ); static void SetAlignOffset( AstSkyFrame *, int, int * ); static void ClearAlignOffset( AstSkyFrame *, int * ); /* Member functions. */ /* ================= */ static double Angle( AstFrame *this_frame, const double a[], const double b[], const double c[], int *status ) { /* * Name: * Angle * Purpose: * Calculate the angle subtended by two points at a third point. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double Angle( AstFrame *this_frame, const double a[], * const double b[], const double c[], int *status ) * Class Membership: * SkyFrame member function (over-rides the astAngle method * inherited from the Frame class). * Description: * This function finds the angle at point B between the line * joining points A and B, and the line joining points C * and B. These lines will in fact be geodesic curves (great circles). * Parameters: * this * Pointer to the SkyFrame. * a * An array of double, with one element for each SkyFrame axis, * containing the coordinates of the first point. * b * An array of double, with one element for each SkyFrame axis, * containing the coordinates of the second point. * c * An array of double, with one element for each SkyFrame axis, * containing the coordinates of the third point. * status * Pointer to the inherited status variable. * Returned Value: * The angle in radians, from the line AB to the line CB, in * the range $\pm \pi$ with positive rotation is in the same sense * as rotation from axis 2 to axis 1. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input coordinates has this value. * - A "bad" value will also be returned if points A and B are * co-incident, or if points B and C are co-incident. * - A "bad" value will also be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ const int *perm; /* Axis permutation array */ double aa[ 2 ]; /* Permuted a coordinates */ double anga; /* Angle from north to the line BA */ double angc; /* Angle from north to the line BC */ double bb[ 2 ]; /* Permuted b coordinates */ double cc[ 2 ]; /* Permuted c coordinates */ double result; /* Value to return */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Check that all supplied coordinates are OK. */ if ( ( a[ 0 ] != AST__BAD ) && ( a[ 1 ] != AST__BAD ) && ( b[ 0 ] != AST__BAD ) && ( b[ 1 ] != AST__BAD ) && ( c[ 0 ] != AST__BAD ) && ( c[ 1 ] != AST__BAD ) ) { /* Apply the axis permutation array to obtain the coordinates of the three points in the required (longitude,latitude) order. */ aa[ perm[ 0 ] ] = a[ 0 ]; aa[ perm[ 1 ] ] = a[ 1 ]; bb[ perm[ 0 ] ] = b[ 0 ]; bb[ perm[ 1 ] ] = b[ 1 ]; cc[ perm[ 0 ] ] = c[ 0 ]; cc[ perm[ 1 ] ] = c[ 1 ]; /* Check that A and B are not co-incident. */ if( aa[ 0 ] != bb[ 0 ] || aa[ 1 ] != bb[ 1 ] ) { /* Check that C and B are not co-incident. */ if( cc[ 0 ] != bb[ 0 ] || cc[ 1 ] != bb[ 1 ] ) { /* Find the angle from north to the line BA. */ anga = palDbear( bb[ 0 ], bb[ 1 ], aa[ 0 ], aa[ 1 ] ); /* Find the angle from north to the line BC. */ angc = palDbear( bb[ 0 ], bb[ 1 ], cc[ 0 ], cc[ 1 ] ); /* Find the difference. */ result = angc - anga; /* This value is the angle from north, but we want the angle from axis 2. If the axes have been swapped so that axis 2 is actually the longitude axis, then we need to correct this result. */ if( perm[ 0 ] != 0 ) result = piby2 - result; /* Fold the result into the range +/- PI. */ result = palDrange( result ); } } } } /* Return the result. */ return result; } static double CalcLAST( AstSkyFrame *this, double epoch, double obslon, double obslat, double obsalt, double dut1, int *status ) { /* * Name: * CalcLAST * Purpose: * Calculate the Local Appearent Sidereal Time for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double CalcLAST( AstSkyFrame *this, double epoch, double obslon, * double obslat, double obsalt, double dut1, * int *status ) * Class Membership: * SkyFrame member function. * Description: * This function calculates and returns the Local Apparent Sidereal Time * at the given epoch, etc. * Parameters: * this * Pointer to the SkyFrame. * epoch * The epoch (MJD). * obslon * Observatory geodetic longitude (radians) * obslat * Observatory geodetic latitude (radians) * obsalt * Observatory geodetic altitude (metres) * dut1 * The UT1-UTC correction, in seconds. * status * Pointer to the inherited status variable. * Returned Value: * The Local Apparent Sidereal Time, in radians. * Notes: * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFrameSet *fs; /* Mapping from TDB offset to LAST offset */ double epoch0; /* Supplied epoch value */ double result; /* Returned LAST value */ /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* See if the required LAST value can be determined from the cached LAST values in the SkyFrame virtual function table. */ result = GetCachedLAST( this, epoch, obslon, obslat, obsalt, dut1, status ); /* If not, we do an exact calculation from scratch. */ if( result == AST__BAD ) { /* If not yet done, create two TimeFrames. Note, this is done here rather than in astInitSkyFrameVtab in order to avoid infinite vtab initialisation loops (caused by the TimeFrame class containing a static SkyFrame). */ if( ! tdbframe ) { astBeginPM; tdbframe = astTimeFrame( "system=mjd,timescale=tdb", status ); lastframe = astTimeFrame( "system=mjd,timescale=last", status ); astEndPM; } /* For better accuracy, use this integer part of the epoch as the origin of the two TimeFrames. */ astSetTimeOrigin( tdbframe, (int) epoch ); astSetTimeOrigin( lastframe, (int) epoch ); /* Convert the absolute Epoch value to an offset from the above origin. */ epoch0 = epoch; epoch -= (int) epoch; /* Store the observers position in the two TimeFrames. */ astSetObsLon( tdbframe, obslon ); astSetObsLon( lastframe, obslon ); astSetObsLat( tdbframe, obslat ); astSetObsLat( lastframe, obslat ); astSetObsAlt( tdbframe, obsalt ); astSetObsAlt( lastframe, obsalt ); /* Store the DUT1 value. */ astSetDut1( tdbframe, dut1 ); astSetDut1( lastframe, dut1 ); /* Get the conversion from tdb mjd offset to last mjd offset. */ fs = astConvert( tdbframe, lastframe, "" ); /* Use it to transform the SkyFrame Epoch from TDB offset to LAST offset. */ astTran1( fs, 1, &epoch, 1, &epoch ); fs = astAnnul( fs ); /* Convert the LAST offset from days to radians. */ result = ( epoch - (int) epoch )*2*AST__DPI; /* Cache the new LAST value in the SkyFrame virtual function table. */ SetCachedLAST( this, result, epoch0, obslon, obslat, obsalt, dut1, status ); } /* Return the required LAST value. */ return result; } static void ClearAsTime( AstSkyFrame *this, int axis, int *status ) { /* * Name: * ClearAsTime * Purpose: * Clear the value of the AsTime attribute for a SkyFrame's axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearAsTime( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function clears any value that has been set for the AsTime * attribute for a specified axis of a SkyFrame. This attribute indicates * whether axis values should be formatted as times (as opposed to angles) * by default. * Parameters: * this * Pointer to the SkyFrame. * axis * Index of the axis for which the value is to be cleared (zero based). * status * Pointer to the inherited status variable. * Returned Value: * void. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astClearAsTime" ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis ); /* If the Axis is a SkyAxis, clear the AsTime attribute (if it is not a SkyAxis, it will not have this attribute anyway). */ if ( astIsASkyAxis( ax ) ) astClearAxisAsTime( ax ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearAttrib protected * method inherited from the Frame class). * Description: * This function clears the value of a specified attribute for a * SkyFrame, so that the default value will subsequently be used. * Parameters: * this * Pointer to the SkyFrame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ int axis; /* SkyFrame axis number */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* AsTime(axis). */ /* ------------- */ if ( nc = 0, ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearAsTime( this, axis - 1 ); /* Equinox. */ /* -------- */ } else if ( !strcmp( attrib, "equinox" ) ) { astClearEquinox( this ); /* NegLon. */ /* ------- */ } else if ( !strcmp( attrib, "neglon" ) ) { astClearNegLon( this ); /* Projection. */ /* ----------- */ } else if ( !strcmp( attrib, "projection" ) ) { astClearProjection( this ); /* SkyRef. */ /* ------- */ } else if ( !strcmp( attrib, "skyref" ) ) { astClearSkyRef( this, 0 ); astClearSkyRef( this, 1 ); /* SkyRef(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearSkyRef( this, axis - 1 ); /* SkyRefP. */ /* -------- */ } else if ( !strcmp( attrib, "skyrefp" ) ) { astClearSkyRefP( this, 0 ); astClearSkyRefP( this, 1 ); /* SkyRefP(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearSkyRefP( this, axis - 1 ); /* SkyRefIs. */ /* --------- */ } else if ( !strcmp( attrib, "skyrefis" ) ) { astClearSkyRefIs( this ); /* AlignOffset. */ /* ------------ */ } else if ( !strcmp( attrib, "alignoffset" ) ) { astClearAlignOffset( this ); /* If the name was not recognised, test if it matches any of the read-only attributes of this class. If it does, then report an error. */ } else if ( !strncmp( attrib, "islataxis", 9 ) || !strncmp( attrib, "islonaxis", 9 ) || !strcmp( attrib, "lataxis" ) || !strcmp( attrib, "lonaxis" ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static void ClearDut1( AstFrame *this, int *status ) { /* * Name: * ClearDut1 * Purpose: * Clear the value of the Dut1 attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearDut1( AstFrame *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearDut1 method * inherited from the Frame class). * Description: * This function clears the Dut1 value and updates the LAST value * stored in the SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original value */ orig = astGetDut1( this ); /* Invoke the parent method to clear the Frame Dut1 */ (*parent_cleardut1)( this, status ); /* If the DUT1 value has changed significantly, indicate that the LAST value will need to be re-calculated when it is next needed. */ if( fabs( orig - astGetDut1( this ) ) > 1.0E-6 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; } } static void ClearObsAlt( AstFrame *this, int *status ) { /* * Name: * ClearObsAlt * Purpose: * Clear the value of the ObsAlt attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearObsAlt( AstFrame *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearObsAlt method * inherited from the Frame class). * Description: * This function clears the ObsAlt value. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original value */ orig = astGetObsAlt( this ); /* Invoke the parent method to clear the Frame ObsAlt. */ (*parent_clearobsalt)( this, status ); /* If the altitude has changed significantly, indicate that the LAST value and magnitude of the diurnal aberration vector will need to be re-calculated when next needed. */ if( fabs( orig - astGetObsAlt( this ) ) > 0.001 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; ( (AstSkyFrame *) this )->diurab = AST__BAD; } } static void ClearObsLat( AstFrame *this, int *status ) { /* * Name: * ClearObsLat * Purpose: * Clear the value of the ObsLat attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearObsLat( AstFrame *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearObsLat method * inherited from the Frame class). * Description: * This function clears the ObsLat value. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original value */ orig = astGetObsLat( this ); /* Invoke the parent method to clear the Frame ObsLat. */ (*parent_clearobslat)( this, status ); /* If the altitude has changed significantly, indicate that the LAST value and magnitude of the diurnal aberration vector will need to be re-calculated when next needed. */ if( fabs( orig - astGetObsLat( this ) ) > 1.0E-8 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; ( (AstSkyFrame *) this )->diurab = AST__BAD; } } static void ClearObsLon( AstFrame *this, int *status ) { /* * Name: * ClearObsLon * Purpose: * Clear the value of the ObsLon attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearObsLon( AstFrame *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearObsLon method * inherited from the Frame class). * Description: * This function clears the ObsLon value. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original value */ orig = astGetObsLon( this ); /* Invoke the parent method to clear the Frame ObsLon. */ (*parent_clearobslon)( this, status ); /* If the longitude has changed significantly, indicate that the LAST value will need to be re-calculated when it is next needed. */ if( fabs( orig - astGetObsLon( this ) ) > 1.0E-8 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; } } static void ClearSystem( AstFrame *this_frame, int *status ) { /* * Name: * ClearSystem * Purpose: * Clear the System attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void ClearSystem( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astClearSystem protected * method inherited from the Frame class). * Description: * This function clears the System attribute for a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrameSet *fs; /* FrameSet to be used as the Mapping */ AstSkyFrame *sfrm; /* Copy of original SkyFrame */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ double xin[ 2 ]; /* Axis 0 values */ double yin[ 2 ]; /* Axis 1 values */ double xout[ 2 ]; /* Axis 0 values */ double yout[ 2 ]; /* Axis 1 values */ int skyref_set; /* Is either SkyRef attribute set? */ int skyrefp_set; /* Is either SkyRefP attribute set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* See if either the SkyRef or SkyRefP attribute is set. */ skyref_set = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ); skyrefp_set = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 ); /* If so, we will need to transform their values into the new coordinate system. Save a copy of the SkyFrame with its original System value. */ sfrm = ( skyref_set || skyrefp_set )?astCopy( this ):NULL; /* Use the parent method to clear the System value. */ (*parent_clearsystem)( this_frame, status ); /* Now modify the SkyRef and SkyRefP attributes if necessary. */ if( sfrm ) { /* Save the SkyRef and SkyRefP values. */ xin[ 0 ] = astGetSkyRef( sfrm, 0 ); xin[ 1 ] = astGetSkyRefP( sfrm, 0 ); yin[ 0 ] = astGetSkyRef( sfrm, 1 ); yin[ 1 ] = astGetSkyRefP( sfrm, 1 ); /* Clear the SkyRef values to avoid infinite recursion in the following call to astConvert. */ if( skyref_set ) { astClearSkyRef( sfrm, 0 ); astClearSkyRef( sfrm, 1 ); astClearSkyRef( this, 0 ); astClearSkyRef( this, 1 ); } /* Get the Mapping from the original System to the default System. Invoking astConvert will recursively invoke ClearSystem again. This is why we need to be careful to ensure that SkyRef is cleared above - doing so ensure we do not end up with infinite recursion. */ fs = astConvert( sfrm, this, "" ); /* Check the Mapping was found. */ if( fs ) { /* Use the Mapping to find the SkyRef and SkyRefP positions in the default coordinate system. */ astTran2( fs, 2, xin, yin, 1, xout, yout ); /* Store the values as required. */ if( skyref_set ) { astSetSkyRef( this, 0, xout[ 0 ] ); astSetSkyRef( this, 1, yout[ 0 ] ); } if( skyrefp_set ) { astSetSkyRefP( this, 0, xout[ 1 ] ); astSetSkyRefP( this, 1, yout[ 1 ] ); } /* Free resources. */ fs = astAnnul( fs ); /* If the Mapping is not defined, we cannot convert the SkyRef or SkyRefP positions in the new Frame so clear them. */ } else { if( skyref_set ) { astClearSkyRef( this, 0 ); astClearSkyRef( this, 1 ); } if( skyrefp_set ) { astClearSkyRefP( this, 0 ); astClearSkyRefP( this, 1 ); } } /* Free resources. */ sfrm = astAnnul( sfrm ); } } static double Distance( AstFrame *this_frame, const double point1[], const double point2[], int *status ) { /* * Name: * Distance * Purpose: * Calculate the distance between two points. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double Distance( AstFrame *this, * const double point1[], const double point2[], int *status ) * Class Membership: * SkyFrame member function (over-rides the astDistance method * inherited from the Frame class). * Description: * This function finds the distance between two points whose * SkyFrame coordinates are given. The distance calculated is that * along the geodesic curve (i.e. great circle) that joins the two * points. * Parameters: * this * Pointer to the SkyFrame. * point1 * An array of double, with one element for each SkyFrame axis, * containing the coordinates of the first point. * point2 * An array of double, with one element for each SkyFrame axis, * containing the coordinates of the second point. * status * Pointer to the inherited status variable. * Returned Value: * The distance between the two points, in radians. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input coordinates has this value. * - A "bad" value will also be returned if this function is * invoked with the AST error status set or if it should fail for * any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ const int *perm; /* Axis permutation array */ double p1[ 2 ]; /* Permuted point1 coordinates */ double p2[ 2 ]; /* Permuted point2 coordinates */ double result; /* Value to return */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Check that all supplied coordinates are OK. */ if ( ( point1[ 0 ] != AST__BAD ) && ( point1[ 1 ] != AST__BAD ) && ( point2[ 0 ] != AST__BAD ) && ( point2[ 1 ] != AST__BAD ) ) { /* Apply the axis permutation array to obtain the coordinates of the two points in the required (longitude,latitude) order. */ p1[ perm[ 0 ] ] = point1[ 0 ]; p1[ perm[ 1 ] ] = point1[ 1 ]; p2[ perm[ 0 ] ] = point2[ 0 ]; p2[ perm[ 1 ] ] = point2[ 1 ]; /* Calculate the great circle distance between the points in radians. */ result = palDsep( p1[ 0 ], p1[ 1 ], p2[ 0 ], p2[ 1 ] ); } } /* Return the result. */ return result; } static const char *Format( AstFrame *this_frame, int axis, double value, int *status ) { /* * Name: * Format * Purpose: * Format a coordinate value for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *Format( AstFrame *this, int axis, double value, int *status ) * Class Membership: * SkyFrame member function (over-rides the astFormat method inherited * from the Frame class). * Description: * This function returns a pointer to a string containing the formatted * (character) version of a coordinate value for a SkyFrame axis. The * formatting applied is that specified by a previous invocation of the * astSetFormat method. A suitable default format is applied if necessary, * and this may depend on which sky coordinate system the SkyFrame * describes. * Parameters: * this * Pointer to the SkyFrame. * axis * The number of the axis (zero-based) for which formatting is to be * performed. * value * The coordinate value to be formatted, in radians. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a null-terminated string containing the formatted value. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const char *result; /* Pointer value to return */ int format_set; /* Format attribute set? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astFormat" ); /* Determine if a Format value has been set for the axis and set a temporary value if it has not. Use the GetFormat member function for this class together with member functions inherited from the parent class (rather than using the object's methods directly) because if any of these methods have been over-ridden by a derived class the Format string syntax may no longer be compatible with this class. */ format_set = (*parent_testformat)( this_frame, axis, status ); if ( !format_set ) { (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status ); } /* Use the Format member function inherited from the parent class to format the value and return a pointer to the resulting string. */ result = (*parent_format)( this_frame, axis, value, status ); /* If necessary, clear any temporary Format value that was set above. */ if ( !format_set ) (*parent_clearformat)( this_frame, axis, status ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static AstPointSet *FrameGrid( AstFrame *this_object, int size, const double *lbnd, const double *ubnd, int *status ){ /* * Name: * FrameGrid * Purpose: * Return a grid of points covering a rectangular area of a Frame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * AstPointSet *FrameGrid( AstFrame *this_frame, int size, * const double *lbnd, const double *ubnd, * int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astFrameGrid * method inherited from the Frame class). * Description: * This function returns a PointSet containing positions spread * approximately evenly throughtout a specified rectangular area of * the Frame. * Parameters: * this * Pointer to the Frame. * size * The preferred number of points in the returned PointSet. The * actual number of points in the returned PointSet may be * different, but an attempt is made to stick reasonably closely to * the supplied value. * lbnd * Pointer to an array holding the lower bound of the rectangular * area on each Frame axis. The array should have one element for * each Frame axis. * ubnd * Pointer to an array holding the upper bound of the rectangular * area on each Frame axis. The array should have one element for * each Frame axis. * Returned Value: * A pointer to a new PointSet holding the grid of points. * Notes: * - A NULL pointer is returned if an error occurs. */ /* Local Variables: */ AstPointSet *result; AstSkyFrame *this; double **ptr; double box_area; double cl; double dlon; double hilat; double hilon; double inclon; double lat_size; double lat; double lon; double lolon; double lon_size; double lolat; double totlen; int ilat; int ilon; int imer; int ip; int ipar; int ipmax; int nmer; int npar; /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Get the zero-based indices of the longitude and latitude axes. */ ilon = astGetLonAxis( this ); ilat = 1 - ilon; /* The latitude bounds may not be the right way round so check for it. */ if( lbnd[ ilat ] <= ubnd[ ilat ] ) { lolat = lbnd[ ilat ]; hilat = ubnd[ ilat ]; } else { lolat = ubnd[ ilat ]; hilat = lbnd[ ilat ]; } /* Check all bounds are good. Also check the size is positive. */ lolon = lbnd[ ilon ]; hilon = ubnd[ ilon ]; if( size > 0 && lolat != AST__BAD && hilat != AST__BAD && lolon != AST__BAD && hilon != AST__BAD ) { /* Ensure the longitude bounds are in the range 0-2PI. */ lolon = palDranrm( lolon ); hilon = palDranrm( hilon ); /* If the upper longitude limit is less than the lower limit, add 2.PI */ if( hilon <= lolon && ubnd[ ilon ] != lbnd[ ilon ] ) hilon += 2*AST__DPI; /* Get the total area of the box in steradians. */ dlon = hilon - lolon; box_area = fabs( dlon*( sin( hilat ) - sin( lolat ) ) ); /* Get the nominal size of a square grid cell, in radians. */ lat_size = sqrt( box_area/size ); /* How many parallels should we use to cover the box? Ensure we use at least two. These parallels pass through the centre of the grid cells. */ npar = (int)( 0.5 + ( hilat - lolat )/lat_size ); if( npar < 2 ) npar = 2; /* Find the actual sample size implied by this number of parallels. */ lat_size = ( hilat - lolat )/npar; /* Find the total arc length of the parallels. */ totlen = 0.0; lat = lolat + 0.5*lat_size; for( ipar = 0; ipar < npar; ipar++ ) { totlen += dlon*cos( lat ); lat += lat_size; } /* If we space "size" samples evenly over this total arc-length, what is the arc-distance between samples? */ lon_size = totlen/size; /* Create a PointSet in which to store the grid. Make it bigger than necessary in order to leave room for extra samples caused by integer truncation. */ ipmax = 2*size; result = astPointSet( ipmax, 2, " ", status ); ptr = astGetPoints( result ); if( astOK ) { /* Loop over all the parallels. */ ip = 0; lat = lolat + 0.5*lat_size; for( ipar = 0; ipar < npar; ipar++ ) { /* Get the longitude increment between samples on this parallel. */ cl = cos( lat ); inclon = ( cl != 0.0 ) ? lon_size/cl : 0.0; /* Get the number of longitude samples for this parallel. Reduce it if it would extend beyond the end of the PointSet. */ nmer = dlon/inclon; if( ip + nmer >= ipmax ) nmer = ipmax - ip; /* Adjust the longitude increment to take up any slack caused by the above integer division. */ inclon = dlon/nmer; /* Produce the samples for the current parallel. */ lon = lolon + 0.5*inclon; for( imer = 0; imer < nmer; imer++ ) { ptr[ ilon ][ ip ] = lon; ptr[ ilat ][ ip ] = lat; lon += inclon; ip++; } /* Get the latitude on the next parallel. */ lat += lat_size; } /* Truncate the PointSet to exclude unused elements at the end. */ astSetNpoint( result, ip ); } /* Report error if supplied values were bad. */ } else if( astOK ) { if( size < 1 ) { astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid " "size (%d) is invalid (programming error).", status, astGetClass( this ), size ); } else { astError( AST__ATTIN, "astFrameGrid(%s): One of more of the " "supplied bounds is AST__BAD (programming error).", status, astGetClass( this ) ); } } /* Annul the returned PointSet if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the PointSet holding the grid. */ return result; } static double Gap( AstFrame *this_frame, int axis, double gap, int *ntick, int *status ) { /* * Name: * Gap * Purpose: * Find a "nice" gap for tabulating SkyFrame axis values. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astGap method * inherited from the Frame class). * Description: * This function returns a gap size which produces a nicely spaced * series of formatted values for a SkyFrame axis, the returned gap * size being as close as possible to the supplied target gap * size. It also returns a convenient number of divisions into * which the gap can be divided. * Parameters: * this * Pointer to the SkyFrame. * axis * The number of the axis (zero-based) for which a gap is to be found. * gap * The target gap size. * ntick * Address of an int in which to return a convenient number of * divisions into which the gap can be divided. * status * Pointer to the inherited status variable. * Returned Value: * The nice gap size. * Notes: * - A value of zero is returned if the target gap size is zero. * - A negative gap size is returned if the supplied gap size is negative. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ double result; /* Gap value to return */ int format_set; /* Format attribute set? */ /* Check the global error status. */ if ( !astOK ) return 0.0; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astGap" ); /* Determine if a Format value has been set for the axis and set a temporary value if it has not. Use the GetFormat member function for this class together with member functions inherited from the parent class (rather than using the object's methods directly) because if any of these methods have been over-ridden by a derived class the Format string syntax may no longer be compatible with this class. */ format_set = (*parent_testformat)( this_frame, axis, status ); if ( !format_set ) { (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status ); } /* Use the Gap member function inherited from the parent class to find the gap size. */ result = (*parent_gap)( this_frame, axis, gap, ntick, status ); /* If necessary, clear any temporary Format value that was set above. */ if ( !format_set ) (*parent_clearformat)( this_frame, axis, status ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = 0.0; /* Return the result. */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied SkyFrame, * in bytes. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astTSizeOf( this->projection ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetActiveUnit( AstFrame *this_frame, int *status ) { /* * Name: * GetActiveUnit * Purpose: * Obtain the value of the ActiveUnit flag for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetActiveUnit( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetActiveUnit protected * method inherited from the Frame class). * Description: * This function returns the value of the ActiveUnit flag for a * SkyFrame, which is always 0. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The value to use for the ActiveUnit flag (0). */ return 0; } static int GetAsTime( AstSkyFrame *this, int axis, int *status ) { /* * Name: * GetAsTime * Purpose: * Obtain the value of the AsTime attribute for a SkyFrame's axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetAsTime( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns the boolean value of the AsTime attribute for a * specified axis of a SkyFrame. This value indicates whether axis values * should be formatted as times (as opposed to angles) by default. * Parameters: * this * Pointer to the SkyFrame. * axis * Index of the axis for which information is required (zero based). * status * Pointer to the inherited status variable. * Returned Value: * Zero or one, according to the setting of the AsTime attribute (if no * value has previously been set, a suitable default is returned). * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ int axis_p; /* Permuted axis index */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ result = 0; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetAsTime" ); /* Obtain a pointer to the required Axis object. */ ax = astGetAxis( this, axis ); /* Determine if the AsTime attribute has been set for the axis (this can only be the case if the object is a SkyAxis). If the attribute is set, obtain its value. */ if ( astIsASkyAxis( ax ) && astTestAxisAsTime( ax ) ) { result = astGetAxisAsTime( ax ); /* Otherwise, check which (permuted) axis is involved. Only the first (longitude) axis may be displayed as a time by default. */ } else if ( axis_p == 0 ) { /* Test for those coordinate systems which normally have their longitude axes displayed as times (basically, those that involve the Earth's equator) and set the returned value appropriately. */ result = IsEquatorial( astGetSystem( this ), status ); } /* Annul the Axis object pointer. */ ax = astAnnul( ax ); /* Return the result. */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astGetAttrib * method inherited from the Frame class). * Description: * This function returns a pointer to the value of a specified * attribute for a SkyFrame, formatted as a character string. * Parameters: * this * Pointer to the SkyFrame. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - The returned string pointer may point at memory allocated * within the SkyFrame, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the SkyFrame. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const char *cval; /* Pointer to character attribute value */ const char *result; /* Pointer value to return */ double dval; /* Floating point attribute value */ double equinox; /* Equinox attribute value (as MJD) */ int as_time; /* AsTime attribute value */ int axis; /* SkyFrame axis number */ int ival; /* Integer attribute value */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ int neglon; /* Display long. values as [-pi,pi]? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* AsTime(axis). */ /* ------------- */ if ( nc = 0, ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { as_time = astGetAsTime( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", as_time ); result = getattrib_buff; } /* Equinox. */ /* -------- */ } else if ( !strcmp( attrib, "equinox" ) ) { equinox = astGetEquinox( this ); if ( astOK ) { /* Format the Equinox as decimal years. Use a Besselian epoch if it will be less than 1984.0, otherwise use a Julian epoch. */ result = astFmtDecimalYr( ( equinox < palEpj2d( 1984.0 ) ) ? palEpb( equinox ) : palEpj( equinox ), DBL_DIG ); } /* IsLatAxis(axis) */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "islataxis(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = astGetIsLatAxis( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* IsLonAxis(axis) */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "islonaxis(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = astGetIsLonAxis( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LatAxis */ /* -------- */ } else if ( !strcmp( attrib, "lataxis" ) ) { axis = astGetLatAxis( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", axis + 1 ); result = getattrib_buff; } /* LonAxis */ /* -------- */ } else if ( !strcmp( attrib, "lonaxis" ) ) { axis = astGetLonAxis( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", axis + 1 ); result = getattrib_buff; } /* NegLon */ /* ------ */ } else if ( !strcmp( attrib, "neglon" ) ) { neglon = astGetNegLon( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", neglon ); result = getattrib_buff; } /* Projection. */ /* ----------- */ } else if ( !strcmp( attrib, "projection" ) ) { result = astGetProjection( this ); /* SkyRef. */ /* ------- */ } else if ( !strcmp( attrib, "skyref" ) ) { cval = astFormat( this, 0, astGetSkyRef( this, 0 ) ); if ( astOK ) { nc = sprintf( getattrib_buff, "%s, ", cval ); cval = astFormat( this, 1, astGetSkyRef( this, 1 ) ); if ( astOK ) { (void) sprintf( getattrib_buff + nc, "%s", cval ); result = getattrib_buff; } } /* SkyRef(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetSkyRef( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* SkyRefP. */ /* -------- */ } else if ( !strcmp( attrib, "skyrefp" ) ) { cval = astFormat( this, 0, astGetSkyRefP( this, 0 ) ); if ( astOK ) { nc = sprintf( getattrib_buff, "%s, ", cval ); cval = astFormat( this, 1, astGetSkyRefP( this, 1 ) ); if ( astOK ) { (void) sprintf( getattrib_buff + nc, "%s", cval ); result = getattrib_buff; } } /* SkyRefP(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetSkyRefP( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* SkyRefIs. */ /* --------- */ } else if ( !strcmp( attrib, "skyrefis" ) ) { ival = astGetSkyRefIs( this ); if ( astOK ) { if( ival == AST__POLE_REF ){ result = POLE_STRING; } else if( ival == AST__IGNORED_REF ){ result = IGNORED_STRING; } else { result = ORIGIN_STRING; } } /* AlignOffset */ /* ----------- */ } else if ( !strcmp( attrib, "alignoffset" ) ) { ival = astGetAlignOffset( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static int GetDirection( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetDirection * Purpose: * Obtain the value of the Direction attribute for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetDirection( AstFrame *this_frame, int axis, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetDirection method inherited * from the Frame class). * Description: * This function returns the value of the Direction attribute for a * specified axis of a SkyFrame. A suitable default value is returned if no * Direction value has previously been set. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Zero or one, depending on the Direction attribute value. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ int axis_p; /* Permuted axis index */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ result = 0; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetDirection" ); /* Check if a value has been set for the axis Direction attribute. If so, obtain its value. */ if ( astTestDirection( this, axis ) ) { result = (*parent_getdirection)( this_frame, axis, status ); /* Otherwise, we will generate a default Direction value. Currently all systems supported by SkyFrame are left handed, so all longitude axes are reversed and all latitude axes are not reversed. */ } else if( axis_p == 0 ) { result = 0; } else { result = 1; } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static double GetBottom( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetBottom * Purpose: * Obtain the value of the Bottom attribute for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetBottom( AstFrame *this_frame, int axis, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetBottom method inherited * from the Frame class). * Description: * This function returns the value of the Bottom attribute for a * specified axis of a SkyFrame. A suitable default value is returned if no * value has previously been set. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * The Bottom value to use. * Notes: * - A value of -DBL_MAX will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ int axis_p; /* Permuted axis index */ double result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return -DBL_MAX; /* Initialise. */ result = -DBL_MAX; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetBottom" ); /* Check if a value has been set for the axis Bottom attribute. If so, obtain its value. */ if ( astTestBottom( this, axis ) ) { result = (*parent_getbottom)( this_frame, axis, status ); /* Otherwise, we will return a default Bottom value appropriate to the SkyFrame class. */ } else { /* If it is a latitude axis return -pi/2. */ if( axis_p == 1 ) { result = -piby2; /* If it is a longitude value return -DBL_MAX (i.e. no lower limit). */ } else { result = -DBL_MAX; } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = -DBL_MAX; /* Return the result. */ return result; } static double GetCachedLAST( AstSkyFrame *this, double epoch, double obslon, double obslat, double obsalt, double dut1, int *status ) { /* * Name: * GetCachedLAST * Purpose: * Attempt to get a LAST value from the cache in the SkyFrame vtab. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetCachedLAST( AstSkyFrame *this, double epoch, double obslon, * double obslat, double obsalt, double dut1, * int *status ) * Class Membership: * SkyFrame member function. * Description: * This function searches the static cache of LAST values held in the * SkyFrame virtual function table for a value that corresponds to the * supplied parameter values. If one is found, it is returned. * Otherwise AST__BAD is found. * Parameters: * this * Pointer to the SkyFrame. * epoch * The epoch (MJD). * obslon * Observatory geodetic longitude (radians) * obslat * Observatory geodetic latitude (radians) * obsalt * Observatory geodetic altitude (metres) * dut1 * The UT1-UTC correction, in seconds. * status * Pointer to the inherited status variable. * Returned Value: * The Local Apparent Sidereal Time, in radians. * Notes: * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS AstSkyLastTable *table; double *ep; double *lp; double dep; double result; int ihi; int ilo; int itable; int itest; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Wait until the table is not being written to by any thread. This also prevents a thread from writing to the table whilst we are reading it. */ LOCK_RLOCK1 /* Loop round every LAST table held in the vtab. Each table refers to a different observatory position and/or DUT1 value. */ for( itable = 0; itable < nlast_tables; itable++ ) { table = last_tables[ itable ]; /* See if the table refers to the given position and dut1 value, allowing some small tolerance. */ if( fabs( table->obslat - obslat ) < 2.0E-7 && fabs( table->obslon - obslon ) < 2.0E-7 && fabs( table->obsalt - obsalt ) < 1.0 && fabs( table->dut1 - dut1 ) < 1.0E-5 ) { /* Get pointers to the array of epoch and corresponding LAST values in the table. */ ep = table->epoch; lp = table->last; /* The values in the epoch array are monotonic increasing. Do a binary chop within the table's epoch array to find the earliest entry that has a value equal to or greater than the supplied epoch value. */ ilo = 0; ihi = table->nentry - 1; while( ihi > ilo ) { itest = ( ilo + ihi )/2; if( ep[ itest ] >= epoch ) { ihi = itest; } else { ilo = itest + 1; } } /* Get the difference between the epoch at the entry selected above and the requested epoch. */ dep = ep[ ilo ] - epoch; /* If the entry selected above is the first entry in the table, it can only be used if it is within 0.001 second of the requested epoch. */ if( ilo == 0 ) { if( fabs( dep ) < 0.001/86400.0 ) { result = lp[ 0 ]; } /* If the list of epoch values contained no value that was greater than the supplied epoch value, then we can use the last entry if it is no more than 0.001 second away from the requested epoch. */ } else if( dep <= 0.0 ) { if( fabs( dep ) < 0.001/86400.0 ) { result = lp[ ilo ]; } /* Otherwise, see if the entry selected above is sufficiently close to its lower neighbour (i.e. closer than 0.4 days) to allow a reasonably accurate LAST value to be determined by interpolation. */ } else if( ep[ ilo ] - ep[ ilo - 1 ] < 0.4 ) { ep += ilo - 1; lp += ilo - 1; result = *lp + ( epoch - *ep )*( lp[ 1 ] - *lp )/( ep[ 1 ] - *ep ); /* If the neighbouring point is too far away for interpolation to be reliable, then we can only use the point if it is within 0.001 seconds of the requested epoch. */ } else if( fabs( dep ) < 0.001/86400.0 ) { result = lp[ ilo ]; } /* If we have found the right table, we do not need to look at any other tables, so leave the table loop. */ break; } } /* Indicate that threads may now write to the table. */ UNLOCK_RWLOCK1 /* Ensure the returned value is within the range 0 - 2.PI. */ if( result != AST__BAD ) { while( result > 2*AST__DPI ) result -= 2*AST__DPI; while( result < 0.0 ) result += 2*AST__DPI; } /* Return the required LAST value. */ return result; } static double GetEpoch( AstFrame *this_frame, int *status ) { /* * Name: * GetEpoch * Purpose: * Obtain the value of the Epoch attribute for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetEpoch( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetEpoch method inherited * from the Frame class). * Description: * This function returns the value of the Epoch attribute for a * SkyFrame. A suitable default value is returned if no value has * previously been set. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The Epoch value to use. * Notes: * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ AstSystemType system; /* System attribute */ double result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Initialise. */ result = AST__BAD; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Check if a value has been set for the Epoch attribute. If so, obtain its value. */ if ( astTestEpoch( this ) ) { result = (*parent_getepoch)( this_frame, status ); /* Otherwise, we will return a default Epoch value appropriate to the SkyFrame class. */ } else { /* Provide a default value of B1950.0 or J2000.0 depending on the System setting. */ system = astGetSystem( this ); if( system == AST__FK4 || system == AST__FK4_NO_E ) { result = palEpb2d( 1950.0 ); } else { result = palEpj2d( 2000.0 ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static double GetTop( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetTop * Purpose: * Obtain the value of the Top attribute for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetTop( AstFrame *this_frame, int axis, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetTop method inherited * from the Frame class). * Description: * This function returns the value of the Top attribute for a * specified axis of a SkyFrame. A suitable default value is returned if no * value has previously been set. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * The Top value to use. * Notes: * - A value of DBL_MAX will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ int axis_p; /* Permuted axis index */ double result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return DBL_MAX; /* Initialise. */ result = DBL_MAX; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetTop" ); /* Check if a value has been set for the axis Top attribute. If so, obtain its value. */ if ( astTestTop( this, axis ) ) { result = (*parent_gettop)( this_frame, axis, status ); /* Otherwise, we will return a default Top value appropriate to the SkyFrame class. */ } else { /* If this is a latitude axis return pi/2. */ if( axis_p == 1 ) { result = piby2; /* If it is a longitude value return DBL_MAX (i.e. no upper limit). */ } else { result = DBL_MAX; } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = DBL_MAX; /* Return the result. */ return result; } static const char *GetDomain( AstFrame *this_frame, int *status ) { /* * Name: * GetDomain * Purpose: * Obtain a pointer to the Domain attribute string for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetDomain( AstFrame *this, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetDomain protected * method inherited from the Frame class). * Description: * This function returns a pointer to the Domain attribute string * for a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a constant null-terminated string containing the * Domain value. * Notes: * - The returned pointer or the string it refers to may become * invalid following further invocation of this function or * modification of the SkyFrame. * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* If a Domain attribute string has been set, invoke the parent method to obtain a pointer to it. */ if ( astTestDomain( this ) ) { result = (*parent_getdomain)( this_frame, status ); /* Otherwise, provide a pointer to a suitable default string. */ } else { result = "SKY"; } /* Return the result. */ return result; } static const char *GetFormat( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetFormat * Purpose: * Access the Format string for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetFormat( AstFrame *this, int axis ) * Class Membership: * SkyFrame member function (over-rides the astGetFormat method inherited * from the Frame class). * Description: * This function returns a pointer to the Format string for a specified axis * of a SkyFrame. A pointer to a suitable default string is returned if no * Format value has previously been set. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * Returned Value: * Pointer to a null-terminated character string containing the requested * information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstAxis *ax; /* Pointer to Axis object */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const char *result; /* Pointer value to return */ int as_time; /* Value of AsTime attribute */ int as_time_set; /* AsTime attribute set? */ int axis_p; /* Permuted axis index */ int digits; /* Number of digits of precision */ int is_latitude; /* Value of IsLatitude attribute */ int is_latitude_set; /* IsLatitude attribute set? */ int parent; /* Use parent method? */ int skyaxis; /* Is the Axis a SkyAxis? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_frame); /* Initialise. */ result = NULL; as_time_set = 0; is_latitude = 0; is_latitude_set = 0; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetFormat" ); /* Obtain a pointer to the Axis structure. */ ax = astGetAxis( this, axis ); /* Decide whether the parent astGetFormat method is able to provide the format string we require. We must use the parent method if the Axis is not a SkyAxis, because the syntax of the Format string would become unsuitable for use with the Axis astFormat method if it was over-ridden here. We also use the parent method to return a Format pointer if an explicit Format string has already been set. */ skyaxis = astIsASkyAxis( ax ); parent = ( !skyaxis || (*parent_testformat)( this_frame, axis, status ) ); /* If neither of the above conditions apply, we may still be able to use the parent method if the Axis (actually a SkyAxis) is required to behave as a normal RA or DEC axis, as this is the standard behaviour provided by the SkyAxis class. Examine the SkyFrame's System attribute to determine if its axes should behave in this way. */ if ( !parent ) parent = IsEquatorial( astGetSystem( this ), status ); /* If using the parent method and dealing with a SkyAxis, determine the settings of any attributes that may affect the Format string. */ if ( astOK ) { if ( parent ) { if ( skyaxis ) { as_time_set = astTestAsTime( this, axis ); is_latitude_set = astTestAxisIsLatitude( ax ); is_latitude = astGetAxisIsLatitude( ax ); /* If no AsTime value is set for the axis, set a temporary value as determined by the astGetAsTime method, which supplies suitable defaults for the axes of a SkyFrame. */ if ( !as_time_set ) { astSetAsTime( this, axis, astGetAsTime( this, axis ) ); } /* Temporarly over-ride the SkyAxis IsLatitude attribute, regardless of its setting, as the second axis of a SkyFrame is always the latitude axis. */ astSetAxisIsLatitude( ax, axis_p == 1 ); } /* Invoke the parent method to obtain a pointer to the Format string. */ result = (*parent_getformat)( this_frame, axis, status ); /* Now restore the attributes that were temporarily over-ridden above to their previous states. */ if ( skyaxis ) { if ( !as_time_set ) astClearAsTime( this, axis ); if ( !is_latitude_set ) { astClearAxisIsLatitude( ax ); } else { astSetAxisIsLatitude( ax, is_latitude ); } } /* If the parent method is unsuitable, we must construct a new Format string here. This affects only those coordinate systems whose axes do not behave like standard RA/DEC axes (e.g. typically ecliptic, galactic and supergalactic coordinates). For these, we format values as decimal degrees (or decimal hours if the AsTime attribute is set). Obtain the AsTime value. */ } else { as_time = astGetAsTime( this, axis ); /* Determine how many digits of precision to use. This is obtained from the SkyAxis Digits attribute (if set), otherwise from the Digits attribute of the enclosing SkyFrame. */ if ( astTestAxisDigits( ax ) ) { digits = astGetAxisDigits( ax ); } else { digits = astGetDigits( this ); } /* If a time format is required, generate a Format string using decimal hours. */ if ( astOK ) { if ( as_time ) { if ( digits <= 2 ) { result = "h"; } else { (void) sprintf( getformat_buff, "h.%d", digits - 2 ); result = getformat_buff; } /* Otherwise use decimal degrees. */ } else { if ( digits <= 3 ) { result = "d"; } else { (void) sprintf( getformat_buff, "d.%d", digits - 3 ); result = getformat_buff; } } } } } /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static const char *GetLabel( AstFrame *this, int axis, int *status ) { /* * Name: * GetLabel * Purpose: * Access the Label string for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetLabel( AstFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetLabel method inherited * from the Frame class). * Description: * This function returns a pointer to the Label string for a specified axis * of a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated character string containing the * requested information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSystemType system; /* Code identifying type of sky coordinates */ const char *result; /* Pointer to label string */ int axis_p; /* Permuted axis index */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise. */ result = NULL; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetLabel" ); /* Check if a value has been set for the required axis label string. If so, invoke the parent astGetLabel method to obtain a pointer to it. */ if ( astTestLabel( this, axis ) ) { result = (*parent_getlabel)( this, axis, status ); /* Otherwise, identify the sky coordinate system described by the SkyFrame. */ } else { system = astGetSystem( this ); /* If OK, supply a pointer to a suitable default label string. */ if ( astOK ) { /* Equatorial coordinate systems. */ if ( IsEquatorial( system, status ) ) { result = ( axis_p == 0 ) ? "Right ascension" : "Declination"; /* Ecliptic coordinates. */ } else if ( system == AST__ECLIPTIC ) { result = ( axis_p == 0 ) ? "Ecliptic longitude" : "Ecliptic latitude"; /* Helio-ecliptic coordinates. */ } else if ( system == AST__HELIOECLIPTIC ) { result = ( axis_p == 0 ) ? "Helio-ecliptic longitude" : "Helio-ecliptic latitude"; /* AzEl coordinates. */ } else if ( system == AST__AZEL ) { result = ( axis_p == 0 ) ? "Azimuth" : "Elevation"; /* Galactic coordinates. */ } else if ( system == AST__GALACTIC ) { result = ( axis_p == 0 ) ? "Galactic longitude" : "Galactic latitude"; /* Supergalactic coordinates. */ } else if ( system == AST__SUPERGALACTIC ) { result = ( axis_p == 0 ) ? "Supergalactic longitude" : "Supergalactic latitude"; /* Unknown spherical coordinates. */ } else if ( system == AST__UNKNOWN ) { result = ( axis_p == 0 ) ? "Longitude" : "Latitude"; /* Report an error if the coordinate system was not recognised. */ } else { astError( AST__SCSIN, "astGetLabel(%s): Corrupt %s contains " "invalid sky coordinate system identification code " "(%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); } /* If the SkyRef attribute has a set value, append " offset" to the label. */ if( astGetSkyRefIs( this ) != AST__IGNORED_REF && ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) ) ) { sprintf( getlabel_buff, "%s offset", result ); result = getlabel_buff; } } } /* Return the result. */ return result; } static double GetDiurab( AstSkyFrame *this, int *status ) { /* * Name: * GetDiurab * Purpose: * Return the magnitude of the diurnal aberration vector. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetDiurab( AstSkyFrame *this, int *status ) * Class Membership: * SkyFrame member function * Description: * This function returns the magnitude of the diurnal aberration * vector. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The magnitude of the diurnal aberration vector. */ /* Local Variables: */ double uau; double vau; /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* If the magnitude of the diurnal aberration vector has not yet been found, find it now, and cache it in the SkyFrame structure. The cached value will be reset to AST__BAD if the ObsLat attribute value is changed. This code is transliterated from SLA_AOPPA. */ if( this->diurab == AST__BAD ) { palGeoc( astGetObsLat( this ), astGetObsAlt( this ), &uau, &vau ); this->diurab = 2*AST__DPI*uau*SOLSID/C; } /* Return the result, */ return this->diurab; } static double GetLAST( AstSkyFrame *this, int *status ) { /* * Name: * GetLAST * Purpose: * Return the Local Apparent Sidereal Time for the SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetLAST( AstSkyFrame *this, int *status ) * Class Membership: * SkyFrame member function * Description: * This function returns the Local Apparent Sidereal Time (LAST) * at the moment intime given by the Epoch attribute of the SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The LAST value. */ /* Local Variables: */ double dlast; /* Change in LAST */ double epoch; /* Epoch (TDB MJD) */ double last1; /* LAST at end of current interval */ double result; /* Result value to return */ double delta_epoch; /* Change in Epoch */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* The "last" component of the SkyFrame structure holds the accurate LAST at the moment in time given by the "eplast" (a TDB MJD) component of the SkyFrame structure. If the current value of the SkyFrame's Epoch attribute is not much different to "eplast" (within 0.4 of a day), then the returned LAST value is the "last" value plus the difference between Epoch and "eplast", converted from solar to sidereal time, then converted to radians. This approximation seems to be good to less than a tenth of an arcsecond. If this approximation cannot be used, invoke SetLast to recalculate the accurate LAST and update the "eplast" and "last" values. */ if( this->eplast != AST__BAD ) { epoch = astGetEpoch( this ); delta_epoch = epoch - this->eplast; /* Return the current LAST value if the epoch has not changed. */ if( delta_epoch == 0.0 ) { result = this->last; /* If the previous full calculation of LAST was less than 0.4 days ago, use a linear approximation to LAST. */ } else if( fabs( delta_epoch ) < 0.4 ) { /* If we do not know the ratio of sidereal to solar time at the current epoch, calculate it now. This involves a full calculation of LAST at the end of the current linear approximation period. */ if( this->klast == AST__BAD ) { last1 = CalcLAST( this, this->eplast + 0.4, astGetObsLon( this ), astGetObsLat( this ), astGetObsAlt( this ), astGetDut1( this ), status ); /* Ensure the change in LAST is positive so that we get a positive ratio. */ dlast = last1 - this->last; if( dlast < 0.0 ) dlast += 2*AST__DPI; this->klast = 2*AST__DPI*0.4/dlast; } /* Now use the ratio of solar to sidereal time to calculate the linear approximation to LAST. */ result = this->last + 2*AST__DPI*delta_epoch/this->klast; /* If the last accurate calculation of LAST was more than 0.4 days ago, do a full accurate calculation. */ } else { SetLast( this, status ); result = this->last; } /* If we have not yet done an accurate calculation of LAST, do one now. */ } else { SetLast( this, status ); result = this->last; } /* Return the result, */ return result; } static int GetIsLatAxis( AstSkyFrame *this, int axis, int *status ) { /* * Name: * GetIsLatAxis * Purpose: * Test an axis to see if it is a latitude axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetIsLatAxis( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function tests if a SkyFrame axis is a celestial latitude axis. * Parameters: * this * Pointer to the SkyFrame. * axis * Zero based axis index. * status * Pointer to the inherited status variable. * Returned Value: * One if the supplied axis is a celestial latitude axis, and zero * otherwise. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Get the index of the latitude axis and compare to the supplied axis index. */ result = ( axis == astGetLatAxis( this ) ); /* Return the result. */ return astOK ? result : 0; } static int GetIsLonAxis( AstSkyFrame *this, int axis, int *status ) { /* * Name: * GetIsLonAxis * Purpose: * Test an axis to see if it is a longitude axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetIsLonAxis( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function tests if a SkyFrame axis is a celestial longitude axis. * Parameters: * this * Pointer to the SkyFrame. * axis * Zero based axis index. * status * Pointer to the inherited status variable. * Returned Value: * One if the supplied axis is a celestial longitude axis, and zero * otherwise. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Get the index of the longitude axis and compare to the supplied axis index. */ result = ( axis == astGetLonAxis( this ) ); /* Return the result. */ return astOK ? result : 0; } static int GetLatAxis( AstSkyFrame *this, int *status ) { /* * Name: * GetLatAxis * Purpose: * Obtain the index of the latitude axis of a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetLatAxis( AstSkyFrame *this, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns the zero-based index of the latitude axis of * a SkyFrame, taking into account any current axis permutation. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The zero based axis index (0 or 1) of the latitude axis. * Notes: * - A value of one will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ const int *perm; /* Axis permutation array */ /* Check the global error status. */ if ( !astOK ) return 1; /* Initialise. */ result = 1; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Identify the latitude axis. */ if( perm[ 0 ] == 1 ) { result = 0; } else { result = 1; } } /* Return the result. */ return result; } static int GetLonAxis( AstSkyFrame *this, int *status ) { /* * Name: * GetLonAxis * Purpose: * Obtain the index of the longitude axis of a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int GetLonAxis( AstSkyFrame *this, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns the zero-based index of the longitude axis of * a SkyFrame, taking into account any current axis permutation. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The zero based axis index (0 or 1) of the longitude axis. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ const int *perm; /* Axis permutation array */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ result = 0; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Identify the longitude axis. */ if( perm[ 0 ] == 0 ) { result = 0; } else { result = 1; } } /* Return the result. */ return result; } static double GetSkyRefP( AstSkyFrame *this, int axis, int *status ) { /* * Name: * GetSkyRefP * Purpose: * Obtain the value of the SkyRefP attribute for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double GetSkyRefP( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns the value of the SkyRefP attribute for a * SkyFrame axis, providing suitable defaults. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * The SkyRefP value to be used. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ double result; /* Returned value */ int axis_p; /* Permuted axis index */ /* Initialise. */ result = 0.0; /* Check the global error status. */ if ( !astOK ) return result; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetSkyRefP" ); /* Check if a value has been set for the required axis. If so, return it. */ if( this->skyrefp[ axis_p ] != AST__BAD ) { result = this->skyrefp[ axis_p ]; /* Otherwise, return the default value */ } else { /* The default longitude value is always zero. */ if( axis_p == 0 ) { result= 0.0; /* The default latitude value depends on SkyRef. The usual default is the north pole. The exception to this is if the SkyRef attribute identifies either the north or the south pole, in which case the origin is used as the default. Allow some tolerance. */ } else if( fabs( cos( this->skyref[ 1 ] ) ) > 1.0E-10 ) { result = pi/2; } else { result = 0.0; } } /* Return the result. */ return result; } static const char *GetSymbol( AstFrame *this, int axis, int *status ) { /* * Name: * GetSymbol * Purpose: * Obtain a pointer to the Symbol string for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetSymbol( AstFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetSymbol method inherited * from the Frame class). * Description: * This function returns a pointer to the Symbol string for a specified axis * of a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated character string containing the * requested information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSystemType system; /* Code identifying type of sky coordinates */ const char *result; /* Pointer to symbol string */ int axis_p; /* Permuted axis index */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise. */ result = NULL; /* Validate and permute the axis index. */ axis_p = astValidateAxis( this, axis, 1, "astGetSymbol" ); /* Check if a value has been set for the required axis symbol string. If so, invoke the parent astGetSymbol method to obtain a pointer to it. */ if ( astTestSymbol( this, axis ) ) { result = (*parent_getsymbol)( this, axis, status ); /* Otherwise, identify the sky coordinate system described by the SkyFrame. */ } else { system = astGetSystem( this ); /* If OK, supply a pointer to a suitable default Symbol string. */ if ( astOK ) { /* Equatorial coordinate systems. */ if ( IsEquatorial( system, status ) ) { result = ( axis_p == 0 ) ? "RA" : "Dec"; /* Ecliptic coordinates. */ } else if ( system == AST__ECLIPTIC ) { result = ( axis_p == 0 ) ? "Lambda" : "Beta"; /* Helio-ecliptic coordinates. */ } else if ( system == AST__HELIOECLIPTIC ) { result = ( axis_p == 0 ) ? "Lambda" : "Beta"; /* AzEl coordinates. */ } else if ( system == AST__AZEL ) { result = ( axis_p == 0 ) ? "Az" : "El"; /* Galactic coordinates. */ } else if ( system == AST__GALACTIC ) { result = ( axis_p == 0 ) ? "l" : "b"; /* Supergalactic coordinates. */ } else if ( system == AST__SUPERGALACTIC ) { result = ( axis_p == 0 ) ? "SGL" : "SGB"; /* Unknown spherical coordinates. */ } else if ( system == AST__UNKNOWN ) { result = ( axis_p == 0 ) ? "Lon" : "Lat"; /* Report an error if the coordinate system was not recognised. */ } else { astError( AST__SCSIN, "astGetSymbol(%s): Corrupt %s contains " "invalid sky coordinate system identification code " "(%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); } /* If the SkyRef attribute had a set value, prepend "D" (for "delta") to the Symbol. */ if( astGetSkyRefIs( this ) != AST__IGNORED_REF && ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) ) ) { sprintf( getsymbol_buff, "D%s", result ); result = getsymbol_buff; } } } /* Return the result. */ return result; } static AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) { /* * Name: * GetAlignSystem * Purpose: * Obtain the AlignSystem attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetAlignSystem protected * method inherited from the Frame class). * Description: * This function returns the AlignSystem attribute for a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The AlignSystem value. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ AstSystemType result; /* Value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* If a AlignSystem attribute has been set, invoke the parent method to obtain it. */ if ( astTestAlignSystem( this ) ) { result = (*parent_getalignsystem)( this_frame, status ); /* Otherwise, provide a suitable default. */ } else { result = AST__ICRS; } /* Return the result. */ return result; } static AstSystemType GetSystem( AstFrame *this_frame, int *status ) { /* * Name: * GetSystem * Purpose: * Obtain the System attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * AstSystemType GetSystem( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetSystem protected * method inherited from the Frame class). * Description: * This function returns the System attribute for a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The System value. * Notes: * - AST__BADSYSTEM is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ AstSystemType result; /* Value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* If a System attribute has been set, invoke the parent method to obtain it. */ if ( astTestSystem( this ) ) { result = (*parent_getsystem)( this_frame, status ); /* Otherwise, provide a suitable default. */ } else { result = AST__ICRS; } /* Return the result. */ return result; } static const char *GetTitle( AstFrame *this_frame, int *status ) { /* * Name: * GetTitle * Purpose: * Obtain a pointer to the Title string for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetTitle( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astGetTitle method inherited * from the Frame class). * Description: * This function returns a pointer to the Title string for a SkyFrame. * A pointer to a suitable default string is returned if no Title value has * previously been set. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a null-terminated character string containing the requested * information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ AstSystemType system; /* Code identifying type of sky coordinates */ const char *extra; /* Pointer to extra information */ const char *p; /* Character pointer */ const char *projection; /* Pointer to sky projection description */ const char *result; /* Pointer to result string */ const char *word; /* Pointer to critical word */ double epoch; /* Value of Epoch attribute */ double equinox; /* Value of Equinox attribute */ int lextra; /* Length of extra information */ int offset; /* Using offset coordinate system? */ int pos; /* Buffer position to enter text */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_frame); /* Initialise. */ result = NULL; pos = 0; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* See if a Title string has been set. If so, use the parent astGetTitle method to obtain a pointer to it. */ if ( astTestTitle( this ) ) { result = (*parent_gettitle)( this_frame, status ); /* Otherwise, we will generate a default Title string. Obtain the values of the SkyFrame's attributes that determine what this string will be. */ } else { epoch = astGetEpoch( this ); equinox = astGetEquinox( this ); projection = astGetProjection( this ); system = astGetSystem( this ); /* See if an offset coordinate system is being used.*/ offset = ( astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ) ) && ( astGetSkyRefIs( this ) != AST__IGNORED_REF ); /* Use this to determine if the word "coordinates" or "offsets" should be used.*/ word = offset ? "offsets" : "coordinates"; /* Classify the coordinate system type and create an appropriate Title string. (Note that when invoking the astFmtDecimalYr function we must use a separate sprintf on each occasion so as not to over-write its internal buffer before the result string has been used.) */ if ( astOK ) { result = gettitle_buff; switch ( system ) { /* FK4 equatorial coordinates. */ /* --------------------------- */ /* Display the Equinox and Epoch values. */ case AST__FK4: pos = sprintf( gettitle_buff, "FK4 equatorial %s", word ); if( astTestEquinox( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; mean equinox B%s", astFmtDecimalYr( palEpb( equinox ), 9 ) ); } if( astTestEpoch( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; epoch B%s", astFmtDecimalYr( palEpb( epoch ), 9 ) ); } break; /* FK4 coordinates with no E-terms of aberration. */ /* ---------------------------------------------- */ /* Display the Equinox and Epoch values. */ case AST__FK4_NO_E: pos = sprintf( gettitle_buff, "FK4 equatorial %s; no E-terms", word ); if( astTestEquinox( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; mean equinox B%s", astFmtDecimalYr( palEpb( equinox ), 9 ) ); } if( astTestEpoch( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; epoch B%s", astFmtDecimalYr( palEpb( epoch ), 9 ) ); } break; /* FK5 equatorial coordinates. */ /* --------------------------- */ /* Display only the Equinox value. */ case AST__FK5: pos = sprintf( gettitle_buff, "FK5 equatorial %s", word ); if( astTestEquinox( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; mean equinox J%s", astFmtDecimalYr( palEpj( equinox ), 9 ) ); } break; /* J2000 equatorial coordinates. */ /* ----------------------------- */ /* Based on the dynamically determined mean equator and equinox of J2000, rather than on a model such as FK4 or FK5 */ case AST__J2000: pos = sprintf( gettitle_buff, "J2000 equatorial %s", word ); break; /* ICRS coordinates. */ /* ----------------- */ /* ICRS is only like RA/Dec by co-incidence, it is not really an equatorial system by definition. */ case AST__ICRS: pos = sprintf( gettitle_buff, "ICRS %s", word ); break; /* AzEl coordinates. */ /* ----------------- */ case AST__AZEL: pos = sprintf( gettitle_buff, "Horizon (Azimuth/Elevation) %s", word ); break; /* Geocentric apparent equatorial coordinates. */ /* ------------------------------------------ */ /* Display only the Epoch value. */ case AST__GAPPT: pos = sprintf( gettitle_buff, "Geocentric apparent equatorial %s; " "; epoch J%s", word, astFmtDecimalYr( palEpj( epoch ), 9 ) ); break; /* Ecliptic coordinates. */ /* --------------------- */ /* Display only the Equinox value. */ case AST__ECLIPTIC: pos = sprintf( gettitle_buff, "Ecliptic %s", word ); if( astTestEquinox( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; mean equinox J%s", astFmtDecimalYr( palEpj( equinox ), 9 ) ); } break; /* Helio-ecliptic coordinates. */ /* --------------------------- */ /* Display only the Epoch value (equinox is fixed). */ case AST__HELIOECLIPTIC: pos = sprintf( gettitle_buff, "Helio-ecliptic %s; mean equinox J2000", word ); if( astTestEpoch( this ) || astGetUseDefs( this ) ) { pos += sprintf( gettitle_buff + pos, "; epoch J%s", astFmtDecimalYr( palEpj( epoch ), 9 ) ); } break; /* Galactic coordinates. */ /* --------------------- */ /* Do not display an Equinox or Epoch value. */ case AST__GALACTIC: pos = sprintf( gettitle_buff, "IAU (1958) galactic %s", word ); break; /* Supergalactic coordinates. */ /* -------------------------- */ /* Do not display an Equinox or Epoch value. */ case AST__SUPERGALACTIC: pos = sprintf( gettitle_buff, "De Vaucouleurs supergalactic %s", word ); break; /* Unknown coordinates. */ /* -------------------------- */ case AST__UNKNOWN: pos = sprintf( gettitle_buff, "Spherical %s", word ); break; /* Report an error if the coordinate system was not recognised. */ default: astError( AST__SCSIN, "astGetTitle(%s): Corrupt %s contains " "invalid sky coordinate system identification code " "(%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); break; } /* If OK, we add either a description of the sky projection, or (if used) a description of the origin or pole of the offset coordinate system. We include only one of these two strings in order to keep the length of the title down to a reasonable value.*/ if ( astOK ) { /* If the SkyRef attribute has set values, create a description of the offset coordinate system. */ if( offset ){ word = ( astGetSkyRefIs( this ) == AST__POLE_REF )?"pole":"origin"; lextra = sprintf( gettitle_buff2, "%s at %s ", word, astFormat( this, 0, astGetSkyRef( this, 0 ) ) ); lextra += sprintf( gettitle_buff2 + lextra, "%s", astFormat( this, 1, astGetSkyRef( this, 1 ) ) ); extra = gettitle_buff2; /* Otherwise, get the sky projection description. */ } else { extra = projection; /* Determine the length of the extra information, after removing trailing white space. */ for ( lextra = (int) strlen( extra ); lextra > 0; lextra-- ) { if ( !isspace( extra[ lextra - 1 ] ) ) break; } } /* If non-blank extra information is available, append it to the title string, checking that the end of the buffer is not over-run. */ if ( lextra ) { p = "; "; while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) && *p ) gettitle_buff[ pos++ ] = *p++; p = extra; while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) && ( p < ( extra + lextra ) ) ) gettitle_buff[ pos++ ] = *p++; if( extra == projection ) { p = " projection"; while ( ( pos < AST__SKYFRAME_GETTITLE_BUFF_LEN ) && *p ) gettitle_buff[ pos++ ] = *p++; } gettitle_buff[ pos ] = '\0'; } } } } /* If an error occurred, clear the returned pointer value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static const char *GetUnit( AstFrame *this_frame, int axis, int *status ) { /* * Name: * GetUnit * Purpose: * Obtain a pointer to the Unit string for a SkyFrame's axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *GetUnit( AstFrame *this_frame, int axis ) * Class Membership: * SkyFrame member function (over-rides the astGetUnit method inherited * from the Frame class). * Description: * This function returns a pointer to the Unit string for a specified axis * of a SkyFrame. If the Unit attribute has not been set for the axis, a * pointer to a suitable default string is returned instead. This string may * depend on the value of the Format attribute for the axis and, in turn, on * the type of sky coordinate system that the SkyFrame describes. * Parameters: * this * Pointer to the SkyFrame. * axis * The number of the axis (zero-based) for which information is required. * Returned Value: * A pointer to a null-terminated string containing the Unit value. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const char *result; /* Pointer value to return */ int format_set; /* Format attribute set? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astGetUnit" ); /* The Unit value may depend on the value of the Format attribute, so determine if a Format value has been set for the axis and set a temporary value if it has not. Use the GetFormat member function for this class together with member functions inherited from the parent class (rather than using the object's methods directly) because if any of these methods have been over-ridden by a derived class the Format string syntax may no longer be compatible with this class. */ format_set = (*parent_testformat)( this_frame, axis, status ); if ( !format_set ) { (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status ); } /* Use the parent GetUnit method to return a pointer to the required Unit string. */ result = (*parent_getunit)( this_frame, axis, status ); /* If necessary, clear any temporary Format value that was set above. */ if ( !format_set ) (*parent_clearformat)( this_frame, axis, status ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } void astInitSkyFrameVtab_( AstSkyFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSkyFrameVtab * Purpose: * Initialise a virtual function table for a SkyFrame. * Type: * Protected function. * Synopsis: * #include "skyframe.h" * void astInitSkyFrameVtab( AstSkyFrameVtab *vtab, const char *name ) * Class Membership: * SkyFrame vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SkyFrame class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ int stat; /* SLALIB status */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitFrameVtab( (AstFrameVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASkyFrame) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstFrameVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearAsTime = ClearAsTime; vtab->ClearEquinox = ClearEquinox; vtab->ClearNegLon = ClearNegLon; vtab->ClearProjection = ClearProjection; vtab->GetAsTime = GetAsTime; vtab->GetEquinox = GetEquinox; vtab->GetNegLon = GetNegLon; vtab->GetIsLatAxis = GetIsLatAxis; vtab->GetIsLonAxis = GetIsLonAxis; vtab->GetLatAxis = GetLatAxis; vtab->GetLonAxis = GetLonAxis; vtab->GetProjection = GetProjection; vtab->SetAsTime = SetAsTime; vtab->SetEquinox = SetEquinox; vtab->SetNegLon = SetNegLon; vtab->SetProjection = SetProjection; vtab->SkyOffsetMap = SkyOffsetMap; vtab->TestAsTime = TestAsTime; vtab->TestEquinox = TestEquinox; vtab->TestNegLon = TestNegLon; vtab->TestProjection = TestProjection; vtab->TestSkyRef = TestSkyRef; vtab->SetSkyRef = SetSkyRef; vtab->GetSkyRef = GetSkyRef; vtab->ClearSkyRef = ClearSkyRef; vtab->TestSkyRefP = TestSkyRefP; vtab->SetSkyRefP = SetSkyRefP; vtab->GetSkyRefP = GetSkyRefP; vtab->ClearSkyRefP = ClearSkyRefP; vtab->TestSkyRefIs = TestSkyRefIs; vtab->SetSkyRefIs = SetSkyRefIs; vtab->GetSkyRefIs = GetSkyRefIs; vtab->ClearSkyRefIs = ClearSkyRefIs; vtab->TestAlignOffset = TestAlignOffset; vtab->SetAlignOffset = SetAlignOffset; vtab->GetAlignOffset = GetAlignOffset; vtab->ClearAlignOffset = ClearAlignOffset; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; frame = (AstFrameVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_gettop = frame->GetTop; frame->GetTop = GetTop; parent_setobsalt = frame->SetObsAlt; frame->SetObsAlt = SetObsAlt; parent_setobslat = frame->SetObsLat; frame->SetObsLat = SetObsLat; parent_setobslon = frame->SetObsLon; frame->SetObsLon = SetObsLon; parent_clearobslon = frame->ClearObsLon; frame->ClearObsLon = ClearObsLon; parent_clearobsalt = frame->ClearObsAlt; frame->ClearObsAlt = ClearObsAlt; parent_clearobslat = frame->ClearObsLat; frame->ClearObsLat = ClearObsLat; parent_getbottom = frame->GetBottom; frame->GetBottom = GetBottom; parent_getepoch = frame->GetEpoch; frame->GetEpoch = GetEpoch; parent_format = frame->Format; frame->Format = Format; parent_gap = frame->Gap; frame->Gap = Gap; parent_getdirection = frame->GetDirection; frame->GetDirection = GetDirection; parent_getdomain = frame->GetDomain; frame->GetDomain = GetDomain; parent_getsystem = frame->GetSystem; frame->GetSystem = GetSystem; parent_setsystem = frame->SetSystem; frame->SetSystem = SetSystem; parent_clearsystem = frame->ClearSystem; frame->ClearSystem = ClearSystem; parent_getalignsystem = frame->GetAlignSystem; frame->GetAlignSystem = GetAlignSystem; parent_getformat = frame->GetFormat; frame->GetFormat = GetFormat; parent_getlabel = frame->GetLabel; frame->GetLabel = GetLabel; parent_getsymbol = frame->GetSymbol; frame->GetSymbol = GetSymbol; parent_gettitle = frame->GetTitle; frame->GetTitle = GetTitle; parent_getunit = frame->GetUnit; frame->GetUnit = GetUnit; parent_match = frame->Match; frame->Match = Match; parent_overlay = frame->Overlay; frame->Overlay = Overlay; parent_subframe = frame->SubFrame; frame->SubFrame = SubFrame; parent_unformat = frame->Unformat; frame->Unformat = Unformat; parent_setdut1 = frame->SetDut1; frame->SetDut1 = SetDut1; parent_cleardut1 = frame->ClearDut1; frame->ClearDut1 = ClearDut1; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ frame->Angle = Angle; frame->Distance = Distance; frame->FrameGrid = FrameGrid; frame->Intersect = Intersect; frame->Norm = Norm; frame->NormBox = NormBox; frame->Resolve = Resolve; frame->ResolvePoints = ResolvePoints; frame->Offset = Offset; frame->Offset2 = Offset2; frame->ValidateSystem = ValidateSystem; frame->SystemString = SystemString; frame->SystemCode = SystemCode; frame->LineDef = LineDef; frame->LineContains = LineContains; frame->LineCrossing = LineCrossing; frame->LineOffset = LineOffset; frame->GetActiveUnit = GetActiveUnit; frame->TestActiveUnit = TestActiveUnit; frame->MatchAxesX = MatchAxesX; /* Store pointers to inherited methods that will be invoked explicitly by this class. */ parent_clearformat = frame->ClearFormat; parent_setformat = frame->SetFormat; parent_testformat = frame->TestFormat; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "SkyFrame", "Description of celestial coordinate system" ); /* Initialize constants for converting between hours, degrees and radians, etc.. */ LOCK_MUTEX2 palDtf2r( 1, 0, 0.0, &hr2rad, &stat ); palDaf2r( 1, 0, 0.0, °2rad, &stat ); palDaf2r( 180, 0, 0.0, &pi, &stat ); piby2 = 0.5*pi; UNLOCK_MUTEX2 /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static void Intersect( AstFrame *this_frame, const double a1[2], const double a2[2], const double b1[2], const double b2[2], double cross[2], int *status ) { /* * Name: * Intersect * Purpose: * Find the point of intersection between two geodesic curves. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Intersect( AstFrame *this_frame, const double a1[2], * const double a2[2], const double b1[2], * const double b2[2], double cross[2], * int *status ) * Class Membership: * SkyFrame member function (over-rides the astIntersect method * inherited from the Frame class). * Description: * This function finds the coordinate values at the point of * intersection between two geodesic curves. Each curve is specified * by two points on the curve. * Parameters: * this * Pointer to the SkyFrame. * a1 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a point on the first * geodesic curve. * a2 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a second point on the * first geodesic curve. * b1 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a point on the second * geodesic curve. * b2 * An array of double, with one element for each Frame axis. * This should contain the coordinates of a second point on * the second geodesic curve. * cross * An array of double, with one element for each Frame axis * in which the coordinates of the required intersection * point will be returned. These will be AST__BAD if the curves do * not intersect. * status * Pointer to the inherited status variable. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. * - For SkyFrames each curve will be a great circle, and in general * each pair of curves will intersect at two diametrically opposite * points on the sky. The returned position is the one which is * closest to point "a1". */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Pointer to axis permutation array */ double aa1[ 2 ]; /* Permuted coordinates for a1 */ double aa2[ 2 ]; /* Permuted coordinates for a2 */ double bb1[ 2 ]; /* Permuted coordinates for b1 */ double bb2[ 2 ]; /* Permuted coordinates for b2 */ double cc[ 2 ]; /* Permuted coords at intersection */ double d1; /* Cos(distance from a1 to vp) */ double d2; /* Cos(distance from a1 to -vp) */ double na[ 3 ]; /* Normal to the a1/a2 great circle */ double nb[ 3 ]; /* Normal to the b1/b2 great circle */ double va1[ 3 ]; /* Vector pointing at a1 */ double va2[ 3 ]; /* Vector pointing at a2 */ double vb1[ 3 ]; /* Vector pointing at b1 */ double vb2[ 3 ]; /* Vector pointing at b2 */ double vmod; /* Length of "vp" */ double vp[ 3 ]; /* Vector pointing at the intersection */ double vpn[ 3 ]; /* Normalised vp */ int iaxis; /* Axis index */ /* Initialise. */ cross[ 0 ] = AST__BAD; cross[ 1 ] = AST__BAD; /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Check that all supplied values are OK. */ if ( ( a1[ 0 ] != AST__BAD ) && ( a1[ 1 ] != AST__BAD ) && ( a2[ 0 ] != AST__BAD ) && ( a2[ 1 ] != AST__BAD ) && ( b1[ 0 ] != AST__BAD ) && ( b1[ 1 ] != AST__BAD ) && ( b2[ 0 ] != AST__BAD ) && ( b2[ 1 ] != AST__BAD ) ) { /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Apply the axis permutation array to obtain the coordinates of the points in the required (longitude,latitude) order. */ for( iaxis = 0; iaxis < 2; iaxis++ ) { aa1[ perm[ iaxis ] ] = a1[ iaxis ]; aa2[ perm[ iaxis ] ] = a2[ iaxis ]; bb1[ perm[ iaxis ] ] = b1[ iaxis ]; bb2[ perm[ iaxis ] ] = b2[ iaxis ]; } /* Convert each (lon,lat) pair into a unit length 3-vector. */ palDcs2c( aa1[ 0 ], aa1[ 1 ], va1 ); palDcs2c( aa2[ 0 ], aa2[ 1 ], va2 ); palDcs2c( bb1[ 0 ], bb1[ 1 ], vb1 ); palDcs2c( bb2[ 0 ], bb2[ 1 ], vb2 ); /* Find the normal vectors to the two great cicles. */ palDvxv( va1, va2, na ); palDvxv( vb1, vb2, nb ); /* The cross product of the two normal vectors points to one of the two diametrically opposite intersections. */ palDvxv( na, nb, vp ); /* Normalise the "vp" vector, also obtaining its original modulus. */ palDvn( vp, vpn, &vmod ); if( vmod != 0.0 ) { /* We want the intersection which is closest to "a1". The dot product gives the cos(distance) between two positions. So find the dot product between "a1" and "vpn", and then between "a1" and the point diametrically opposite "vpn". */ d1 = palDvdv( vpn, va1 ); vpn[ 0 ] = -vpn[ 0 ]; vpn[ 1 ] = -vpn[ 1 ]; vpn[ 2 ] = -vpn[ 2 ]; d2 = palDvdv( vpn, va1 ); /* Revert to "vpn" if it is closer to "a1". */ if( d1 > d2 ) { vpn[ 0 ] = -vpn[ 0 ]; vpn[ 1 ] = -vpn[ 1 ]; vpn[ 2 ] = -vpn[ 2 ]; } /* Convert the vector back into a (lon,lat) pair, and put the longitude into the range 0 to 2.pi. */ palDcc2s( vpn, cc, cc + 1 ); *cc = palDranrm( *cc ); /* Permute the result coordinates to undo the effect of the SkyFrame axis permutation array. */ cross[ 0 ] = cc[ perm[ 0 ] ]; cross[ 1 ] = cc[ perm[ 1 ] ]; } } } } static int IsEquatorial( AstSystemType system, int *status ) { /* * Name: * IsEquatorial * Purpose: * Test for an equatorial sky coordinate system. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int IsEquatorial( AstSystemType system, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns a boolean value to indicate if a sky coordinate * system is equatorial. * Parameters: * system * Code to identify the sky coordinate system. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the sky coordinate system is equatorial, otherwise zero. * Notes: * - A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables: */ int result; /* Result value to return */ /* Check the global error status. */ if ( !astOK ) return 0; /* Determine if the sky coordinate system is an equatorial one. Note, ICRS is not equatorial by definition, but is included here because it is normally treated as an equatorial system in terms of the axis labels, formats, etc. */ result = ( ( system == AST__FK4 ) || ( system == AST__FK4_NO_E ) || ( system == AST__ICRS ) || ( system == AST__FK5 ) || ( system == AST__J2000 ) || ( system == AST__GAPPT ) ); /* Return the result. */ return result; } static int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) { /* * Name: * LineContains * Purpose: * Determine if a line contains a point. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astLineContains * method inherited from the Frame class). * Description: * This function determines if the supplied point is on the supplied * line within the supplied Frame. The start point of the line is * considered to be within the line, but the end point is not. The tests * are that the point of closest approach of the line to the point should * be between the start and end, and that the distance from the point to * the point of closest aproach should be less than 1.0E-7 of the length * of the line. * Parameters: * this * Pointer to the Frame. * l * Pointer to the structure defining the line. * def * Should be set non-zero if the "point" array was created by a * call to astLineCrossing (in which case it may contain extra * information following the axis values),and zero otherwise. * point * Point to an array containing the axis values of the point to be * tested, possibly followed by extra cached information (see "def"). * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the line contains the point. * Notes: * - The pointer supplied for "l" should have been created using the * astLineDef method. These structures contained cached information about * the lines which improve the efficiency of this method when many * repeated calls are made. An error will be reported if the structure * does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. *- */ /* Local Variables: */ SkyLineDef *sl; /* SkyLine information */ const int *perm; /* Pointer to axis permutation array */ double *b; /* Pointer to Cartesian coords array */ double bb[3]; /* Buffer for Cartesian coords */ double p1[2]; /* Buffer for Spherical coords */ double t1, t2; int result; /* Returned value */ /* Initialise */ result =0; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the line refers to the supplied Frame. */ if( l->frame != this ) { astError( AST__INTER, "astLineContains(%s): The supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); /* Check the axis values are good */ } else if( point[ 0 ] != AST__BAD && point[ 1 ] != AST__BAD ){ /* Get a pointer to an array holding the corresponding Cartesian coords. */ if( def ) { b = point + 2; } else { perm = astGetPerm( this ); if ( perm ) { p1[ perm[ 0 ] ] = point[ 0 ]; p1[ perm[ 1 ] ] = point[ 1 ]; palDcs2c( p1[ 0 ], p1[ 1 ], bb ); b = bb; } else { b = NULL; } } /* Recast the supplied AstLineDef into a SkyLineDef to get the different structure (we know from the above check on the Frame that it is safe to do this). */ sl = (SkyLineDef *) l; /* Check that the point of closest approach of the line to the point is within the limits of the line. */ if( LineIncludes( sl, b, status ) ){ /* Check that the point is 90 degrees away from the pole of the great circle containing the line. */ t1 = palDvdv( sl->q, b ); t2 = 1.0E-7*sl->length; if( t2 < 1.0E-10 ) t2 = 1.0E-10; if( fabs( t1 ) <= t2 ) result = 1; } } /* Return the result. */ return result; } static int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2, double **cross, int *status ) { /* * Name: * LineCrossing * Purpose: * Determine if two lines cross. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2, * double **cross, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astLineCrossing * method inherited from the Frame class). * Description: * This function determines if the two suplied line segments cross, * and if so returns the axis values at the point where they cross. * A flag is also returned indicating if the crossing point occurs * within the length of both line segments, or outside one or both of * the line segments. * Parameters: * this * Pointer to the Frame. * l1 * Pointer to the structure defining the first line. * l2 * Pointer to the structure defining the second line. * cross * Pointer to a location at which to put a pointer to a dynamically * alocated array containing the axis values at the crossing. If * NULL is supplied no such array is returned. Otherwise, the returned * array should be freed using astFree when no longer needed. If the * lines are parallel (i.e. do not cross) then AST__BAD is returned for * all axis values. Note usable axis values are returned even if the * lines cross outside the segment defined by the start and end points * of the lines. The order of axes in the returned array will take * account of the current axis permutation array if appropriate. Note, * sub-classes such as SkyFrame may append extra values to the end * of the basic frame axis values. A NULL pointer is returned if an * error occurs. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the lines cross at a point which is * within the [start,end) segment of both lines. If the crossing point * is outside this segment on either line, or if the lines are parallel, * zero is returned. Note, the start point is considered to be inside * the length of the segment, but the end point is outside. * Notes: * - The pointers supplied for "l1" and "l2" should have been created * using the astLineDef method. These structures contained cached * information about the lines which improve the efficiency of this method * when many repeated calls are made. An error will be reported if * either structure does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. */ /* Local Variables: */ SkyLineDef *sl1; /* SkyLine information for line 1 */ SkyLineDef *sl2; /* SkyLine information for line 2 */ const int *perm; /* Pointer to axis permutation array */ double *crossing; /* Pointer to returned array */ double *b; /* Pointer to Cartesian coords */ double len; /* Vector length */ double p[ 2 ]; /* Temporary (lon,lat) pair */ double temp[ 3 ]; /* Temporary vector */ int result; /* Returned value */ /* Initialise */ result = 0; if( cross ) *cross = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Allocate returned array (2 elements for the lon and lat values, plus 3 for the corresponding (x,y,z) coords). */ crossing = astMalloc( sizeof(double)*5 ); /* Check that both lines refer to the supplied Frame. */ if( l1->frame != this ) { astError( AST__INTER, "astLineCrossing(%s): First supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); } else if( l2->frame != this ) { astError( AST__INTER, "astLineCrossing(%s): Second supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); /* Recast the supplied AstLineDefs into a SkyLineDefs to get the different structure (we know from the above check on the Frame that it is safe to do this). */ } else if( crossing ){ sl1 = (SkyLineDef *) l1; sl2 = (SkyLineDef *) l2; /* Point of intersection of the two great circles is perpendicular to the pole vectors of both great circles. Put the Cartesian coords in elements 2 to 4 of the returned array. */ palDvxv( sl1->q, sl2->q, temp ); b = crossing + 2; palDvn( temp, b, &len ); /* See if this point is within the length of both arcs. If so return it. */ if( LineIncludes( sl2, b, status ) && LineIncludes( sl1, b, status ) ) { result = 1; /* If not, see if the negated b vector is within the length of both arcs. If so return it. Otherwise, we return zero. */ } else { b[ 0 ] *= -1.0; b[ 1 ] *= -1.0; b[ 2 ] *= -1.0; if( LineIncludes( sl2, b, status ) && LineIncludes( sl1, b, status ) ) result = 1; } /* Store the spherical coords in elements 0 and 1 of the returned array. */ palDcc2s( b, p, p + 1 ); /* Permute the spherical axis value into the order used by the SkyFrame. */ perm = astGetPerm( this ); if( perm ){ crossing[ 0 ] = p[ perm[ 0 ] ]; crossing[ 1 ] = p[ perm[ 1 ] ]; } } /* If an error occurred, return 0. */ if( !astOK ) { result = 0; crossing = astFree( crossing ); } /* Return the array */ if( cross ) { *cross = crossing; } else { crossing = astFree( crossing ); } /* Return the result. */ return result; } static AstLineDef *LineDef( AstFrame *this, const double start[2], const double end[2], int *status ) { /* * Name: * LineDef * Purpose: * Creates a structure describing a line segment in a 2D Frame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * AstLineDef *LineDef( AstFrame *this, const double start[2], * const double end[2], int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astLineDef * method inherited from the Frame class). * Description: * This function creates a structure containing information describing a * given line segment within the supplied 2D Frame. This may include * information which allows other methods such as astLineCrossing to * function more efficiently. Thus the returned structure acts as a * cache to store intermediate values used by these other methods. * Parameters: * this * Pointer to the Frame. Must have 2 axes. * start * An array of 2 doubles marking the start of the line segment. * end * An array of 2 doubles marking the end of the line segment. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the memory structure containing the description of the * line. This structure should be freed using astFree when no longer * needed. A NULL pointer is returned (without error) if any of the * supplied axis values are AST__BAD. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ SkyLineDef *result; /* Returned value */ const int *perm; /* Axis permutation array */ double len; /* Permuted point1 coordinates */ double p1[ 2 ]; /* Permuted point1 coordinates */ double p2[ 2 ]; /* Permuted point2 coordinates */ double temp[3]; /* Cartesian coords at offset position */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return NULL; /* Check the axis values are good */ if( start[ 0 ] != AST__BAD && start[ 1 ] != AST__BAD && end[ 0 ] != AST__BAD && end[ 1 ] != AST__BAD ) { /* Allocate memory for the returned structure. */ result = astMalloc( sizeof( SkyLineDef ) ); /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( perm ) { /* Apply the axis permutation array to obtain the coordinates of the two input points in the required (longitude,latitude) order. */ p1[ perm[ 0 ] ] = start[ 0 ]; p1[ perm[ 1 ] ] = start[ 1 ]; p2[ perm[ 0 ] ] = end[ 0 ]; p2[ perm[ 1 ] ] = end[ 1 ]; /* Convert each point into a 3-vector of unit length and store in the returned structure. */ palDcs2c( p1[ 0 ], p1[ 1 ], result->start ); palDcs2c( p2[ 0 ], p2[ 1 ], result->end ); /* Calculate the great circle distance between the points in radians and store in the result structure. */ result->length = acos( palDvdv( result->start, result->end ) ); /* Find a unit vector representing the pole of the system in which the equator is given by the great circle. This is such that going the short way from the start to the end, the pole is to the left of the line as seen by the observer (i.e. from the centre of the sphere). If the line has zero length, or 180 degrees length, the pole is undefined, so we use an arbitrary value. */ if( result->length == 0.0 || result->length > pi - 5.0E-11 ) { palDcs2c( p1[ 0 ] + 0.01, p1[ 1 ] + 0.01, temp ); palDvxv( temp, result->start, result->dir ); } else { palDvxv( result->end, result->start, result->dir ); } palDvn( result->dir, result->q, &len ); /* Also store a point which is 90 degrees along the great circle from the start. */ palDvxv( result->start, result->q, result->dir ); /* Store a pointer to the defining SkyFrame. */ result->frame = this; /* Indicate that the line is considered to be terminated at the start and end points. */ result->infinite = 0; result->start_2d[ 0 ] = start[ 0 ]; result->start_2d[ 1 ] = start[ 1 ]; result->end_2d[ 0 ] = end[ 0 ]; result->end_2d[ 1 ] = end[ 1 ]; astNorm( this, result->start_2d ); astNorm( this, result->end_2d ); } } /* Free the returned pointer if an error occurred. */ if( !astOK ) result = astFree( result ); /* Return a pointer to the output structure. */ return (AstLineDef *) result; } static int LineIncludes( SkyLineDef *l, double point[3], int *status ) { /* * Name: * LineIncludes * Purpose: * Determine if a line includes a point which is known to be in the * great circle. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int LineIncludes( SkyLineDef *l, double point[3], int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astLineIncludes * method inherited from the Frame class). * Description: * The supplied point is assumed to be a point on the great circle of * which the supplied line is a segment. This function returns true if * "point" is within the bounds of the segment (the end point of the * line is assumed * not to be part of the segment). * Parameters: * l * Pointer to the structure defining the line. * point * An array holding the Cartesian coords of the point to be tested. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the line includes the point. * Notes: * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. */ /* Local Variables: */ double t1, t2, t3; /* Check the global error status. */ if ( !astOK ) return 0; /* If the line is of infite length, it is assumed to include the supplied point. */ if( l->infinite ) return 1; /* Otherwise, get the unsigned distance of the point from the start of the line in the range 0 - 180 degs. Check it is less than the line length. Then check that the point is not more than 90 degs away from the quarter point. */ t1 = palDvdv( l->start, point ); t2 = acos( t1 ); t3 = palDvdv( l->dir, point ); return ( ((l->length > 0) ? t2 < l->length : t2 == 0.0 ) && t3 >= -1.0E-8 ); } static void LineOffset( AstFrame *this, AstLineDef *line, double par, double prp, double point[2], int *status ){ /* * Name: * LineOffset * Purpose: * Find a position close to a line. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void LineOffset( AstFrame *this, AstLineDef *line, double par, * double prp, double point[2], int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astLineOffset * method inherited from the Frame class). * Description: * This function returns a position formed by moving a given distance along * the supplied line, and then a given distance away from the supplied line. * Parameters: * this * Pointer to the Frame. * line * Pointer to the structure defining the line. * par * The distance to move along the line from the start towards the end. * prp * The distance to move at right angles to the line. Positive * values result in movement to the left of the line, as seen from * the observer, when moving from start towards the end. * status * Pointer to the inherited status variable. * Notes: * - The pointer supplied for "line" should have been created using the * astLineDef method. This structure contains cached information about the * line which improves the efficiency of this method when many repeated * calls are made. An error will be reported if the structure does not * refer to the Frame specified by "this". *- */ /* Local Variables; */ SkyLineDef *sl; const int *perm; double c; double nx; double ny; double nz; double p[2]; double s; double v[3]; /* Check the global error status. */ if ( !astOK ) return; /* Check that the line refers to the supplied Frame. */ if( line->frame != this ) { astError( AST__INTER, "astLineOffset(%s): The supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); /* This implementation uses spherical geometry. */ } else { /* Get a pointer to the SkyLineDef structure. */ sl = (SkyLineDef *) line; /* Move a distance par from start to end. */ c = cos( par ); s = sin( par ); nx = c * sl->start[ 0 ] + s * sl->dir[ 0 ]; ny = c * sl->start[ 1 ] + s * sl->dir[ 1 ]; nz = c * sl->start[ 2 ] + s * sl->dir[ 2 ]; /* Move a distance prp from this point towards the pole point. */ if( prp != 0.0 ) { c = cos( prp ); s = sin( prp ); v[ 0 ] = c * nx + s * sl->q[ 0 ]; v[ 1 ] = c * ny + s * sl->q[ 1 ]; v[ 2 ] = c * nz + s * sl->q[ 2 ]; } else { v[ 0 ] = nx; v[ 1 ] = ny; v[ 2 ] = nz; } /* Convert to lon/lat */ palDcc2s( v, p, p + 1 ); /* Permute the spherical axis value into the order used by the SkyFrame. */ perm = astGetPerm( this ); if( perm ){ point[ 0 ] = p[ perm[ 0 ] ]; point[ 1 ] = p[ perm[ 1 ] ]; } } } static int MakeSkyMapping( AstSkyFrame *target, AstSkyFrame *result, AstSystemType align_sys, AstMapping **map, int *status ) { /* * Name: * MakeSkyMapping * Purpose: * Generate a Mapping between two SkyFrames. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int MakeSkyMapping( AstSkyFrame *target, AstSkyFrame *result, * AstSystemType align_sys, AstMapping **map, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function takes two SkyFrames and generates a Mapping that * converts between them, taking account of differences in their * coordinate systems, equinox value, epoch, etc. (but not allowing * for any axis permutations). * Parameters: * target * Pointer to the first SkyFrame. * result * Pointer to the second SkyFrame. * align_sys * The system in which to align the two SkyFrames. * map * Pointer to a location which is to receive a pointer to the * returned Mapping. The forward transformation of this Mapping * will convert from "target" coordinates to "result" * coordinates, and the inverse transformation will convert in * the opposite direction (all coordinate values in radians). * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Mapping could be generated, or zero if the two * SkyFrames are sufficiently un-related that no meaningful Mapping * can be produced. * Notes: * A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Constants: */ #define MAX_ARGS 4 /* Max arguments for an SlaMap conversion */ /* Local Variables: */ AstMapping *omap; /* Mapping from coorinates to offsets */ AstMapping *tmap2; /* Temporary Mapping */ AstMapping *tmap; /* Temporary Mapping */ AstSlaMap *slamap; /* Pointer to SlaMap */ AstSystemType result_system; /* Code to identify result coordinate system */ AstSystemType system; /* Code to identify coordinate system */ AstSystemType target_system; /* Code to identify target coordinate system */ double args[ MAX_ARGS ]; /* Conversion argument array */ double epoch; /* Epoch as Modified Julian Date */ double epoch_B; /* Besselian epoch as decimal years */ double epoch_J; /* Julian epoch as decimal years */ double equinox; /* Equinox as Modified Julian Date */ double equinox_B; /* Besselian equinox as decimal years */ double equinox_J; /* Julian equinox as decimal years */ double diurab; /* Magnitude of diurnal aberration vector */ double last; /* Local Apparent Sidereal Time */ double lat; /* Observers latitude */ double result_epoch; /* Result frame Epoch */ double result_equinox; /* Result frame Epoch */ double target_epoch; /* Target frame Epoch */ double target_equinox; /* Target frame Epoch */ int match; /* Mapping can be generated? */ int step1; /* Convert target to FK5 J2000? */ int step2; /* Convert FK5 J2000 to align sys? */ int step3; /* Convert align sys to FK5 J2000? */ int step4; /* Convert FK5 J2000 to result? */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise the returned values. */ match = 1; *map = NULL; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ epoch_B = 0.0; epoch_J = 0.0; equinox_B = 0.0; equinox_J = 0.0; /* Get the two epoch values. */ result_epoch = astGetEpoch( result ); target_epoch = astGetEpoch( target ); /* Get the two equinox values. */ result_equinox = astGetEquinox( result ); target_equinox = astGetEquinox( target ); /* Get the two system values. */ result_system = astGetSystem( result ); target_system = astGetSystem( target ); /* If either system is not references to the equinox given by the Equinox attribute, then use the equinox of the other system rather than adopting the arbitrary default of J2000. */ if( !EQREF(result_system) ) result_equinox = target_equinox; if( !EQREF(target_system) ) target_equinox = result_equinox; /* If both systems are unknown, assume they are the same. Return a UnitMap. We need to do this, otherwise a simple change of Title (for instance) will result in a FrameSet whose current Frame has System=AST__UNKNOWN loosing its integrity. */ if( target_system == AST__UNKNOWN && result_system == AST__UNKNOWN ) { *map = (AstMapping *) astUnitMap( 2, "", status ); return 1; } /* The total Mapping is divided into two parts in series; the first part converts from the target SkyFrame to the alignment system, using the Epoch and Equinox of the target Frame, the second part converts from the alignment system to the result SkyFrame, using the Epoch and Equinox of the result Frame. Each of these parts has an arbitrary input and an output system, and therefore could be implemented using a collection of NxN conversions. To reduce the complexity, each part is implement by converting from the input system to FK5 J2000, and then from FK5 J2000 to the output system. This scheme required only N conversions rather than NxN. Thus overall the total Mapping is made up of 4 steps in series. Some of these steps may be ommitted if they are effectively a UnitMap. Determine which steps need to be included. Assume all need to be done to begin with. */ step1 = 1; step2 = 1; step3 = 1; step4 = 1; /* If the target system is the same as the alignment system, neither of the first 2 steps need be done. */ if( target_system == align_sys ) { step1 = 0; step2 = 0; } /* If the result system is the same as the alignment system, neither of the last 2 steps need be done. */ if( result_system == align_sys ) { step3 = 0; step4 = 0; } /* If the two epochs are the same, or if the alignment system is FK5 J2000, steps 2 and 3 are not needed. */ if( step2 && step3 ) { if( align_sys == AST__FK5 || result_epoch == target_epoch ) { step2 = 0; step3 = 0; } } /* None are needed if the target and result SkyFrames have the same System, Epoch and Equinox. */ if( result_system == target_system && result_epoch == target_epoch && result_equinox == target_equinox ) { step1 = 0; step2 = 0; step3 = 0; step4 = 0; } /* Create an initial (null) SlaMap. */ slamap = astSlaMap( 0, "", status ); /* Define local macros as shorthand for adding sky coordinate conversions to this SlaMap. Each macro simply stores details of the additional arguments in the "args" array and then calls astSlaAdd. The macros differ in the number of additional argument values. */ #define TRANSFORM_0(cvt) \ astSlaAdd( slamap, cvt, NULL ); #define TRANSFORM_1(cvt,arg0) \ args[ 0 ] = arg0; \ astSlaAdd( slamap, cvt, args ); #define TRANSFORM_2(cvt,arg0,arg1) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ astSlaAdd( slamap, cvt, args ); #define TRANSFORM_3(cvt,arg0,arg1,arg2) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ args[ 2 ] = arg2; \ astSlaAdd( slamap, cvt, args ); #define TRANSFORM_4(cvt,arg0,arg1,arg2,arg3) \ args[ 0 ] = arg0; \ args[ 1 ] = arg1; \ args[ 2 ] = arg2; \ args[ 3 ] = arg3; \ astSlaAdd( slamap, cvt, args ); /* Convert _to_ FK5 J2000.0 coordinates. */ /* ===================================== */ /* The overall conversion is formulated in four phases. In this first phase, we convert from the target coordinate system to intermediate sky coordinates expressed using the FK5 system, mean equinox J2000.0. */ /* Obtain the sky coordinate system, equinox, epoch, etc, of the target SkyFrame. */ system = target_system; equinox = target_equinox; epoch = target_epoch; last = GetLAST( target, status ); diurab = GetDiurab( target, status ); lat = astGetObsLat( target ); if( astOK && step1 ) { /* Convert the equinox and epoch values (stored as Modified Julian Dates) into the equivalent Besselian and Julian epochs (as decimal years). */ equinox_B = palEpb( equinox ); equinox_J = palEpj( equinox ); epoch_B = palEpb( epoch ); epoch_J = palEpj( epoch ); /* Formulate the conversion... */ /* From FK4. */ /* --------- */ /* If necessary, apply the old-style FK4 precession model to bring the equinox to B1950.0, with rigorous handling of the E-terms of aberration. Then convert directly to FK5 J2000.0 coordinates. */ if ( system == AST__FK4 ) { VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status ); if ( equinox_B != 1950.0 ) { TRANSFORM_1( "SUBET", equinox_B ) TRANSFORM_2( "PREBN", equinox_B, 1950.0 ) TRANSFORM_1( "ADDET", 1950.0 ) } TRANSFORM_1( "FK45Z", epoch_B ) /* From FK4 with no E-terms. */ /* ------------------------- */ /* This is the same as above, except that we do not need to subtract the E-terms initially as they are already absent. */ } else if ( system == AST__FK4_NO_E ) { VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status ); if ( equinox_B != 1950.0 ) { TRANSFORM_2( "PREBN", equinox_B, 1950.0 ) } TRANSFORM_1( "ADDET", 1950.0 ) TRANSFORM_1( "FK45Z", epoch_B ) /* From FK5. */ /* --------- */ /* We simply need to apply a precession correction for the change of equinox. Omit even this if the equinox is already J2000.0. */ } else if ( system == AST__FK5 ) { VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status ); if ( equinox_J != 2000.0 ) { TRANSFORM_2( "PREC", equinox_J, 2000.0 ); } /* From J2000. */ /* ----------- */ /* Convert from J2000 to ICRS, then from ICRS to FK5. */ } else if ( system == AST__J2000 ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_0( "J2000H" ) TRANSFORM_1( "HFK5Z", epoch_J ); /* From geocentric apparent. */ /* ------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__GAPPT ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_2( "AMP", epoch, 2000.0 ) /* From ecliptic coordinates. */ /* -------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__ECLIPTIC ) { VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status ); TRANSFORM_1( "ECLEQ", equinox ) /* From helio-ecliptic coordinates. */ /* -------------------------------- */ } else if ( system == AST__HELIOECLIPTIC ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_1( "HEEQ", epoch ) /* From galactic coordinates. */ /* -------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__GALACTIC ) { TRANSFORM_0( "GALEQ" ) /* From ICRS. */ /* ---------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__ICRS ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_1( "HFK5Z", epoch_J ); /* From supergalactic coordinates. */ /* ------------------------------- */ /* Convert to galactic coordinates and then to FK5 J2000.0 equatorial. */ } else if ( system == AST__SUPERGALACTIC ) { TRANSFORM_0( "SUPGAL" ) TRANSFORM_0( "GALEQ" ) /* From AzEl. */ /* ---------- */ /* Rotate from horizon to equator (H2E), shift hour angle into RA (H2R), go from geocentric apparent to FK5 J2000. */ } else if ( system == AST__AZEL ) { VerifyMSMAttrs( target, result, 1, "ObsLon ObsLat Epoch", "astMatch", status ); TRANSFORM_2( "H2E", lat, diurab ) TRANSFORM_1( "H2R", last ) TRANSFORM_2( "AMP", epoch, 2000.0 ) /* From unknown coordinates. */ /* ------------------------- */ /* No conversion is possible. */ } else if ( system == AST__UNKNOWN ) { match = 0; } } /* Convert _from_ FK5 J2000.0 coordinates _to_ the alignment system. */ /* ============================================================ */ /* In this second phase, we convert to the system given by the align_sys argument (if required), still using the properties of the target Frame. */ if ( astOK && match && step2 ) { /* Align in FK4. */ /* --------------- */ /* Convert directly from FK5 J2000.0 to FK4 B1950.0 coordinates at the appropriate epoch. Then, if necessary, apply the old-style FK4 precession model to bring the equinox to that required, with rigorous handling of the E-terms of aberration. */ if ( align_sys == AST__FK4 ) { VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status ); TRANSFORM_1( "FK54Z", epoch_B ) if ( equinox_B != 1950.0 ) { TRANSFORM_1( "SUBET", 1950.0 ) TRANSFORM_2( "PREBN", 1950.0, equinox_B ) TRANSFORM_1( "ADDET", equinox_B ) } /* Align in FK4 with no E-terms. */ /* ------------------------------- */ /* This is the same as above, except that we do not need to add the E-terms at the end. */ } else if ( align_sys == AST__FK4_NO_E ) { VerifyMSMAttrs( target, result, 1, "Equinox Epoch", "astMatch", status ); TRANSFORM_1( "FK54Z", epoch_B ) TRANSFORM_1( "SUBET", 1950.0 ) if ( equinox_B != 1950.0 ) { TRANSFORM_2( "PREBN", 1950.0, equinox_B ) } /* Align in FK5. */ /* ------------- */ /* We simply need to apply a precession correction for the change of equinox. Omit even this if the required equinox is J2000.0. */ } else if ( align_sys == AST__FK5 ) { VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status ); if ( equinox_J != 2000.0 ) { TRANSFORM_2( "PREC", 2000.0, equinox_J ) } /* Align in J2000. */ /* --------------- */ /* Mov from FK5 to ICRS, and from ICRS to J2000. */ } else if ( align_sys == AST__J2000 ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_1( "FK5HZ", epoch_J ) TRANSFORM_0( "HJ2000" ) /* Align in geocentric apparent. */ /* ------------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__GAPPT ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_2( "MAP", 2000.0, epoch ) /* Align in ecliptic coordinates. */ /* -------------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__ECLIPTIC ) { VerifyMSMAttrs( target, result, 1, "Equinox", "astMatch", status ); TRANSFORM_1( "EQECL", equinox ) /* Align in helio-ecliptic coordinates. */ /* ------------------------------------ */ } else if ( align_sys == AST__HELIOECLIPTIC ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_1( "EQHE", epoch ) /* Align in galactic coordinates. */ /* -------------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__GALACTIC ) { TRANSFORM_0( "EQGAL" ) /* Align in ICRS. */ /* -------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__ICRS ) { VerifyMSMAttrs( target, result, 1, "Epoch", "astMatch", status ); TRANSFORM_1( "FK5HZ", epoch_J ) /* Align in supergalactic coordinates. */ /* ------------------------------------- */ /* Convert to galactic coordinates and then to supergalactic. */ } else if ( align_sys == AST__SUPERGALACTIC ) { TRANSFORM_0( "EQGAL" ) TRANSFORM_0( "GALSUP" ) /* Align in AzEl coordinates. */ /* -------------------------- */ /* Go from FK5 J2000 to geocentric apparent (MAP), shift RA into hour angle (R2H), rotate from equator to horizon (E2H). */ } else if ( align_sys == AST__AZEL ) { VerifyMSMAttrs( target, result, 1, "ObsLon ObsLat Epoch", "astMatch", status ); TRANSFORM_2( "MAP", 2000.0, epoch ) TRANSFORM_1( "R2H", last ) TRANSFORM_2( "E2H", lat, diurab ) /* Align in unknown coordinates. */ /* ------------------------------- */ /* No conversion is possible. */ } else if ( align_sys == AST__UNKNOWN ) { match = 0; } } /* Convert _from_ the alignment system _to_ FK5 J2000.0 coordinates */ /* =========================================================== */ /* In this third phase, we convert from the alignment system (if required) to the intermediate FK5 J2000 system, using the properties of the result SkyFrame. */ /* Obtain the sky coordinate system, equinox, epoch, etc, of the result SkyFrame. */ system = result_system; equinox = result_equinox; epoch = result_epoch; diurab = GetDiurab( result, status ); last = GetLAST( result, status ); lat = astGetObsLat( result ); /* Convert the equinox and epoch values (stored as Modified Julian Dates) into the equivalent Besselian and Julian epochs (as decimal years). */ if( astOK ) { equinox_B = palEpb( equinox ); equinox_J = palEpj( equinox ); epoch_B = palEpb( epoch ); epoch_J = palEpj( epoch ); } /* Check we need to do the conversion. */ if ( astOK && match && step3 ) { /* Formulate the conversion... */ /* From FK4. */ /* --------- */ /* If necessary, apply the old-style FK4 precession model to bring the equinox to B1950.0, with rigorous handling of the E-terms of aberration. Then convert directly to FK5 J2000.0 coordinates. */ if ( align_sys == AST__FK4 ) { VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status ); if ( equinox_B != 1950.0 ) { TRANSFORM_1( "SUBET", equinox_B ) TRANSFORM_2( "PREBN", equinox_B, 1950.0 ) TRANSFORM_1( "ADDET", 1950.0 ) } TRANSFORM_1( "FK45Z", epoch_B ) /* From FK4 with no E-terms. */ /* ------------------------- */ /* This is the same as above, except that we do not need to subtract the E-terms initially as they are already absent. */ } else if ( align_sys == AST__FK4_NO_E ) { VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status ); if ( equinox_B != 1950.0 ) { TRANSFORM_2( "PREBN", equinox_B, 1950.0 ) } TRANSFORM_1( "ADDET", 1950.0 ) TRANSFORM_1( "FK45Z", epoch_B ) /* From FK5. */ /* --------- */ /* We simply need to apply a precession correction for the change of equinox. Omit even this if the equinox is already J2000.0. */ } else if ( align_sys == AST__FK5 ) { VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status ); if ( equinox_J != 2000.0 ) { TRANSFORM_2( "PREC", equinox_J, 2000.0 ); } /* From geocentric apparent. */ /* ------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__GAPPT ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_2( "AMP", epoch, 2000.0 ) /* From ecliptic coordinates. */ /* -------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__ECLIPTIC ) { VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status ); TRANSFORM_1( "ECLEQ", equinox ) /* From helio-ecliptic coordinates. */ /* -------------------------------- */ } else if ( align_sys == AST__HELIOECLIPTIC ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_1( "HEEQ", epoch ) /* From galactic coordinates. */ /* -------------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__GALACTIC ) { TRANSFORM_0( "GALEQ" ) /* From ICRS. */ /* ---------- */ /* This conversion is supported directly by SLALIB. */ } else if ( align_sys == AST__ICRS ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_1( "HFK5Z", epoch_J ) /* From J2000. */ /* ----------- */ /* From J2000 to ICRS, and from ICRS to FK5. */ } else if ( align_sys == AST__J2000 ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_0( "J2000H" ) TRANSFORM_1( "HFK5Z", epoch_J ) /* From supergalactic coordinates. */ /* ------------------------------- */ /* Convert to galactic coordinates and then to FK5 J2000.0 equatorial. */ } else if ( align_sys == AST__SUPERGALACTIC ) { TRANSFORM_0( "SUPGAL" ) TRANSFORM_0( "GALEQ" ) /* From AzEl. */ /* ---------- */ /* Rotate from horizon to equator (H2E), shift hour angle into RA (H2R), go from geocentric apparent to FK5 J2000. */ } else if ( align_sys == AST__AZEL ) { VerifyMSMAttrs( target, result, 3, "ObsLon ObsLat Epoch", "astMatch", status ); TRANSFORM_2( "H2E", lat, diurab ) TRANSFORM_1( "H2R", last ) TRANSFORM_2( "AMP", epoch, 2000.0 ) /* From unknown coordinates. */ /* ------------------------------- */ /* No conversion is possible. */ } else if ( align_sys == AST__UNKNOWN ) { match = 0; } } /* Convert _from_ FK5 J2000.0 coordinates. */ /* ======================================= */ /* In this fourth and final phase, we convert to the result coordinate system from the intermediate FK5 J2000 sky coordinates generated above. */ if ( astOK && match && step4 ) { /* To FK4. */ /* ------- */ /* Convert directly from FK5 J2000.0 to FK4 B1950.0 coordinates at the appropriate epoch. Then, if necessary, apply the old-style FK4 precession model to bring the equinox to that required, with rigorous handling of the E-terms of aberration. */ if ( system == AST__FK4 ) { VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status ); TRANSFORM_1( "FK54Z", epoch_B ) if ( equinox_B != 1950.0 ) { TRANSFORM_1( "SUBET", 1950.0 ) TRANSFORM_2( "PREBN", 1950.0, equinox_B ) TRANSFORM_1( "ADDET", equinox_B ) } /* To FK4 with no E-terms. */ /* ----------------------- */ /* This is the same as above, except that we do not need to add the E-terms at the end. */ } else if ( system == AST__FK4_NO_E ) { VerifyMSMAttrs( target, result, 3, "Equinox Epoch", "astMatch", status ); TRANSFORM_1( "FK54Z", epoch_B ) TRANSFORM_1( "SUBET", 1950.0 ) if ( equinox_B != 1950.0 ) { TRANSFORM_2( "PREBN", 1950.0, equinox_B ) } /* To FK5. */ /* ------- */ /* We simply need to apply a precession correction for the change of equinox. Omit even this if the required equinox is J2000.0. */ } else if ( system == AST__FK5 ) { VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status ); if ( equinox_J != 2000.0 ) { TRANSFORM_2( "PREC", 2000.0, equinox_J ) } /* To geocentric apparent. */ /* ----------------------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__GAPPT ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_2( "MAP", 2000.0, epoch ) /* To ecliptic coordinates. */ /* ------------------------ */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__ECLIPTIC ) { VerifyMSMAttrs( target, result, 3, "Equinox", "astMatch", status ); TRANSFORM_1( "EQECL", equinox ) /* To helio-ecliptic coordinates. */ /* ------------------------------ */ } else if ( system == AST__HELIOECLIPTIC ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_1( "EQHE", epoch ) /* To galactic coordinates. */ /* ------------------------ */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__GALACTIC ) { TRANSFORM_0( "EQGAL" ) /* To ICRS. */ /* -------- */ /* This conversion is supported directly by SLALIB. */ } else if ( system == AST__ICRS ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_1( "FK5HZ", epoch_J ) /* To J2000. */ /* --------- */ /* From FK5 to ICRS, then from ICRS to J2000. */ } else if ( system == AST__J2000 ) { VerifyMSMAttrs( target, result, 3, "Epoch", "astMatch", status ); TRANSFORM_1( "FK5HZ", epoch_J ) TRANSFORM_0( "HJ2000" ) /* To supergalactic coordinates. */ /* ----------------------------- */ /* Convert to galactic coordinates and then to supergalactic. */ } else if ( system == AST__SUPERGALACTIC ) { TRANSFORM_0( "EQGAL" ) TRANSFORM_0( "GALSUP" ) /* To AzEl */ /* ------- */ /* Go from FK5 J2000 to geocentric apparent (MAP), shift RA into hour angle (R2H), rotate from equator to horizon (E2H). */ } else if ( system == AST__AZEL ) { VerifyMSMAttrs( target, result, 3, "ObsLon ObsLat Epoch", "astMatch", status ); TRANSFORM_2( "MAP", 2000.0, epoch ) TRANSFORM_1( "R2H", last ) TRANSFORM_2( "E2H", lat, diurab ) /* To unknown coordinates. */ /* ----------------------------- */ /* No conversion is possible. */ } else if ( system == AST__UNKNOWN ) { match = 0; } } /* Now need to take account of the possibility that the input or output SkyFrame may represent an offset system rather than a coordinate system. Form the Mapping from the target coordinate system to the associated offset system. A UnitMap is returned if the target does not use an offset system. */ omap = SkyOffsetMap( target, status ); /* Invert it to get the Mapping from the actual used system (whther offsets or coordinates) to the coordinate system. */ astInvert( omap ); /* Combine it with the slamap created earlier, so that its coordinate outputs feed the inputs of the slamap. Annul redundant pointers afterwards. */ tmap = (AstMapping *) astCmpMap( omap, slamap, 1, "", status ); omap = astAnnul( omap ); slamap =astAnnul( slamap ); /* Now form the Mapping from the result coordinate system to the associated offset system. A UnitMap is returned if the result does not use an offset system. */ omap = SkyOffsetMap( result, status ); /* Combine it with the above CmpMap, so that the CmpMap outputs feed the new Mapping inputs. Annul redundant pointers afterwards. */ tmap2 = (AstMapping *) astCmpMap( tmap, omap, 1, "", status ); omap =astAnnul( omap ); tmap =astAnnul( tmap ); /* Simplify the Mapping produced above (this eliminates any redundant conversions) and annul the original pointer. */ *map = astSimplify( tmap2 ); tmap2 = astAnnul( tmap2 ); /* If an error occurred, annul the returned Mapping and clear the returned values. */ if ( !astOK ) { *map = astAnnul( *map ); match = -1; } /* Return the result. */ return match; /* Undefine macros local to this function. */ #undef MAX_ARGS #undef TRANSFORM_0 #undef TRANSFORM_1 #undef TRANSFORM_2 #undef TRANSFORM_3 } static int Match( AstFrame *template_frame, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * Match * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int Match( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astMatch method * inherited from the Frame class). * Description: * This function matches a "template" SkyFrame to a "target" Frame and * determines whether it is possible to convert coordinates between them. * If it is, a mapping that performs the transformation is returned along * with a new Frame that describes the coordinate system that results when * this mapping is applied to the "target" coordinate system. In addition, * information is returned to allow the axes in this "result" Frame to be * associated with the corresponding axes in the "target" and "template" * Frames from which they are derived. * Parameters: * template * Pointer to the template SkyFrame. This describes the coordinate system * (or set of possible coordinate systems) into which we wish to convert * our coordinates. * target * Pointer to the target Frame. This describes the coordinate system in * which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case. * template_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the template SkyFrame axis from which * it is derived. If it is not derived from any template SkyFrame axis, * a value of -1 will be returned instead. * target_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the target Frame axis from which it * is derived. If it is not derived from any target Frame axis, a value * of -1 will be returned instead. * map * Address of a location where a pointer to a new Mapping will be * returned if the requested coordinate conversion is possible. If * returned, the forward transformation of this Mapping may be used to * convert coordinates between the "target" Frame and the "result" * Frame (see below) and the inverse transformation will convert in the * opposite direction. * result * Address of a location where a pointer to a new Frame will be returned * if the requested coordinate conversion is possible. If returned, this * Frame describes the coordinate system that results from applying the * returned Mapping (above) to the "target" coordinate system. In * general, this Frame will combine attributes from (and will therefore * be more specific than) both the target and the template Frames. In * particular, when the template allows the possibility of transformaing * to any one of a set of alternative coordinate systems, the "result" * Frame will indicate which of the alternatives was used. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the requested coordinate conversion is * possible. Otherwise zero is returned (this will not in itself result in * an error condition). * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * This implementation addresses the matching of a SkyFrame class object to * any other class of Frame. A SkyFrame will match any class of SkyFrame * (i.e. possibly from a derived class) but will not match a less * specialised class of Frame. */ /* Local Variables: */ AstFrame *frame0; /* Pointer to Frame underlying axis 0 */ AstFrame *frame1; /* Pointer to Frame underlying axis 1 */ AstSkyFrame *template; /* Pointer to template SkyFrame structure */ int iaxis; /* Axis index */ int iaxis0; /* Axis index underlying axis 0 */ int iaxis1; /* Axis index underlying axis 1 */ int match; /* Coordinate conversion possible? */ int swap1; /* Template axes swapped? */ int swap2; /* Target axes swapped? */ int swap; /* Additional axis swap needed? */ int target_axis0; /* Index of 1st SkyFrame axis in the target */ int target_axis1; /* Index of 2nd SkyFrame axis in the target */ int target_naxes; /* Number of target axes */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ swap = 0; target_axis0 = -1; target_axis1 = -1; /* Obtain a pointer to the template SkyFrame structure. */ template = (AstSkyFrame *) template_frame; /* Obtain the number of axes in the target Frame. */ target_naxes = astGetNaxes( target ); /* The first criterion for a match is that the template matches as a Frame class object. This ensures that the number of axes (2) and domain, etc. of the target Frame are suitable. Invoke the parent "astMatch" method to verify this. */ match = (*parent_match)( template_frame, target, matchsub, template_axes, target_axes, map, result, status ); /* If a match was found, annul the returned objects, which are not needed, but keep the memory allocated for the axis association arrays, which we will re-use. */ if ( astOK && match ) { *map = astAnnul( *map ); *result = astAnnul( *result ); } /* If OK so far, obtain pointers to the primary Frames which underlie all target axes. Stop when a SkyFrame axis is found. */ if ( match && astOK ) { match = 0; for( iaxis = 0; iaxis < target_naxes; iaxis++ ) { astPrimaryFrame( target, iaxis, &frame0, &iaxis0 ); if( astIsASkyFrame( frame0 ) ) { target_axis0 = iaxis; match = 1; break; } else { frame0 = astAnnul( frame0 ); } } /* Check at least one SkyFrame axis was found it the target. */ if( match ) { /* If so, search the remaining target axes for another axis that is derived from the same SkyFrame. */ match = 0; for( iaxis++ ; iaxis < target_naxes; iaxis++ ) { astPrimaryFrame( target, iaxis, &frame1, &iaxis1 ); if( frame1 == frame0 ) { target_axis1 = iaxis; frame1 = astAnnul( frame1 ); match = 1; break; } else { frame1 = astAnnul( frame1 ); } } /* Annul the remaining Frame pointer used in the above tests. */ frame0 = astAnnul( frame0 ); } /* If this test is passed, we can now test that the underlying axis indices are 0 and 1, in either order. This then ensures that we have a single SkyFrame (not a compound Frame) with both axes present. */ if ( match && astOK ) { match = ( ( ( iaxis0 == 0 ) && ( iaxis1 == 1 ) ) || ( ( iaxis1 == 0 ) && ( iaxis0 == 1 ) ) ); } } /* If a possible match has been detected, we must now decide how the order of the axes in the result Frame relates to the order of axes in the target Frame. There are two factors involved. The first depends on whether the axis permutation array for the template SkyFrame (whose method we are executing) causes an axis reversal. Determine this by permuting axis index zero. */ if ( astOK && match ) { swap1 = ( astValidateAxis( template, 0, 1, "astMatch" ) != 0 ); /* The second factor depends on whether the axes of the underlying primary SkyFrame are reversed when seen in the target Frame. */ swap2 = ( iaxis0 != 0 ); /* Combine these to determine if an additional axis swap will be needed. */ swap = ( swap1 != swap2 ); /* Now check to see if this additional swap is permitted by the template's Permute attribute. */ match = ( !swap || astGetPermute( template ) ); } /* If the Frames still match, we next set up the axis association arrays. */ if ( astOK && match ) { /* If the target axis order is to be preserved, then the target axis association involves no permutation but the template axis association may involve an axis swap. */ if ( astGetPreserveAxes( template ) ) { (*template_axes)[ 0 ] = swap; (*template_axes)[ 1 ] = !swap; (*target_axes)[ 0 ] = target_axis0; (*target_axes)[ 1 ] = target_axis1; /* Otherwise, any swap applies to the target axis association instead. */ } else { (*template_axes)[ 0 ] = 0; (*template_axes)[ 1 ] = 1; (*target_axes)[ 0 ] = swap ? target_axis1 : target_axis0; (*target_axes)[ 1 ] = swap ? target_axis0 : target_axis1; } /* Use the target's "astSubFrame" method to create a new Frame (the result Frame) with copies of the target axes in the required order. This process also overlays the template attributes on to the target Frame and returns a Mapping between the target and result Frames which effects the required coordinate conversion. */ match = astSubFrame( target, template, 2, *target_axes, *template_axes, map, result ); } /* If an error occurred, or conversion to the result Frame's coordinate system was not possible, then free all memory, annul the returned objects, and reset the returned value. */ if ( !astOK || !match ) { *template_axes = astFree( *template_axes ); *target_axes = astFree( *target_axes ); if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } static void MatchAxesX( AstFrame *frm2_frame, AstFrame *frm1, int *axes, int *status ) { /* * Name: * MatchAxesX * Purpose: * Find any corresponding axes in two Frames. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes ) * int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astMatchAxesX * method inherited from the Frame class). * This function looks for corresponding axes within two supplied * Frames. An array of integers is returned that contains an element * for each axis in the second supplied Frame. An element in this array * will be set to zero if the associated axis within the second Frame * has no corresponding axis within the first Frame. Otherwise, it * will be set to the index (a non-zero positive integer) of the * corresponding axis within the first supplied Frame. * Parameters: * frm2 * Pointer to the second Frame. * frm1 * Pointer to the first Frame. * axes * Pointer to an integer array in which to return the indices of * the axes (within the first Frame) that correspond to each axis * within the second Frame. Axis indices start at 1. A value of zero * will be stored in the returned array for each axis in the second * Frame that has no corresponding axis in the first Frame. * * The number of elements in this array must be greater than or * equal to the number of axes in the second Frame. * status * Pointer to inherited status value. * Notes: * - Corresponding axes are identified by the fact that a Mapping * can be found between them using astFindFrame or astConvert. Thus, * "corresponding axes" are not necessarily identical. For instance, * SkyFrame axes in two Frames will match even if they describe * different celestial coordinate systems */ /* Local Variables: */ AstFrame *resfrm; AstMapping *resmap; AstSkyFrame *frm2; int *frm2_axes; int *frm1_axes; int max_axes; int min_axes; int preserve_axes; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the SkyFrame. */ frm2 = (AstSkyFrame *) frm2_frame; /* Temporarily ensure that the PreserveAxes attribute is non-zero in the first supplied Frame. This means thte result Frame returned by astMatch below will have the axis count and order of the target Frame (i.e. "pfrm"). */ if( astTestPreserveAxes( frm1 ) ) { preserve_axes = astGetPreserveAxes( frm1 ) ? 1 : 0; } else { preserve_axes = -1; } astSetPreserveAxes( frm1, 1 ); /* Temporarily ensure that the MaxAxes and MinAxes attributes in the first supplied Frame are set so the Frame can be used as a template in astMatch for matching any number of axes. */ if( astTestMaxAxes( frm1 ) ) { max_axes = astGetMaxAxes( frm1 ); } else { max_axes = -1; } astSetMaxAxes( frm1, 10000 ); if( astTestMinAxes( frm1 ) ) { min_axes = astGetMinAxes( frm1 ); } else { min_axes = -1; } astSetMinAxes( frm1, 1 ); /* Attempt to find a sub-frame within the first supplied Frame that corresponds to the supplied SkyFrame. */ if( astMatch( frm1, frm2, 1, &frm1_axes, &frm2_axes, &resmap, &resfrm ) ) { /* If successfull, Store the one-based index within "frm1" of the corresponding axes. */ axes[ 0 ] = frm1_axes[ 0 ] + 1; axes[ 1 ] = frm1_axes[ 1 ] + 1; /* Free resources */ frm1_axes = astFree( frm1_axes ); frm2_axes = astFree( frm2_axes ); resmap = astAnnul( resmap ); resfrm = astAnnul( resfrm ); /* If no corresponding SkyFrame was found store zeros in the returned array. */ } else { axes[ 0 ] = 0; axes[ 1 ] = 0; } /* Re-instate the original attribute values in the first supplied Frame. */ if( preserve_axes == -1 ) { astClearPreserveAxes( frm1 ); } else { astSetPreserveAxes( frm1, preserve_axes ); } if( max_axes == -1 ) { astClearMaxAxes( frm1 ); } else { astSetMaxAxes( frm1, max_axes ); } if( min_axes == -1 ) { astClearMinAxes( frm1 ); } else { astSetMinAxes( frm1, min_axes ); } } static void Norm( AstFrame *this_frame, double value[], int *status ) { /* * Name: * Norm * Purpose: * Normalise a set of SkyFrame coordinates. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Norm( AstAxis *this, double value[], int *status ) * Class Membership: * SkyFrame member function (over-rides the astNorm method inherited * from the Frame class). * Description: * This function converts a set of SkyFrame coordinate values, * which might potentially be unsuitable for display to a user (for * instance, may lie outside the expected range of values) into a * set of acceptable alternative values suitable for display. * * This is done by wrapping coordinates so that the latitude lies * in the range (-pi/2.0) <= latitude <= (pi/2.0). If the NegLon * attribute is zero (the default), then the wrapped longitude value * lies in the range 0.0 <= longitude < (2.0*pi). Otherwise, it lies * in the range -pi <= longitude < pi. * Parameters: * this * Pointer to the SkyFrame. * value * An array of double, with one element for each SkyFrame axis. * This should contain the initial set of coordinate values, * which will be modified in place. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Axis permutation array */ double sky_lat; /* Sky latitude value */ double sky_long; /* Sky longitude value */ double v[ 2 ]; /* Permuted value coordinates */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Obtain the sky longitude and latitude values, allowing for any axis permutation. */ v[ perm[ 0 ] ] = value[ 0 ]; v[ perm[ 1 ] ] = value[ 1 ]; sky_long = v[ 0 ]; sky_lat = v[ 1 ]; /* Test if both values are OK (i.e. not "bad"). */ if ( ( sky_long != AST__BAD ) && ( sky_lat != AST__BAD ) ) { /* Fold the longitude value into the range 0 to 2*pi and the latitude into the range -pi to +pi. */ sky_long = palDranrm( sky_long ); sky_lat = palDrange( sky_lat ); /* If the latitude now exceeds pi/2, shift the longitude by pi in whichever direction will keep it in the range 0 to 2*pi. */ if ( sky_lat > ( pi / 2.0 ) ) { sky_long += ( sky_long < pi ) ? pi : -pi; /* Reflect the latitude value through the pole, so it lies in the range 0 to pi/2. */ sky_lat = pi - sky_lat; /* If the latitude is less than -pi/2, shift the longitude in the same way as above. */ } else if ( sky_lat < -( pi / 2.0 ) ) { sky_long += ( sky_long < pi ) ? pi : -pi; /* But reflect the latitude through the other pole, so it lies in the range -pi/2 to 0. */ sky_lat = -pi - sky_lat; } /* If only the longitude value is valid, wrap it into the range 0 to 2*pi. */ } else if ( sky_long != AST__BAD ) { sky_long = palDranrm( sky_long ); /* If only the latitude value is valid, wrap it into the range -pi to +pi. */ } else if ( sky_lat != AST__BAD ) { sky_lat = palDrange( sky_lat ); /* Then refect through one of the poles (as above), if necessary, to move it into the range -pi/2 to +pi/2. */ if ( sky_lat > ( pi / 2.0 ) ) { sky_lat = pi - sky_lat; } else if ( sky_lat < -( pi / 2.0 ) ) { sky_lat = -pi - sky_lat; } } /* Convert 2*pi longitude into zero. Allow for a small error. */ if ( fabs( sky_long - ( 2.0 * pi ) ) <= ( 2.0 * pi ) * ( DBL_EPSILON * (double) FLT_RADIX ) ) sky_long = 0.0; /* If the NegLon attribute is set, and the longitude value is good, convert it into the range -pi to +pi. */ if( sky_long != AST__BAD && astGetNegLon( this ) ) { sky_long = palDrange( sky_long ); } /* Return the new values, allowing for any axis permutation. */ v[ 0 ] = sky_long; v[ 1 ] = sky_lat; value[ 0 ] = v[ perm[ 0 ] ]; value[ 1 ] = v[ perm[ 1 ] ]; } } static void NormBox( AstFrame *this_frame, double lbnd[], double ubnd[], AstMapping *reg, int *status ) { /* * Name: * NormBox * Purpose: * Extend a box to include effect of any singularities in the Frame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void astNormBox( AstFrame *this, double lbnd[], double ubnd[], * AstMapping *reg, int *status ) * Class Membership: * SkyFrame member function (over-rides the astNormBox method inherited * from the Frame class). * Description: * This function modifies a supplied box to include the effect of any * singularities in the co-ordinate system represented by the Frame. * For a normal Cartesian coordinate system, the box will be returned * unchanged. Other classes of Frame may do other things. For instance, * a SkyFrame will check to see if the box contains either the north * or south pole and extend the box appropriately. * Parameters: * this * Pointer to the Frame. * lbnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * lower axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * ubnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * upper axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * reg * A Mapping which should be used to test if any singular points are * inside or outside the box. The Mapping should leave an input * position unchanged if the point is inside the box, and should * set all bad if the point is outside the box. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Axis permutation array */ double lb[ 2 ]; /* Permuted lower bounds */ double t; /* Temporary storage */ double t2; /* Temporary storage */ double ub[ 2 ]; /* Permuted upper bounds */ double x[2]; /* 1st axis values at poles */ double xo[2]; /* Tested 1st axis values at poles */ double y[2]; /* 2nd axis values at poles */ double yo[2]; /* Tested 2nd axis values at poles */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if( perm ) { /* Obtain the sky longitude and latitude limits, allowing for any axis permutation. */ lb[ perm[ 0 ] ] = lbnd[ 0 ]; lb[ perm[ 1 ] ] = lbnd[ 1 ]; ub[ perm[ 0 ] ] = ubnd[ 0 ]; ub[ perm[ 1 ] ] = ubnd[ 1 ]; /* Use the supplied Mapping to test if box includes either pole. */ if( perm[ 0 ] == 0 ) { x[ 0 ] = 0.0; y[ 0 ] = AST__DPIBY2; x[ 1 ] = 0.0; y[ 1 ] = -AST__DPIBY2; } else { x[ 0 ] = AST__DPIBY2; y[ 0 ] = 0.0; x[ 1 ] = -AST__DPIBY2; y[ 1 ] = 0.0; } astTran2( reg, 2, x, y, 1, xo, yo ); /* If the box includes the north pole... */ if( xo[ 0 ] != AST__BAD ) { /* Find the lowest latitude after normalisation. */ if( ub[ 1 ] != AST__BAD && lb[ 1 ] != AST__BAD ){ t = palDrange( ub[ 1 ] ); t2 = palDrange( lb[ 1 ] ); if( t2 < t ) t = t2; } else { t = AST__BAD; } /* Set the lower returned limit to this value and the upper returned limit to +90 degs */ lb[ 1 ] = t; ub[ 1 ] = AST__DPIBY2; /* Set the longitude range to 0 to 2PI */ lb[ 0 ] = 0; ub[ 0 ] = 2*AST__DPI; } /* If the box includes the south pole... */ if( xo[ 1 ] != AST__BAD ) { /* Find the highest latitude after normalisation. */ if( ub[ 1 ] != AST__BAD && lb[ 1 ] != AST__BAD ){ t = palDrange( ub[ 1 ] ); t2 = palDrange( lb[ 1 ] ); if( t2 > t ) t = t2; } else { t = AST__BAD; } /* Set the upper returned limit to this value and the lower returned limit to -90 degs */ lb[ 1 ] = -AST__DPIBY2; ub[ 1 ] = t; /* Set the longitude range to 0 to 2PI */ lb[ 0 ] = 0; ub[ 0 ] = 2*AST__DPI; } /* Return the modified limits. */ lbnd[ 0 ] = lb[ perm[ 0 ] ]; lbnd[ 1 ] = lb[ perm[ 1 ] ]; ubnd[ 0 ] = ub[ perm[ 0 ] ]; ubnd[ 1 ] = ub[ perm[ 1 ] ]; } } static void Offset( AstFrame *this_frame, const double point1[], const double point2[], double offset, double point3[], int *status ) { /* * Name: * Offset * Purpose: * Calculate an offset along a geodesic curve. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Offset( AstFrame *this, * const double point1[], const double point2[], * double offset, double point3[], int *status ) * Class Membership: * SkyFrame member function (over-rides the astOffset method * inherited from the Frame class). * Description: * This function finds the SkyFrame coordinate values of a point * which is offset a specified distance along the geodesic curve * (i.e. great circle) between two other points. * Parameters: * this * Pointer to the SkyFrame. * point1 * An array of double, with one element for each SkyFrame axis. * This should contain the coordinates of the point marking the * start of the geodesic curve. * point2 * An array of double, with one element for each SkyFrame axis. * This should contain the coordinates of the point marking the * end of the geodesic curve. * offset * The required offset from the first point along the geodesic * curve, in radians. If this is positive, it will be towards * the second point. If it is negative, it will be in the * opposite direction. This offset need not imply a position * lying between the two points given, as the curve will be * extrapolated if necessary. * point3 * An array of double, with one element for each SkyFrame axis * in which the coordinates of the required point will be * returned. * status * Pointer to the inherited status variable. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. * - "Bad" coordinate values will also be returned if the two * points supplied are coincident (or otherwise fail to uniquely * specify a geodesic curve) but the requested offset is non-zero. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Pointer to axis permutation array */ double mrot[ 3 ][ 3 ]; /* Rotation matrix */ double p1[ 2 ]; /* Permuted coordinates for point1 */ double p2[ 2 ]; /* Permuted coordinates for point2 */ double p3[ 2 ]; /* Permuted coordinates for point3 */ double scale; /* Scale factor */ double v1[ 3 ]; /* 3-vector for p1 */ double v2[ 3 ]; /* 3-vector for p2 */ double v3[ 3 ]; /* 3-vector for p3 */ double vmod; /* Modulus of vector */ double vrot[ 3 ]; /* Vector along rotation axis */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Check that all supplied coordinates are OK. If not, generate "bad" output coordinates. */ if ( ( point1[ 0 ] == AST__BAD ) || ( point1[ 1 ] == AST__BAD ) || ( point2[ 0 ] == AST__BAD ) || ( point2[ 1 ] == AST__BAD ) ) { point3[ 0 ] = AST__BAD; point3[ 1 ] = AST__BAD; /* Otherwise, apply the axis permutation array to obtain the coordinates of the two input points in the required (longitude,latitude) order. */ } else { p1[ perm[ 0 ] ] = point1[ 0 ]; p1[ perm[ 1 ] ] = point1[ 1 ]; p2[ perm[ 0 ] ] = point2[ 0 ]; p2[ perm[ 1 ] ] = point2[ 1 ]; /* Convert each point into a 3-vector of unit length. */ palDcs2c( p1[ 0 ], p1[ 1 ], v1 ); palDcs2c( p2[ 0 ], p2[ 1 ], v2 ); /* Find the cross product between these two vectors (the vector order is reversed here to compensate for the sense of rotation introduced by palDav2m and palDmxv below). */ palDvxv( v2, v1, v3 ); /* Normalise the cross product vector, also obtaining its original modulus. */ palDvn( v3, vrot, &vmod ); /* If the original modulus was zero, the input points are either coincident or diametrically opposite, so do not uniquely define a great circle. In either case, we can only generate output coordinates if the offset required is an exact multiple of pi. If it is, generate the 3-vector that results from rotating the first input point through this angle. */ if ( vmod == 0.0 ) { if ( sin( offset ) == 0.0 ) { scale = cos( offset ); v3[ 0 ] = v1[ 0 ] * scale; v3[ 1 ] = v1[ 1 ] * scale; v3[ 2 ] = v1[ 2 ] * scale; /* Convert the 3-vector back into spherical cooordinates and then constrain the longitude result to lie in the range 0 to 2*pi (palDcc2s doesn't do this itself). */ palDcc2s( v3, &p3[ 0 ], &p3[ 1 ] ); p3[ 0 ] = palDranrm( p3[ 0 ] ); /* If the offset was not a multiple of pi, generate "bad" output coordinates. */ } else { p3[ 0 ] = AST__BAD; p3[ 1 ] = AST__BAD; } /* If the two input points define a great circle, scale the normalised cross product vector to make its length equal to the required offset (angle) between the first input point and the result. */ } else { vrot[ 0 ] *= offset; vrot[ 1 ] *= offset; vrot[ 2 ] *= offset; /* Generate the rotation matrix that implements this rotation and use it to rotate the first input point (3-vector) to give the required result (3-vector). */ palDav2m( vrot, mrot ); palDmxv( mrot, v1, v3 ); /* Convert the 3-vector back into spherical cooordinates and then constrain the longitude result to lie in the range 0 to 2*pi. */ palDcc2s( v3, &p3[ 0 ], &p3[ 1 ] ); p3[ 0 ] = palDranrm( p3[ 0 ] ); } /* Permute the result coordinates to undo the effect of the SkyFrame axis permutation array. */ point3[ 0 ] = p3[ perm[ 0 ] ]; point3[ 1 ] = p3[ perm[ 1 ] ]; } } } static AstMapping *SkyOffsetMap( AstSkyFrame *this, int *status ){ /* *++ * Name: c astSkyOffsetMap f AST_SKYOFFSETMAP * Purpose: * Returns a Mapping which goes from absolute coordinates to offset * coordinates. * Type: * Public virtual function. * Synopsis: c #include "skyframe.h" c AstMapping *astSkyOffsetMap( AstSkyFrame *this ) f RESULT = AST_SKYOFFSETMAP( THIS, STATUS ) * Class Membership: * SkyFrame method. * Description: * This function returns a Mapping in which the forward transformation * transforms a position in the coordinate system given by the System * attribute of the supplied SkyFrame, into the offset coordinate system * specified by the SkyRef, SkyRefP and SkyRefIs attributes of the * supplied SkyFrame. * * A UnitMap is returned if the SkyFrame does not define an offset * coordinate system. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the SkyFrame. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSkyOffsetMap() f AST_SKYOFFSETMAP = INTEGER * Pointer to the returned Mapping. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstCmpMap *map3; /* Partial Mapping. */ AstMapping *result; /* The returned Mapping. */ AstMatrixMap *map1; /* Spherical rotation in 3D cartesian space */ AstSphMap *map2; /* 3D Cartesian to 2D spherical Mapping */ double *vx; /* Pointer to x unit vector. */ double *vy; /* Pointer to y unit vector. */ double *vz; /* Pointer to z unit vector. */ double mat[ 9 ]; /* Spherical rotation matrix */ double vmod; /* Length of vector (+ve) */ double vp[ 3 ]; /* Unit vector representin SkyRefP position. */ int lataxis; /* Index of the latitude axis */ int lonaxis; /* Index of the longitude axis */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Return a UnitMap if the offset coordinate system is not defined. */ if( astGetSkyRefIs( this ) == AST__IGNORED_REF || ( !astTestSkyRef( this, 0 ) && !astTestSkyRef( this, 1 ) ) ) { result = (AstMapping *) astUnitMap( 2, "", status ); /* Otherwise... */ } else { /* Get the longitude and latitude at the reference point and at a point on the primary meridian. */ lataxis = astGetLatAxis( this ); lonaxis = 1 - lataxis; /* Initialise pointers to the rows of the 3x3 matrix. Each row will be used to store a unit vector. */ vx = mat; vy = mat + 3; vz = mat + 6; /* The following trig converts between (longitude,latitude) and (x,y,z) on a unit sphere, in which (0,0) is at (1,0,0), (0,pi/2) is (0,0,1) and (pi/2,0) is at (0,1,0). */ /* First deal with cases where the SkyRef attribute holds the standard coords at the origin of the offset coordinate system. */ if( astGetSkyRefIs( this ) == AST__ORIGIN_REF ) { /* Convert each point into a 3-vector of unit length. The SkyRef position defines the X axis in the offset coord system. */ palDcs2c( astGetSkyRef( this, lonaxis ), astGetSkyRef( this, lataxis ), vx ); palDcs2c( astGetSkyRefP( this, lonaxis ), astGetSkyRefP( this, lataxis ), vp ); /* The Y axis is perpendicular to both the X axis and the skyrefp position. That is, it is parallel to the cross product of the 2 above vectors.*/ palDvxv( vp, vx, vy ); /* Normalize the y vector. */ palDvn( vy, vy, &vmod ); /* Report an error if the modulus of the vector is zero.*/ if( vmod == 0.0 ) { astError( AST__BADOC, "astConvert(%s): The position specified by the SkyRefP " "attribute is either coincident, with or opposite to, the " "position specified by the SkyRef attribute.", status, astGetClass( this ) ); /* If OK, form the Z axis as the cross product of the x and y axes. */ } else { palDvxv( vx, vy, vz ); } /* Now deal with cases where the SkyRef attribute holds the standard coords at the north pole of the offset coordinate system. */ } else { /* Convert each point into a 3-vector of unit length. The SkyRef position defines the Z axis in the offset coord system. */ palDcs2c( astGetSkyRef( this, lonaxis ), astGetSkyRef( this, lataxis ), vz ); palDcs2c( astGetSkyRefP( this, lonaxis ), astGetSkyRefP( this, lataxis ), vp ); /* The Y axis is perpendicular to both the Z axis and the skyrefp position. That is, it is parallel to the cross product of the 2 above vectors.*/ palDvxv( vz, vp, vy ); /* Normalize the y vector. */ palDvn( vy, vy, &vmod ); /* Report an error if the modulus of the vector is zero.*/ if( vmod == 0.0 ) { astError( AST__BADOC, "astConvert(%s): The position specified by the SkyRefP " "attribute is either coincident, with or opposite to, the " "position specified by the SkyRef attribute.", status, astGetClass( this ) ); /* If OK, form the X axis as the cross product of the y and z axes. */ } else { palDvxv( vy, vz, vx ); } } /* Create a MatrixMap which implements the above spherical rotation. Each row in this matrix represents one of the unit axis vectors found above. */ map1 = astMatrixMap( 3, 3, 0, mat, "", status ); /* Create a 3D cartesian to 2D spherical Mapping. */ map2 = astSphMap( "UnitRadius=1", status ); /* Form a series CmpMap which converts from 2D (long,lat) in the base System to 2D (long,lat) in the offset coordinate system. */ map3 = astCmpMap( map1, map2, 1, "", status ); astInvert( map2 ); result = (AstMapping *) astCmpMap( map2, map3, 1, "", status ); /* Free resources. */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); } /* Annul the returned Mapping if anything has gone wrong. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static double Offset2( AstFrame *this_frame, const double point1[2], double angle, double offset, double point2[2], int *status ) { /* * Name: * Offset2 * Purpose: * Calculate an offset along a geodesic curve at a given bearing. * Type: * Private function. * Synopsis: * #include "skyframe.h" * double Offset2( AstFrame *this_frame, const double point1[2], * double angle, double offset, double point2[2], int *status ) * Class Membership: * SkyFrame member function (over-rides the astOffset2 method * inherited from the Frame class). * Description: * This function finds the SkyFrame coordinate values of a point * which is offset a specified distance along the geodesic curve * (i.e. great circle) at a given angle from a given starting point. * Parameters: * this * Pointer to the SkyFrame. * point1 * An array of double, with one element for each SkyFrame axis. * This should contain the coordinates of the point marking the * start of the geodesic curve. * angle * The angle (in radians) from the positive direction of the second * axis, to the direction of the required position, as seen from * the starting position. Positive rotation is in the sense of * rotation from the positive direction of axis 2 to the positive * direction of axis 1. * offset * The required offset from the first point along the geodesic * curve, in radians. If this is positive, it will be towards * the given angle. If it is negative, it will be in the * opposite direction. * point2 * An array of double, with one element for each SkyFrame axis * in which the coordinates of the required point will be * returned. * status * Pointer to the inherited status variable. * Returned Value: * The direction of the geodesic curve at the end point. That is, the * angle (in radians) between the positive direction of the second * axis and the continuation of the geodesic curve at the requested * end point. Positive rotation is in the sense of rotation from * the positive direction of axis 2 to the positive direction of axis * 1. * Notes: * - The geodesic curve used by this function is the path of * shortest distance between two points, as defined by the * astDistance function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Pointer to axis permutation array */ double p1[ 2 ]; /* Permuted coordinates for point1 */ double p2[ 2 ]; /* Permuted coordinates for point2 */ double result; /* The returned answer */ double cosoff; /* Cosine of offset */ double cosa1; /* Cosine of longitude at start */ double cosb1; /* Cosine of latitude at start */ double pa; /* A position angle measured from north */ double q1[ 3 ]; /* Vector PI/2 away from R4 in meridian of R4 */ double q2[ 3 ]; /* Vector PI/2 away from R4 on equator */ double q3[ 3 ]; /* Vector PI/2 away from R4 on great circle */ double r0[ 3 ]; /* Reference position vector */ double r3[ 3 ]; /* Vector PI/2 away from R0 on great circle */ double sinoff; /* Sine of offset */ double sina1; /* Sine of longitude at start */ double sinb1; /* Sine of latitude at start */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Check that all supplied values are OK. If not, generate "bad" output coordinates. */ if ( ( point1[ 0 ] == AST__BAD ) || ( point1[ 1 ] == AST__BAD ) || ( angle == AST__BAD ) || ( offset == AST__BAD ) ) { point2[ 0 ] = AST__BAD; point2[ 1 ] = AST__BAD; /* Otherwise, apply the axis permutation array to obtain the coordinates of the starting point in the required (longitude,latitude) order. */ } else { p1[ perm[ 0 ] ] = point1[ 0 ]; p1[ perm[ 1 ] ] = point1[ 1 ]; /* If the axes are permuted, convert the supplied angle into a position angle. */ pa = ( perm[ 0 ] == 0 )? angle: piby2 - angle; /* Use Shcal to calculate the required vectors R0 (representing the reference point) and R3 (representing the point which is 90 degrees away from the reference point, along the required great circle). The XY plane defines zero latitude, Z is in the direction of increasing latitude, X is towards zero longitude, and Y is towards longitude 90 degrees. */ Shcal( p1[ 0 ], p1[ 1 ], pa, r0, r3, status ); /* Use Shapp to use R0 and R3 to calculate the new position. */ Shapp( offset, r0, r3, p1[ 0 ], p2, status ); /* Normalize the result. */ astNorm( this, p2 ); /* Create the vector Q1 representing the point in the meridian of the required point which has latitude 90 degrees greater than the required point. */ sina1 = sin( p2[ 0 ] ); cosa1 = cos( p2[ 0 ] ); sinb1 = sin( p2[ 1 ] ); cosb1 = cos( p2[ 1 ] ); q1[ 0 ] = -sinb1*cosa1; q1[ 1 ] = -sinb1*sina1; q1[ 2 ] = cosb1; /* Create the vector Q2 representing the point on the equator (i.e. a latitude of zero), which has a longitude 90 degrees to the west of the required point. */ q2[ 0 ] = -sina1; q2[ 1 ] = cosa1; q2[ 2 ] = 0.0; /* Create the vector Q3 representing the point which is 90 degrees away from the required point, along the required great circle. */ cosoff = cos( offset ); sinoff = sin( offset ); q3[ 0 ] = -sinoff*r0[ 0 ] + cosoff*r3[ 0 ]; q3[ 1 ] = -sinoff*r0[ 1 ] + cosoff*r3[ 1 ]; q3[ 2 ] = -sinoff*r0[ 2 ] + cosoff*r3[ 2 ]; /* Calculate the position angle of the great circle at the required point. */ pa = atan2( palDvdv( q3, q2 ), palDvdv( q3, q1 ) ); /* Convert this from a pa into the required angle. */ result = ( perm[ 0 ] == 0 )? pa: piby2 - pa; /* Ensure that the end angle is in the range 0 to 2*pi. */ result = palDranrm( result ); /* Permute the result coordinates to undo the effect of the SkyFrame axis permutation array. */ point2[ 0 ] = p2[ perm[ 0 ] ]; point2[ 1 ] = p2[ perm[ 1 ] ]; } } /* Return the result. */ return result; } static void Overlay( AstFrame *template, const int *template_axes, AstFrame *result, int *status ) { /* * Name: * Overlay * Purpose: * Overlay the attributes of a template SkyFrame on to another Frame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Overlay( AstFrame *template, const int *template_axes, * AstFrame *result, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astOverlay method * inherited from the Frame class). * Description: * This function overlays attributes of a SkyFrame (the "template") on to * another Frame, so as to over-ride selected attributes of that second * Frame. Normally only those attributes which have been specifically set * in the template will be transferred. This implements a form of * defaulting, in which a Frame acquires attributes from the template, but * retains its original attributes (as the default) if new values have not * previously been explicitly set in the template. * * Note that if the result Frame is a SkyFrame and a change of sky * coordinate system occurs as a result of overlaying its System * attribute, then some of its original attribute values may no * longer be appropriate (e.g. the Title, or attributes describing * its axes). In this case, these will be cleared before overlaying * any new values. * Parameters: * template * Pointer to the template SkyFrame, for which values should have been * explicitly set for any attribute which is to be transferred. * template_axes * Pointer to an array of int, with one element for each axis of the * "result" Frame (see below). For each axis in the result frame, the * corresponding element of this array should contain the (zero-based) * index of the template axis to which it corresponds. This array is used * to establish from which template axis any axis-dependent attributes * should be obtained. * * If any axis in the result Frame is not associated with a template * axis, the corresponding element of this array should be set to -1. * * If a NULL pointer is supplied, the template and result axis * indicies are assumed to be identical. * result * Pointer to the Frame which is to receive the new attribute values. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - In general, if the result Frame is not from the same class as the * template SkyFrame, or from a class derived from it, then attributes may * exist in the template SkyFrame which do not exist in the result Frame. In * this case, these attributes will not be transferred. */ /* Local Variables: */ AstSystemType new_alignsystem;/* Code identifying new alignment coords */ AstSystemType new_system; /* Code identifying new sky cordinates */ AstSystemType old_system; /* Code identifying old sky coordinates */ int axis; /* Loop counter for result SkyFrame axes */ int skyref_changed; /* Has the SkyRef attribute changed? */ int reset_system; /* Was the template System value cleared? */ int skyframe; /* Result Frame is a SkyFrame? */ int tax0; /* Template axis for result axis 0 */ int tax1; /* Template axis for result axis 1 */ /* Check the global error status. */ if ( !astOK ) return; /* Indicate that we do not need to reset the System attribute of the template. */ reset_system = 0; new_system = AST__UNKNOWN; /* If the result Frame is a SkyFrame, we must test to see if overlaying its System attribute will change the type of sky coordinate system it describes. Determine the value of this attribute for the result and template SkyFrames. We also need to do this if either SkyRef attribute would change. */ skyframe = astIsASkyFrame( result ); if ( skyframe ) { old_system = astGetSystem( result ); new_system = astGetSystem( template ); skyref_changed = ( astGetSkyRef( result, 0 ) != astGetSkyRef( template, 0 ) ) || ( astGetSkyRef( result, 1 ) != astGetSkyRef( template, 1 ) ); /* If the coordinate system will change, any value already set for the result SkyFrame's Title will no longer be appropriate, so clear it. */ if ( new_system != old_system || skyref_changed ) { astClearTitle( result ); /* Test if the old and new sky coordinate systems are similar enough to make use of the same axis attribute values (e.g. if they are both equatorial systems, then they can both use the same axis labels, etc.,so long as the SKyRefIs value has not changed). */ if ( IsEquatorial( new_system, status ) != IsEquatorial( old_system, status ) || skyref_changed ) { /* If necessary, clear inappropriate values for all those axis attributes whose access functions are over-ridden by this class (these access functions will then provide suitable defaults appropriate to the new coordinate system instead). */ for ( axis = 0; axis < 2; axis++ ) { astClearAsTime( result, axis ); astClearDirection( result, axis ); astClearFormat( result, axis ); astClearLabel( result, axis ); astClearSymbol( result, axis ); astClearUnit( result, axis ); } } } /* If the result Frame is not a SkyFrame, we must temporarily clear the System and AlignSystem values since the values used by this class are only appropriate to this class. */ } else { if( astTestSystem( template ) ) { new_system = astGetSystem( template ); astClearSystem( template ); new_alignsystem = astGetAlignSystem( template ); astClearAlignSystem( template ); reset_system = 1; } } /* Invoke the parent class astOverlay method to transfer attributes inherited from the parent class. */ (*parent_overlay)( template, template_axes, result, status ); /* Reset the System and AlignSystem values if necessary */ if( reset_system ) { astSetSystem( template, new_system ); astSetAlignSystem( template, new_alignsystem ); } /* Check if the result Frame is a SkyFrame or from a class derived from SkyFrame. If not, we cannot transfer SkyFrame attributes to it as it is insufficiently specialised. In this case simply omit these attributes. */ if ( skyframe && astOK ) { /* Define a macro that tests whether an attribute is set in the template and, if so, transfers its value to the result. */ #define OVERLAY(attr) \ if ( astTest##attr( template ) ) { \ astSet##attr( result, astGet##attr( template ) ); \ } /* Store template axis indices */ if( template_axes ) { tax0 = template_axes[ 0 ]; tax1 = template_axes[ 1 ]; } else { tax0 = 0; tax1 = 1; } /* Define a similar macro that does the same for SkyFrame specific axis attributes. */ #define OVERLAY2(attr) \ if( astTest##attr( template, tax0 ) ) { \ astSet##attr( result, 0, astGet##attr( template, tax0 ) ); \ } \ if( astTest##attr( template, tax1 ) ) { \ astSet##attr( result, 1, astGet##attr( template, tax1 ) ); \ } /* Use the macro to transfer each SkyFrame attribute in turn. */ OVERLAY(Equinox); OVERLAY(Projection); OVERLAY(NegLon); OVERLAY(AlignOffset); OVERLAY(SkyRefIs); OVERLAY2(SkyRef); OVERLAY2(SkyRefP); } /* Undefine macros local to this function. */ #undef OVERLAY #undef OVERLAY2 } static void Resolve( AstFrame *this_frame, const double point1[], const double point2[], const double point3[], double point4[], double *d1, double *d2, int *status ){ /* * Name: * Resolve * Purpose: * Resolve a vector into two orthogonal components * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Resolve( AstFrame *this, const double point1[], * const double point2[], const double point3[], * double point4[], double *d1, double *d2, int *status ) * Class Membership: * SkyFrame member function (over-rides the astResolve method * inherited from the Frame class). * Description: * This function resolves a vector into two perpendicular components. * The vector from point 1 to point 2 is used as the basis vector. * The vector from point 1 to point 3 is resolved into components * parallel and perpendicular to this basis vector. The lengths of the * two components are returned, together with the position of closest * aproach of the basis vector to point 3. * * Each vector is a geodesic curve. For a SkyFrame, these are great * circles on the celestial sphere. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vector to be resolved. * point2 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. * point3 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the vector to be * resolved. * point4 * An array of double, with one element for each Frame axis * in which the coordinates of the point of closest approach of the * basis vector to point 3 will be returned. * d1 * The address of a location at which to return the distance from * point 1 to point 4 (that is, the length of the component parallel * to the basis vector). Positive values are in the same sense as * movement from point 1 to point 2. * d2 * The address of a location at which to return the distance from * point 4 to point 3 (that is, the length of the component * perpendicular to the basis vector). The returned value is always * positive. * status * Pointer to the inherited status variable. * Notes: * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the required * output values are undefined. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ const int *perm; /* Pointer to axis permutation array */ double n1[ 3 ]; /* Unit normal to grt crcl thru p1 and p2 */ double n2[ 3 ]; /* Unit normal to grt crcl thru p3 and p4 */ double p1[ 2 ]; /* Permuted coordinates for point1 */ double p2[ 2 ]; /* Permuted coordinates for point2 */ double p3[ 2 ]; /* Permuted coordinates for point3 */ double p4[ 2 ]; /* Permuted coordinates for point4 */ double v1[ 3 ]; /* 3-vector for p1 */ double v2[ 3 ]; /* 3-vector for p2 */ double v3[ 3 ]; /* 3-vector for p3 */ double v4[ 3 ]; /* 3-vector for p4 */ double v5[ 3 ]; /* 3-vector 90 degs away from p1 */ double vmod; /* Modulus of vector */ double vtemp[ 3 ]; /* Temporary vector workspace */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Store initial bad output values. */ point4[ 0 ] = AST__BAD; point4[ 1 ] = AST__BAD; *d1 = AST__BAD; *d2 = AST__BAD; /* Check that all supplied values are OK. */ if ( ( point1[ 0 ] != AST__BAD ) && ( point1[ 1 ] != AST__BAD ) && ( point2[ 0 ] != AST__BAD ) && ( point2[ 1 ] != AST__BAD ) && ( point3[ 0 ] != AST__BAD ) && ( point3[ 1 ] != AST__BAD ) ) { /* If so, obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); if ( astOK ) { /* Apply the axis permutation array to obtain the coordinates of the three supplied point in the required (longitude,latitude) order. */ p1[ perm[ 0 ] ] = point1[ 0 ]; p1[ perm[ 1 ] ] = point1[ 1 ]; p2[ perm[ 0 ] ] = point2[ 0 ]; p2[ perm[ 1 ] ] = point2[ 1 ]; p3[ perm[ 0 ] ] = point3[ 0 ]; p3[ perm[ 1 ] ] = point3[ 1 ]; /* Convert each point into a 3-vector of unit length. */ palDcs2c( p1[ 0 ], p1[ 1 ], v1 ); palDcs2c( p2[ 0 ], p2[ 1 ], v2 ); palDcs2c( p3[ 0 ], p3[ 1 ], v3 ); /* Find the cross product between the first two vectors, and normalize is. This is the unit normal to the great circle plane defining parallel distance. */ palDvxv( v2, v1, vtemp ); palDvn( vtemp, n1, &vmod ); /* Return with bad values if the normal is undefined (i.e. if the first two vectors are identical or diametrically opposite). */ if( vmod > 0.0 ) { /* Now take the cross product of the normal vector and v1. This gives a point, v5, on the great circle which is 90 degrees away from v1, in the direction of v2. */ palDvxv( v1, n1, v5 ); /* Find the cross product of the outlying point (point 3), and the vector n1 found above, and normalize it. This is the unit normal to the great circle plane defining perpendicular distance. */ palDvxv( v3, n1, vtemp ); palDvn( vtemp, n2, &vmod ); /* Return with bad values if the normal is undefined (i.e. if the outlying point is normal to the great circle defining the basis vector). */ if( vmod > 0.0 ) { /* The point of closest approach, point 4, is the point which is normal to both normal vectors (i.e. the intersection of the two great circles). This is the cross product of n1 and n2. No need to normalize this time since both n1 and n2 are unit vectors, and so v4 will already be a unit vector. */ palDvxv( n1, n2, v4 ); /* The dot product of v4 and v1 is the cos of the parallel distance, d1, whilst the dot product of v4 and v5 is the sin of the parallel distance. Use these to get the parallel distance with the correct sign, in the range -PI to +PI. */ *d1 = atan2( palDvdv( v4, v5 ), palDvdv( v4, v1 ) ); /* The dot product of v4 and v3 is the cos of the perpendicular distance, d2, whilst the dot product of n1 and v3 is the sin of the perpendicular distance. Use these to get the perpendicular distance. */ *d2 = fabs( atan2( palDvdv( v3, n1 ), palDvdv( v3, v4 ) ) ); /* Convert the 3-vector representing the intersection of the two planes back into spherical cooordinates and then constrain the longitude result to lie in the range 0 to 2*pi. */ palDcc2s( v4, &p4[ 0 ], &p4[ 1 ] ); p4[ 0 ] = palDranrm( p4[ 0 ] ); /* Permute the result coordinates to undo the effect of the SkyFrame axis permutation array. */ point4[ 0 ] = p4[ perm[ 0 ] ]; point4[ 1 ] = p4[ perm[ 1 ] ]; } } } } return; } static AstPointSet *ResolvePoints( AstFrame *this_frame, const double point1[], const double point2[], AstPointSet *in, AstPointSet *out, int *status ) { /* * Name: * ResolvePoints * Purpose: * Resolve a set of vectors into orthogonal components * Type: * Private function. * Synopsis: * #include "frame.h" * AstPointSet *astResolvePoints( AstFrame *this, const double point1[], * const double point2[], AstPointSet *in, * AstPointSet *out ) * Class Membership: * SkyFrame member function (over-rides the astResolvePoints method * inherited from the Frame class). * Description: * This function takes a Frame and a set of vectors encapsulated * in a PointSet, and resolves each one into two orthogonal components, * returning these two components in another PointSet. * * This is exactly the same as the public astResolve method, except * that this method allows many vectors to be processed in a single call, * thus reducing the computational cost of overheads of many * individual calls to astResolve. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vectors to be resolved. * point2 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. * in * Pointer to the PointSet holding the ends of the vectors to be * resolved. * out * Pointer to a PointSet which will hold the length of the two * resolved components. A NULL value may also be given, in which * case a new PointSet will be created by this function. * Returned Value: * Pointer to the output (possibly new) PointSet. The first axis will * hold the lengths of the vector components parallel to the basis vector. * These values will be signed (positive values are in the same sense as * movement from point 1 to point 2. The second axis will hold the lengths * of the vector components perpendicular to the basis vector. These * values will be signed only if the Frame is 2-dimensional, in which * case a positive value indicates that rotation from the basis vector * to the tested vector is in the same sense as rotation from the first * to the second axis of the Frame. * Notes: * - The number of coordinate values per point in the input * PointSet must match the number of axes in the supplied Frame. * - If an output PointSet is supplied, it must have space for * sufficient number of points and 2 coordinate values per point. * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * - We assume spherical geometry throughout this function. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ const int *perm; /* Pointer to axis permutation array */ double **ptr_in; /* Pointers to input axis values */ double **ptr_out; /* Pointers to returned axis values */ double *d1; /* Pointer to next parallel component value */ double *d2; /* Pointer to next perpendicular component value */ double *point3x; /* Pointer to next first axis value */ double *point3y; /* Pointer to next second axis value */ double n1[ 3 ]; /* Unit normal to grt crcl thru p1 and p2 */ double n2[ 3 ]; /* Unit normal to grt crcl thru p3 and p4 */ double p1[ 2 ]; /* Permuted coordinates for point1 */ double p2[ 2 ]; /* Permuted coordinates for point2 */ double p3[ 2 ]; /* Permuted coordinates for point3 */ double sign; /* Sign for perpendicular distances */ double v1[ 3 ]; /* 3-vector for p1 */ double v2[ 3 ]; /* 3-vector for p2 */ double v3[ 3 ]; /* 3-vector for p3 */ double v4[ 3 ]; /* 3-vector for p4 */ double v5[ 3 ]; /* 3-vector 90 degs away from p1 */ double vmod; /* Modulus of vector */ double vtemp[ 3 ]; /* Temporary vector workspace */ int ipoint; /* Index of next point */ int ncoord_in; /* Number of input PointSet coordinates */ int ncoord_out; /* Number of coordinates in output PointSet */ int npoint; /* Number of points to transform */ int npoint_out; /* Number of points in output PointSet */ int ok; /* OK to proceed? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Obtain the number of input vectors to resolve and the number of coordinate values per vector. */ npoint = astGetNpoint( in ); ncoord_in = astGetNcoord( in ); /* If OK, check that the number of input coordinates matches the number required by the Frame. Report an error if these numbers do not match. */ if ( astOK && ( ncoord_in != 2 ) ) { astError( AST__NCPIN, "astResolvePoints(%s): Bad number of coordinate " "values (%d) in input %s.", status, astGetClass( this ), ncoord_in, astGetClass( in ) ); astError( AST__NCPIN, "The %s given requires 2 coordinate values for " "each input point.", status, astGetClass( this ) ); } /* If still OK, and a non-NULL pointer has been given for the output PointSet, then obtain the number of points and number of coordinates per point for this PointSet. */ if ( astOK && out ) { npoint_out = astGetNpoint( out ); ncoord_out = astGetNcoord( out ); /* Check that the dimensions of this PointSet are adequate to accommodate the output coordinate values and report an error if they are not. */ if ( astOK ) { if ( npoint_out < npoint ) { astError( AST__NOPTS, "astResolvePoints(%s): Too few points (%d) in " "output %s.", status, astGetClass( this ), npoint_out, astGetClass( out ) ); astError( AST__NOPTS, "The %s needs space to hold %d transformed " "point(s).", status, astGetClass( this ), npoint ); } else if ( ncoord_out < 2 ) { astError( AST__NOCTS, "astResolvePoints(%s): Too few coordinate " "values per point (%d) in output %s.", status, astGetClass( this ), ncoord_out, astGetClass( out ) ); astError( AST__NOCTS, "The %s supplied needs space to store 2 " "coordinate value(s) per transformed point.", status, astGetClass( this ) ); } } } /* If all the validation stages are passed successfully, and a NULL output pointer was given, then create a new PointSet to encapsulate the output coordinate data. */ if ( astOK ) { if ( !out ) { result = astPointSet( npoint, 2, "", status ); /* Otherwise, use the PointSet supplied. */ } else { result = out; } } /* Get pointers to the input and output axis values */ ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Obtain a pointer to the SkyFrame's axis permutation array. */ perm = astGetPerm( this ); /* If the axes have been swapped we need to swap the sign of the returned perpendicular distances. */ sign = ( perm[ 0 ] == 0 ) ? -1.0 : 1.0; /* Check pointers can be used safely */ if( astOK ) { /* Apply the axis permutation array to obtain the coordinates of the two supplied points in the required (longitude,latitude) order. */ p1[ perm[ 0 ] ] = point1[ 0 ]; p1[ perm[ 1 ] ] = point1[ 1 ]; p2[ perm[ 0 ] ] = point2[ 0 ]; p2[ perm[ 1 ] ] = point2[ 1 ]; /* Convert these points into 3-vectors of unit length. */ palDcs2c( p1[ 0 ], p1[ 1 ], v1 ); palDcs2c( p2[ 0 ], p2[ 1 ], v2 ); /* Find the cross product between the vectors, and normalize it. This is the unit normal to the great circle plane defining parallel distance. */ palDvxv( v2, v1, vtemp ); palDvn( vtemp, n1, &vmod ); /* Return with bad values if the normal is undefined (i.e. if the first two vectors are identical or diametrically opposite). */ ok = 0; if( vmod > 0.0 ) { ok = 1; /* Now take the cross product of the normal vector and v1. This gives a point, v5, on the great circle which is 90 degrees away from v1, in the direction of v2. */ palDvxv( v1, n1, v5 ); } /* Store pointers to the first two axis arrays in the returned PointSet. */ d1 = ptr_out[ 0 ]; d2 = ptr_out[ 1 ]; /* Store pointers to the axis values in the supplied PointSet. */ point3x = ptr_in[ 0 ]; point3y = ptr_in[ 1 ]; /* Check supplied values can be used */ if( ok ) { /* Loop round each supplied vector. */ for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++, point3x++, point3y++ ) { /* Store bad output values if either input axis value is bad. */ if( *point3x == AST__BAD || *point3y == AST__BAD ){ *d1 = AST__BAD; *d2 = AST__BAD; /* If both are good... */ } else { /* Apply the axis permutation array to obtain the coordinates in the required (longitude,latitude) order. */ p3[ perm[ 0 ] ] = *point3x; p3[ perm[ 1 ] ] = *point3y; /* Convert into a 3-vector of unit length. */ palDcs2c( p3[ 0 ], p3[ 1 ], v3 ); /* Find the cross product of the outlying point (point 3), and the vector n1 found above, and normalize it. This is the unit normal to the great circle plane defining perpendicular distance. */ palDvxv( v3, n1, vtemp ); palDvn( vtemp, n2, &vmod ); /* Return with bad values if the normal is undefined (i.e. if the outlying point is normal to the great circle defining the basis vector). */ if( vmod <= 0.0 ) { *d1 = AST__BAD; *d2 = AST__BAD; } else { /* The point of closest approach, point 4, is the point which is normal to both normal vectors (i.e. the intersection of the two great circles). This is the cross product of n1 and n2. No need to normalize this time since both n1 and n2 are unit vectors, and so v4 will already be a unit vector. */ palDvxv( n1, n2, v4 ); /* The dot product of v4 and v1 is the cos of the parallel distance, d1, whilst the dot product of v4 and v5 is the sin of the parallel distance. Use these to get the parallel distance with the correct sign, in the range -PI to +PI. */ *d1 = atan2( palDvdv( v4, v5 ), palDvdv( v4, v1 ) ); /* The dot product of v4 and v3 is the cos of the perpendicular distance, d2, whilst the dot product of n1 and v3 is the sin of the perpendicular distance. Use these to get the perpendicular distance. */ *d2 = sign*atan2( palDvdv( v3, n1 ), palDvdv( v3, v4 ) ); } } } /* If supplied values cannot be used, fill the returned PointSet with bad values */ } else { for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) { *d1 = AST__BAD; *d2 = AST__BAD; } } } /* Annul the returned PointSet if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static void SetAsTime( AstSkyFrame *this, int axis, int value, int *status ) { /* * Name: * SetAsTime * Purpose: * Set a value for the AsTime attribute for a SkyFrame's axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetAsTime( AstSkyFrame *this, int axis, int value, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function sets the boolean value of the AsTime attribute for a * specified axis of a SkyFrame. This value indicates whether axis values * should be formatted as times (as opposed to angles) by default. * Parameters: * this * Pointer to the SkyFrame. * axis * Index of the axis for which a value is to be set (zero based). * value * The boolean value to be set. * status * Pointer to the inherited status variable. * Returned Value: * void. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ AstSkyAxis *new_ax; /* Pointer to new SkyAxis object */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astSetAsTime" ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis ); /* Check if the Axis object is a SkyAxis. If not, we will replace it with one. */ if ( !astIsASkyAxis( ax ) ) { /* Create a new SkyAxis and overlay the attributes of the original Axis. */ new_ax = astSkyAxis( "", status ); astAxisOverlay( ax, new_ax ); /* Modify the SkyFrame to use the new Skyaxis and annul the original Axis pointer. Retain a pointer to the new SkyAxis. */ astSetAxis( this, axis, new_ax ); ax = astAnnul( ax ); ax = (AstAxis *) new_ax; } /* Set a value for the Axis AsTime attribute. */ astSetAxisAsTime( ax, value ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * SkyFrame member function (extends the astSetAttrib method inherited from * the Mapping class). * Description: * This function assigns an attribute value for a SkyFrame, the attribute * and its value being specified by means of a string of the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in lower * case with no white space present. The value to the right of the "=" * should be a suitable textual representation of the value to be assigned * and this will be interpreted according to the attribute's data type. * White space surrounding the value is only significant for string * attributes. * Parameters: * this * Pointer to the SkyFrame. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. * Returned Value: * void * Attributes: * As well as those attributes inherited from the parent class, this * function also accepts values for the following additional attributes: * * Equinox (double, read as a string) * Notes: * This protected method is intended to be invoked by the Object astSet * method and makes additional attributes accessible to it. */ /* Local Vaiables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ double dval; /* Floating point attribute value */ double dval1; /* Floating point attribute value */ double dval2; /* Floating point attribute value */ double mjd; /* Modified Julian Date */ int astime; /* Value of AsTime attribute */ int axis; /* Axis index */ int equinox; /* Offset of Equinox attribute value */ int ival; /* Integer attribute value */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ int neglon; /* Display -ve longitudes? */ int ok; /* Can string be used? */ int offset; /* Offset of start of attribute value */ int projection; /* Offset of projection attribute value */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Obtain the length of the setting string. */ len = strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* AsTime(axis). */ /* ------------- */ if ( nc = 0, ( 2 == astSscanf( setting, "astime(%d)= %d %n", &axis, &astime, &nc ) ) && ( nc >= len ) ) { astSetAsTime( this, axis - 1, astime ); /* Equinox. */ /* -------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "equinox=%n%*[^\n]%n", &equinox, &nc ) ) && ( nc >= len ) ) { /* Convert the Equinox value to a Modified Julian Date before use. */ mjd = astReadDateTime( setting + equinox ); if ( astOK ) { astSetEquinox( this, mjd ); /* Report contextual information if the conversion failed. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid equinox value " "\"%s\" given for sky coordinate system.", status, astGetClass( this ), setting + equinox ); } /* NegLon. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "neglon= %d %n", &neglon, &nc ) ) && ( nc >= len ) ) { astSetNegLon( this, neglon ); /* Projection. */ /* ----------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "projection=%n%*[^\n]%n", &projection, &nc ) ) && ( nc >= len ) ) { astSetProjection( this, setting + projection ); /* SkyRef. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "skyref=%n%*[^\n]%n", &offset, &nc ) ) && ( nc >= len ) ) { ok = 0; nc = astUnformat( this, 0, setting + offset, &dval1 ); if( setting[ offset + nc ] == ',' ) { nc++; nc += astUnformat( this, 1, setting + offset + nc, &dval2 ); if( nc == strlen( setting + offset ) ) { astSetSkyRef( this, 0, dval1 ); astSetSkyRef( this, 1, dval2 ); ok = 1; } } if( !ok && astOK ) { astError( AST__BADOC, "astSetAttrib(%s): Invalid axis values string " "\"%.*s\" given for SkyRef attribute.", status, astGetClass( this ), (int) astChrLen( setting + offset ), setting + offset ); } /* SkyRef(axis). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "skyref(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetSkyRef( this, axis - 1, dval ); /* SkyRefIs. */ /* --------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "skyrefis=%n%*[^\n]%n", &offset, &nc ) ) && ( nc >= len ) ) { if( astChrMatch( setting + offset, POLE_STRING ) ) { astSetSkyRefIs( this, AST__POLE_REF ); } else if( astChrMatch( setting + offset, ORIGIN_STRING ) ) { astSetSkyRefIs( this, AST__ORIGIN_REF ); } else if( astChrMatch( setting + offset, IGNORED_STRING ) ) { astSetSkyRefIs( this, AST__IGNORED_REF ); } else if( astOK ) { astError( AST__OPT, "astSet(%s): option '%s' is unknown in '%s'.", status, astGetClass( this ), setting+offset, setting ); } /* SkyRefP. */ /* -------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "skyrefp=%n%*[^\n]%n", &offset, &nc ) ) && ( nc >= len ) ) { ok = 0; nc = astUnformat( this, 0, setting + offset, &dval1 ); if( setting[ offset + nc ] == ',' ) { nc++; nc += astUnformat( this, 1, setting + offset + nc, &dval2 ); if( nc == strlen( setting + offset ) ) { astSetSkyRefP( this, 0, dval1 ); astSetSkyRefP( this, 1, dval2 ); ok = 1; } } if( !ok && astOK ) { astError( AST__BADOC, "astSetAttrib(%s): Invalid axis values string " "\"%.*s\" given for SkyRefP attribute.", status, astGetClass( this ), (int) astChrLen( setting + offset ), setting + offset ); } /* SkyRefP(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "skyrefp(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetSkyRefP( this, axis - 1, dval ); /* AlignOffset. */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "alignoffset= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetAlignOffset( this, ival ); /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* If the attribute was not recognised, use this macro to report an error if a read-only attribute has been specified. */ } else if ( !strncmp( setting, "islataxis", 9 ) || !strncmp( setting, "islonaxis", 9 ) || MATCH( "lataxis" ) || MATCH( "lonaxis" ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Pass any unrecognised setting to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static void SetCachedLAST( AstSkyFrame *this, double last, double epoch, double obslon, double obslat, double obsalt, double dut1, int *status ) { /* * Name: * SetCachedLAST * Purpose: * Store a LAST value in the cache in the SkyFrame vtab. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetCachedLAST( AstSkyFrame *this, double last, double epoch, * double obslon, double obslat, double obsalt, * double dut1, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function stores the supplied LAST value in a cache in the * SkyFrame virtual function table for later use by GetCachedLAST. * Parameters: * this * Pointer to the SkyFrame. * last * The Local Apparent Sidereal Time (radians). * epoch * The epoch (MJD). * obslon * Observatory geodetic longitude (radians) * obslat * Observatory geodetic latitude (radians) * obsalt * Observatory geodetic altitude (metres) * dut1 * The UT1-UTC correction, in seconds. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS AstSkyLastTable *table; double *ep; double *lp; double lp_ref; int i; int itable; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise */ table = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Ensure no threads are allowed to read the table whilst we are writing to it. */ LOCK_WLOCK1 /* Loop round every LAST table held in the vtab. Each table refers to a different observatory position and/or DUT1 value. */ for( itable = 0; itable < nlast_tables; itable++ ) { table = last_tables[ itable ]; /* See if the table refers to the given position and dut1 value, allowing some small tolerance. If it does, leave the loop. */ if( fabs( table->obslat - obslat ) < 2.0E-7 && fabs( table->obslon - obslon ) < 2.0E-7 && fabs( table->obsalt - obsalt ) < 1.0 && fabs( table->dut1 - dut1 ) < 1.0E-5 ) break; /* Ensure "table" ends up NULL if no suitable table is found. */ table = NULL; } /* If no table was found, create one now, and add it into the vtab cache. */ if( !table ) { astBeginPM; table = astMalloc( sizeof( AstSkyLastTable ) ); itable = nlast_tables++; last_tables = astGrow( last_tables, nlast_tables, sizeof( AstSkyLastTable * ) ); astEndPM; if( astOK ) { last_tables[ itable ] = table; table->obslat = obslat; table->obslon = obslon; table->obsalt = obsalt; table->dut1 = dut1; table->nentry = 1; astBeginPM; table->epoch = astMalloc( sizeof( double ) ); table->last = astMalloc( sizeof( double ) ); astEndPM; if( astOK ) { table->epoch[ 0 ] = epoch; table->last[ 0 ] = last; } } /* If we have a table, add the new point into it. */ } else { /* Extend the epoch and last arrays. */ astBeginPM; table->epoch = astGrow( table->epoch, ++(table->nentry), sizeof( double ) ); table->last = astGrow( table->last, table->nentry, sizeof( double ) ); astEndPM; /* Check memory allocation was successful. */ if( astOK ) { /* Get pointers to the last original elements in the arrays of epoch and corresponding LAST values in the table. */ ep = table->epoch + table->nentry - 2; lp = table->last + table->nentry - 2; /* Starting from the end of the arrays, shuffle all entries up one element until an element is found which is less than the supplied epoch value. This maintains the epoch array in monotonic increasing order. */ for( i = table->nentry - 2; i >= 0; i--,ep--,lp-- ) { if( *ep <= epoch ) break; ep[ 1 ] = *ep; lp[ 1 ] = *lp; } /* Store the new epoch and LAST value. Add or subtract 2.PI as needed from the new LAST value to ensure it is continuous with an adjacent LAST value. This is needed for interpolation between the two values to be meaningful. */ ep[ 1 ] = epoch; /* For most cases, compare with the previous LAST value. If the new epoch value is smaller than any epoch already in the table, there will be no previous LAST value. So compare with the next value instead. */ if( i >= 0 ) { lp_ref = lp[ 0 ]; } else { lp_ref = lp[ 2 ]; } if( last > lp_ref + AST__DPI ) { lp[ 1 ] = last - 2*AST__DPI; } else if( last < lp_ref - AST__DPI ) { lp[ 1 ] = last + 2*AST__DPI; } else { lp[ 1 ] = last; } } } /* Indicate other threads are now allowed to read the table. */ UNLOCK_RWLOCK1 } static void SetDut1( AstFrame *this_frame, double val, int *status ) { /* * Name: * SetDut1 * Purpose: * Set the value of the Dut1 attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetDut1( AstFrame *this, double val, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSetDut1 method * inherited from the Frame class). * Description: * This function clears the Dut1 value and updates the LAST value * stored in the SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * val * New Dut1 value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSkyFrame *this; double orig; /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Note the original Dut1 value. */ orig = astGetDut1( this ); /* Invoke the parent method to set the Frame Dut1 value. */ (*parent_setdut1)( this_frame, val, status ); /* If the DUT1 value has changed significantly, indicate that the LAST value will need to be re-calculated when it is next needed. */ if( fabs( orig - val ) > 1.0E-6 ) { this->last = AST__BAD; this->eplast = AST__BAD; this->klast = AST__BAD; } } static void SetLast( AstSkyFrame *this, int *status ) { /* * Name: * SetLast * Purpose: * Set the Local Appearent Sidereal Time for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetLast( AstSkyFrame *this, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function sets the Local Apparent Sidereal Time at the epoch * and geographical longitude given by the current values of the Epoch * and ObsLon attributes associated with the supplied SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Notes: * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ double epoch; /* Epoch as a TDB MJD */ /* Check the global error status. */ if ( !astOK ) return; /* Get the SkyFrame Epoch as a TDB MJD. */ epoch = astGetEpoch( this ); /* Calculate the LAST value (in rads) and store in the SkyFrame structure. */ this->last = CalcLAST( this, epoch, astGetObsLon( this ), astGetObsLat( this ), astGetObsAlt( this ), astGetDut1( this ), status ); /* Save the TDB MJD to which this LAST corresponds. */ this->eplast = epoch; /* The ratio between solar and sidereal time is a slowly varying function of epoch. The GetLAST function returns a fast approximation to LAST by using the ratio between solar and sidereal time. Indicate that GetLAST should re-calculate the ratio by setting the ratio value bad. */ this->klast = AST__BAD; } static void SetObsAlt( AstFrame *this, double val, int *status ) { /* * Name: * SetObsAlt * Purpose: * Set the value of the ObsAlt attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetObsAlt( AstFrame *this, double val, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSetObsAlt method * inherited from the Frame class). * Description: * This function sets the ObsAlt value. * Parameters: * this * Pointer to the SkyFrame. * val * New ObsAlt value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original ObsAlt value. */ orig = astGetObsAlt( this ); /* Invoke the parent method to set the Frame ObsAlt. */ (*parent_setobsalt)( this, val, status ); /* If the altitude has changed significantly, indicate that the LAST value and magnitude of the diurnal aberration vector will need to be re-calculated when next needed. */ if( fabs( orig - val ) > 0.001 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; ( (AstSkyFrame *) this )->diurab = AST__BAD; } } static void SetObsLat( AstFrame *this, double val, int *status ) { /* * Name: * SetObsLat * Purpose: * Set the value of the ObsLat attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetObsLat( AstFrame *this, double val, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSetObsLat method * inherited from the Frame class). * Description: * This function sets the ObsLat value. * Parameters: * this * Pointer to the SkyFrame. * val * New ObsLat value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original ObsLat value. */ orig = astGetObsLat( this ); /* Invoke the parent method to set the Frame ObsLat. */ (*parent_setobslat)( this, val, status ); /* If the altitude has changed significantly, indicate that the LAST value and magnitude of the diurnal aberration vector will need to be re-calculated when next needed. */ if( fabs( orig - val ) > 1.0E-8 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; ( (AstSkyFrame *) this )->diurab = AST__BAD; } } static void SetObsLon( AstFrame *this, double val, int *status ) { /* * Name: * SetObsLon * Purpose: * Set the value of the ObsLon attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetObsLon( AstFrame *this, double val, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSetObsLon method * inherited from the Frame class). * Description: * This function sets the ObsLon value. * Parameters: * this * Pointer to the SkyFrame. * val * New ObsLon value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double orig; /* Check the global error status. */ if ( !astOK ) return; /* Note the original ObsLon value. */ orig = astGetObsLon( this ); /* Invoke the parent method to set the Frame ObsLon. */ (*parent_setobslon)( this, val, status ); /* If the longitude has changed significantly, indicate that the LAST value will need to be re-calculated when it is next needed. */ if( fabs( orig - val ) > 1.0E-8 ) { ( (AstSkyFrame *) this )->last = AST__BAD; ( (AstSkyFrame *) this )->eplast = AST__BAD; ( (AstSkyFrame *) this )->klast = AST__BAD; } } static void SetSystem( AstFrame *this_frame, AstSystemType system, int *status ) { /* * Name: * SetSystem * Purpose: * Set the System attribute for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void SetSystem( AstFrame *this_frame, AstSystemType system, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSetSystem protected * method inherited from the Frame class). * Description: * This function assigns a new value to the System attribute for a SkyFrame. * Parameters: * this * Pointer to the SkyFrame. * system * The new System value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrameSet *fs; /* FrameSet to be used as the Mapping */ AstSkyFrame *sfrm; /* Copy of original SkyFrame */ AstSkyFrame *this; /* Pointer to SkyFrame structure */ double xin[ 2 ]; /* Axis 0 values */ double xout[ 2 ]; /* Axis 0 values */ double yin[ 2 ]; /* Axis 1 values */ double yout[ 2 ]; /* Axis 1 values */ int aloff; /* The AlignOffset attribute value */ int aloff_set; /* Is the AlignOffset attribute set? */ int skyref_set; /* Is either SkyRef attribute set? */ int skyrefis; /* The SkyRefIs attribute value */ int skyrefis_set; /* Is the SkyRefIs attribute set? */ int skyrefp_set; /* Is either SkyRefP attribute set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* See if either the SkyRef or SkyRefP attribute is set. */ skyref_set = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ); skyrefp_set = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 ); /* If so, we will need to transform their values into the new coordinate system. Save a copy of the SkyFrame with its original System value. */ sfrm = ( skyref_set || skyrefp_set )?astCopy( this ):NULL; /* Use the parent method to set the new System value. */ (*parent_setsystem)( this_frame, system, status ); /* Now modify the SkyRef and SkyRefP attributes if necessary. */ if( sfrm ) { /* Save the AlignOffset, SkyRefIs, SkyRef and SkyRefP values. */ aloff_set = astTestAlignOffset( sfrm ); aloff = astGetAlignOffset( sfrm ); skyrefis_set = astTestSkyRefIs( sfrm ); skyrefis = astGetSkyRefIs( sfrm ); xin[ 0 ] = astGetSkyRef( sfrm, 0 ); xin[ 1 ] = astGetSkyRefP( sfrm, 0 ); yin[ 0 ] = astGetSkyRef( sfrm, 1 ); yin[ 1 ] = astGetSkyRefP( sfrm, 1 ); /* Clear the SkyRef and SkyRefP values to avoid infinite recursion in the following call to astConvert. */ if( skyref_set ) { astClearSkyRef( sfrm, 0 ); astClearSkyRef( sfrm, 1 ); astClearSkyRef( this, 0 ); astClearSkyRef( this, 1 ); } if( skyrefp_set ) { astClearSkyRefP( sfrm, 0 ); astClearSkyRefP( sfrm, 1 ); astClearSkyRefP( this, 0 ); astClearSkyRefP( this, 1 ); } /* Also set AlignOffset and SkyRefIs so that the following call to astConvert does not align in offset coords. */ astSetAlignOffset( sfrm, 0 ); astSetSkyRefIs( sfrm, AST__IGNORED_REF ); /* Get the Mapping from the original System to the new System. Invoking astConvert will recursively invoke SetSystem again. This is why we need to be careful to ensure that SkyRef and SKyRefP are cleared above - doing so ensure we do not end up with infinite recursion. */ fs = astConvert( sfrm, this, "" ); /* If the conversion is not possible, clear the SkyRef and SkyRefP values. */ if( !fs ) { if( skyref_set ) { astClearSkyRef( this, 0 ); astClearSkyRef( this, 1 ); } if( skyrefp_set ) { astClearSkyRefP( this, 0 ); astClearSkyRefP( this, 1 ); } /* Use the Mapping to find the SkyRef and SkyRefP positions in the new coordinate system. */ } else { astTran2( fs, 2, xin, yin, 1, xout, yout ); /* Store the values as required. */ if( skyref_set ) { astSetSkyRef( this, 0, xout[ 0 ] ); astSetSkyRef( this, 1, yout[ 0 ] ); } if( skyrefp_set ) { astSetSkyRefP( this, 0, xout[ 1 ] ); astSetSkyRefP( this, 1, yout[ 1 ] ); } /* Restore the original SkyRefIs and AlignOffset values. */ if( aloff_set ) { astSetAlignOffset( this, aloff ); } else { astClearAlignOffset( this ); } if( skyrefis_set ) { astSetSkyRefIs( this, skyrefis ); } else { astClearSkyRefIs( this ); } /* Free resources. */ fs = astAnnul( fs ); } sfrm = astAnnul( sfrm ); } } static void Shapp( double dist, double *r0, double *r3, double a0, double *p4, int *status ){ /* * Name: * Shapp * Purpose: * Use the vectors calculated by Shcal to find a sky position * which is offset along a given position angle. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Shapp( double dist, double *r0, double *r3, double a0, * double *p4, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function uses the vectors R0 and R3 calculated previously by * Shcal to find the sky position which is offset away from the * "reference" position (see function Offset2) by a given arc * distance, along a given great circle. * * No checks are made for AST__BAD values. * Parameters: * dist * The arc distance to move away from the reference position * in the given direction, in radians. * r0 * Pointer to an array holding the 3-vector representing the reference * position. * r3 * Pointer to an array holding the 3-vector representing the * point which is 90 degrees away from the reference point, along * the required great circle. * a0 * The sky longitude of the reference position, in radians. * p4 * Pointer to an array of 2 doubles in which to put the sky longitude * and latitude of the required point, in radians. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double cosdst; /* Cosine of DIST */ double r4[ 3 ]; /* Required position vector */ double sindst; /* Sine of DIST */ /* Check the global error status. */ if ( !astOK ) return; /* Store commonly used values. */ sindst = sin( dist ); cosdst = cos( dist ); /* The vector R4 representing the required point is produced as a linear sum of R0 and R3. */ r4[ 0 ] = cosdst*r0[ 0 ] + sindst*r3[ 0 ]; r4[ 1 ] = cosdst*r0[ 1 ] + sindst*r3[ 1 ]; r4[ 2 ] = cosdst*r0[ 2 ] + sindst*r3[ 2 ]; /* Create the longitude of the required point. If this point is at a pole it is assigned the same longitude as the reference point. */ if( r4[ 0 ] != 0.0 || r4[ 1 ] != 0.0 ) { p4[ 0 ] = atan2( r4[ 1 ], r4[ 0 ] ); } else { p4[ 0 ] = a0; } /* Create the latitude of the required point. */ if( r4[ 2 ] > 1.0 ) { r4[ 2 ] = 1.0; } else if( r4[ 2 ] < -1.0 ) { r4[ 2 ] = -1.0; } p4[ 1 ] = asin( r4[ 2 ] ); } static void Shcal( double a0, double b0, double angle, double *r0, double *r3, int *status ) { /* * Name: * Shcal * Purpose: * Calculate vectors required by Offset2. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void Shcal( double a0, double b0, double angle, double *r0, * double *r3, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function calculates the 3-vector R0, representing the given * sky position (A0,B0), and the 3-vector R3, representing the sky * position which is 90 degrees away from R0, along a great circle * passing through R0 at a position angle given by ANGLE. Each * 3-vector holds Cartesian (X,Y,Z) values with origin at the centre * of the celestial sphere. The XY plane is the "equator", the Z * axis is in the direction of the "north pole", X is towards zero * longitude (A=0), and Y is towards longitude 90 degrees. * * No checks are made for AST__BAD input values. * Parameters: * a0 * The sky longitude of the given position, in radians. * b0 * The sky latitude of the given position, in radians. * angle * The position angle of a great circle passing through the given * position. That is, the angle from north to the required * direction, in radians. Positive angles are in the sense of * rotation from north to east. * r0 * A pointer to an array to receive 3-vector R0. See above. * r3 * A pointer to an array to receive 3-vector R3. See above. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double cosa0; /* Cosine of A0 */ double cosb0; /* Cosine of B0 */ double cospa; /* Cosine of ANGLE */ double r1[ 3 ]; /* Vector PI/2 away from R0 in meridian of R0 */ double r2[ 3 ]; /* Vector PI/2 away from R0 on equator */ double sinpa; /* Sine of ANGLE */ double sina0; /* Sine of A0 */ double sinb0; /* Sine of B0 */ /* Check the global error status. */ if ( !astOK ) return; /* Store commonly used values. */ sina0 = sin( a0 ); cosa0 = cos( a0 ); sinb0 = sin( b0 ); cosb0 = cos( b0 ); sinpa = sin( angle ); cospa = cos( angle ); /* Create the vector R0 representing the given point. The XY plane defines zero latitude, Z is in the direction of increasing latitude, X is towards zero longitude, and Y is towards longitude 90 degrees. */ r0[ 0 ] = cosb0*cosa0; r0[ 1 ] = cosb0*sina0; r0[ 2 ] = sinb0; /* Create the vector R1 representing the point in the meridian of the given point which has latitude 90 degrees greater than the given point. */ r1[ 0 ] = -sinb0*cosa0; r1[ 1 ] = -sinb0*sina0; r1[ 2 ] = cosb0; /* Create the vector R2 representing the point on the equator (i.e. a latitude of zero), which has a longitude 90 degrees to the west of the given point. */ r2[ 0 ] = -sina0; r2[ 1 ] = cosa0; r2[ 2 ] = 0.0; /* Create the vector R3 representing the point which is 90 degrees away from the given point, along the required great circle. */ r3[ 0 ] = cospa*r1[ 0 ] + sinpa*r2[ 0 ]; r3[ 1 ] = cospa*r1[ 1 ] + sinpa*r2[ 1 ]; r3[ 2 ] = cospa*r1[ 2 ] + sinpa*r2[ 2 ]; /* Return */ return; } static int SubFrame( AstFrame *target_frame, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * SubFrame * Purpose: * Select axes from a SkyFrame and convert to the new coordinate system. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int SubFrame( AstFrame *target, AstFrame *template, * int result_naxes, const int *target_axes, * const int *template_axes, AstMapping **map, * AstFrame **result, int *status ) * Class Membership: * SkyFrame member function (over-rides the protected astSubFrame method * inherited from the Frame class). * Description: * This function selects a requested sub-set (or super-set) of the axes from * a "target" SkyFrame and creates a new Frame with copies of the selected * axes assembled in the requested order. It then optionally overlays the * attributes of a "template" Frame on to the result. It returns both the * resulting Frame and a Mapping that describes how to convert between the * coordinate systems described by the target and result Frames. If * necessary, this Mapping takes account of any differences in the Frames' * attributes due to the influence of the template. * Parameters: * target * Pointer to the target SkyFrame, from which axes are to be selected. * template * Pointer to the template Frame, from which new attributes for the * result Frame are to be obtained. Optionally, this may be NULL, in * which case no overlaying of template attributes will be performed. * result_naxes * Number of axes to be selected from the target Frame. This number may * be greater than or less than the number of axes in this Frame (or * equal). * target_axes * Pointer to an array of int with result_naxes elements, giving a list * of the (zero-based) axis indices of the axes to be selected from the * target SkyFrame. The order in which these are given determines the * order in which the axes appear in the result Frame. If any of the * values in this array is set to -1, the corresponding result axis will * not be derived from the target Frame, but will be assigned default * attributes instead. * template_axes * Pointer to an array of int with result_naxes elements. This should * contain a list of the template axes (given as zero-based axis indices) * with which the axes of the result Frame are to be associated. This * array determines which axes are used when overlaying axis-dependent * attributes of the template on to the result. If any element of this * array is set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not used and * a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned Mapping. * The forward transformation of this Mapping will describe how to * convert coordinates from the coordinate system described by the target * SkyFrame to that described by the result Frame. The inverse * transformation will convert in the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if coordinate conversion is possible * between the target and the result Frame. Otherwise zero is returned and * *map and *result are returned as NULL (but this will not in itself * result in an error condition). In general, coordinate conversion should * always be possible if no template Frame is supplied but may not always * be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * - This implementation addresses the selection of axes from a SkyFrame * object. This results in another object of the same class only if both * axes of the SkyFrame are selected, once each. Otherwise, the result is a * Frame class object which inherits the SkyFrame's axis information (if * appropriate) but none of the other properties of a SkyFrame. * - In the event that a SkyFrame results, the returned Mapping will take * proper account of the relationship between the target and result sky * coordinate systems. * - In the event that a Frame class object results, the returned Mapping * will only represent a selection/permutation of axes. * Implementation Deficiencies: * - Any axis selection is currently permitted. Probably this should be * restricted so that each axis can only be selected once. The * astValidateAxisSelection method will do this but currently there are bugs * in the CmpFrame class that cause axis selections which will not pass this * test. Install the validation when these are fixed. */ /* Local Variables: */ AstAxis *ax; /* Pointer to result Frame Axis object */ AstMapping *tmpmap; /* Temporary Mapping pointer */ AstPermMap *permmap; /* Pointer to PermMap */ AstSkyFrame *target; /* Pointer to the SkyFrame structure */ AstSkyFrame *temp; /* Pointer to copy of target SkyFrame */ AstSystemType align_sys; /* System in which to align the SkyFrames */ int match; /* Coordinate conversion is possible? */ int perm[ 2 ]; /* Permutation array for axis swap */ int result_swap; /* Swap result SkyFrame coordinates? */ int set_usedefs; /* Set the returned UseDefs attribute zero?*/ int target_axis; /* Target SkyFrame axis index */ int target_swap; /* Swap target SkyFrame coordinates? */ /* Initialise the returned values. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain a pointer to the target SkyFrame structure. */ target = (AstSkyFrame *) target_frame; /* Result is a SkyFrame. */ /* --------------------- */ /* Check if the result Frame is to have two axes obtained by selecting both of the target SkyFrame axes, in either order. If so, the result will also be a SkyFrame. */ if ( ( result_naxes == 2 ) && ( ( ( target_axes[ 0 ] == 0 ) && ( target_axes[ 1 ] == 1 ) ) || ( ( target_axes[ 0 ] == 1 ) && ( target_axes[ 1 ] == 0 ) ) ) ) { /* If a template has not been supplied, or is the same object as the target, we are simply extracting axes from the supplied SkyFrame. In this case we temporarily force the UseDefs attribute to 1 so that (for instance) the astPickAxes method can function correctly. E.g. if you have a SkyFrame with no set Epoch and UseDefs set zero, and you try to swap the axes, the attempt would fail because MakeSkyMapping would be unable to determine the Mapping from original to swapped SkyFrame, because of the lack of an Epoch value. */ set_usedefs = 0; if( !template || template == target_frame ) { if( !astGetUseDefs( target ) ) { astClearUseDefs( target ); set_usedefs = 1; } } /* Form the result from a copy of the target and then permute its axes into the order required. */ *result = astCopy( target ); astPermAxes( *result, target_axes ); /* If required, overlay the template attributes on to the result SkyFrame. Also get the system in which to align the two SkyFrames. This is the value of the AlignSystem attribute from the template (if there is a template). */ if ( template ) { astOverlay( template, template_axes, *result ); align_sys = astGetAlignSystem( template ); } else { align_sys = astGetAlignSystem( target ); } /* See whether alignment occurs in offset coordinates or absolute coordinates. If the current call to this function is part of the process of restoring a FrameSet's integrity following changes to the FrameSet's current Frame, then we ignore the setting of the AlignOffset attributes and use 0. This ensures that when the System attribute (for instance) is changed via a FrameSet pointer, the Mappings within the FrameSet are modified to produce offsets in the new System. If we are not currently restoring a FrameSet's integrity, then we align in offsets if the template is a SkyFrame and both template and target want alignment to occur in the offset coordinate system. In this case we use a UnitMap to connect them. */ if( ( astGetFrameFlags( target_frame ) & AST__INTFLAG ) == 0 ) { if( astGetAlignOffset( target ) && astGetSkyRefIs( target ) != AST__IGNORED_REF && template && astIsASkyFrame( template ) ){ if( astGetAlignOffset( (AstSkyFrame *) template ) && astGetSkyRefIs( (AstSkyFrame *) template ) != AST__IGNORED_REF ) { match = 1; *map = (AstMapping *) astUnitMap( 2, "", status ); } } } /* Otherwise, generate a Mapping that takes account of changes in the sky coordinate system (equinox, epoch, etc.) between the target SkyFrame and the result SkyFrame. If this Mapping can be generated, set "match" to indicate that coordinate conversion is possible. */ if( ! *map ) { match = ( MakeSkyMapping( target, (AstSkyFrame *) *result, align_sys, map, status ) != 0 ); } /* If required, re-instate the original zero value of UseDefs. */ if( set_usedefs ) { astSetUseDefs( target, 0 ); astSetUseDefs( *result, 0 ); } /* If a Mapping has been obtained, it will expect coordinate values to be supplied in (longitude,latitude) pairs. Test whether we need to swap the order of the target SkyFrame coordinates to conform with this. */ if ( astOK && match ) { target_swap = ( astValidateAxis( target, 0, 1, "astSubFrame" ) != 0 ); /* Coordinates will also be delivered in (longitude,latitude) pairs, so check to see whether the result SkyFrame coordinate order should be swapped. */ result_swap = ( target_swap != ( target_axes[ 0 ] != 0 ) ); /* If either set of coordinates needs swapping, create a PermMap that will swap a pair of coordinates. */ permmap = NULL; if ( target_swap || result_swap ) { perm[ 0 ] = 1; perm[ 1 ] = 0; permmap = astPermMap( 2, perm, 2, perm, NULL, "", status ); } /* If necessary, prefix this PermMap to the main Mapping. */ if ( target_swap ) { tmpmap = (AstMapping *) astCmpMap( permmap, *map, 1, "", status ); *map = astAnnul( *map ); *map = tmpmap; } /* Also, if necessary, append it to the main Mapping. */ if ( result_swap ) { tmpmap = (AstMapping *) astCmpMap( *map, permmap, 1, "", status ); *map = astAnnul( *map ); *map = tmpmap; } /* Annul the pointer to the PermMap (if created). */ if ( permmap ) permmap = astAnnul( permmap ); } /* Result is not a SkyFrame. */ /* ------------------------- */ /* In this case, we select axes as if the target were from the Frame class. However, since the resulting data will then be separated from their enclosing SkyFrame, default attribute values may differ if the methods for obtaining them were over-ridden by the SkyFrame class. To overcome this, we ensure that these values are explicitly set for the result Frame (rather than relying on their defaults). */ } else { /* Make a temporary copy of the target SkyFrame. We will explicitly set the attribute values in this copy so as not to modify the original. */ temp = astCopy( target ); /* Define a macro to test if an attribute is set. If not, set it explicitly to its default value. */ #define SET(attribute) \ if ( !astTest##attribute( temp ) ) { \ astSet##attribute( temp, astGet##attribute( temp ) ); \ } /* Set attribute values which apply to the Frame as a whole and which we want to retain, but whose defaults are over-ridden by the SkyFrame class. */ SET(Domain) SET(Title) /* Now loop to set explicit attribute values for each axis. */ for ( target_axis = 0; target_axis < 2; target_axis++ ) { /* Define a macro to test if an axis attribute is set. If not, set it explicitly to its default value. */ #define SET_AXIS(attribute) \ if ( !astTest##attribute( temp, target_axis ) ) { \ astSet##attribute( temp, target_axis, \ astGet##attribute( temp, target_axis ) ); \ } /* Use this macro to set explicit values for all the axis attributes for which the SkyFrame class over-rides the default value. */ SET_AXIS(AsTime) SET_AXIS(Format) SET_AXIS(Label) SET_AXIS(Symbol) SET_AXIS(Unit) /* Now handle axis attributes for which there are no SkyFrame access methods. For these we require a pointer to the temporary SkyFrame's Axis object. */ ax = astGetAxis( temp, target_axis ); /* Set an explicit value for the IsLatitude and CentreZero attributes. */ if( astValidateAxis( temp, target_axis, 1, "astSubFrame" ) == 1 ) { astSetAxisIsLatitude( ax, 1 ); astSetAxisCentreZero( ax, 1 ); } else { astSetAxisIsLatitude( ax, 0 ); astSetAxisCentreZero( ax, astGetNegLon( temp ) ); } /* Annul the Axis object pointer. */ ax = astAnnul( ax ); } /* Clear attributes which have an extended range of values allowed by this class. */ astClearSystem( temp ); astClearAlignSystem( temp ); /* Invoke the astSubFrame method inherited from the Frame class to produce the result Frame by selecting the required set of axes and overlaying the template Frame's attributes. */ match = (*parent_subframe)( (AstFrame *) temp, template, result_naxes, target_axes, template_axes, map, result, status ); /* Delete the temporary copy of the target SkyFrame. */ temp = astDelete( temp ); } /* Ensure the returned Frame does not have active units. */ astSetActiveUnit( *result, 0 ); /* If an error occurred or no match was found, annul the returned objects and reset the returned result. */ if ( !astOK || !match ) { if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; /* Undefine macros local to this function. */ #undef SET #undef SET_AXIS } static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) { /* * Name: * SystemCode * Purpose: * Convert a string into a coordinate system type code. * Type: * Private function. * Synopsis: * #include "skyframe.h" * AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSystemCode method * inherited from the Frame class). * Description: * This function converts a string used for the external * description of a sky coordinate system into a SkyFrame * coordinate system type code (System attribute value). It is the * inverse of the astSystemString function. * Parameters: * this * The Frame. * system * Pointer to a constant null-terminated string containing the * external description of the sky coordinate system. * status * Pointer to the inherited status variable. * Returned Value: * The System type code. * Notes: * - A value of AST__BADSYSTEM is returned if the sky coordinate * system description was not recognised. This does not produce an * error. * - A value of AST__BADSYSTEM is also returned if this function * is invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ AstSystemType result; /* Result value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" string against each possibility and assign the result. */ if ( astChrMatch( "FK4", system ) ) { result = AST__FK4; } else if ( astChrMatch( "FK4_NO_E", system ) || astChrMatch( "FK4-NO-E", system ) ) { result = AST__FK4_NO_E; } else if ( astChrMatch( "FK5", system ) || astChrMatch( "Equatorial", system ) ) { result = AST__FK5; } else if ( astChrMatch( "J2000", system ) ) { result = AST__J2000; } else if ( astChrMatch( "ICRS", system ) ) { result = AST__ICRS; } else if ( astChrMatch( "AZEL", system ) ) { result = AST__AZEL; } else if ( astChrMatch( "GAPPT", system ) || astChrMatch( "GEOCENTRIC", system ) || astChrMatch( "APPARENT", system ) ) { result = AST__GAPPT; } else if ( astChrMatch( "ECLIPTIC", system ) ) { result = AST__ECLIPTIC; } else if ( astChrMatch( "HELIOECLIPTIC", system ) ) { result = AST__HELIOECLIPTIC; } else if ( astChrMatch( "GALACTIC", system ) ) { result = AST__GALACTIC; } else if ( astChrMatch( "SUPERGALACTIC", system ) ) { result = AST__SUPERGALACTIC; } else if ( astChrMatch( "UNKNOWN", system ) ) { result = AST__UNKNOWN; } /* Return the result. */ return result; } static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) { /* * Name: * SystemString * Purpose: * Convert a coordinate system type code into a string. * Type: * Private function. * Synopsis: * #include "skyframe.h" * const char *SystemString( AstFrame *this, AstSystemType system, int *status ) * Class Membership: * SkyFrame member function (over-rides the astSystemString method * inherited from the Frame class). * Description: * This function converts a SkyFrame coordinate system type code * (System attribute value) into a string suitable for use as an * external representation of the coordinate system type. * Parameters: * this * The Frame. * system * The coordinate system type code. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the sky coordinate system * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" value against each possibility and convert to a string pointer. (Where possible, return the same string as would be used in the FITS WCS representation of the coordinate system). */ switch ( system ) { case AST__FK4: result = "FK4"; break; case AST__FK4_NO_E: result = "FK4-NO-E"; break; case AST__FK5: result = "FK5"; break; case AST__J2000: result = "J2000"; break; case AST__ICRS: result = "ICRS"; break; case AST__GAPPT: result = "GAPPT"; break; case AST__AZEL: result = "AZEL"; break; case AST__ECLIPTIC: result = "ECLIPTIC"; break; case AST__HELIOECLIPTIC: result = "HELIOECLIPTIC"; break; case AST__GALACTIC: result = "GALACTIC"; break; case AST__SUPERGALACTIC: result = "SUPERGALACTIC"; break; case AST__UNKNOWN: result = "Unknown"; break; } /* Return the result pointer. */ return result; } static int TestActiveUnit( AstFrame *this_frame, int *status ) { /* * Name: * TestActiveUnit * Purpose: * Test the ActiveUnit flag for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int TestActiveUnit( AstFrame *this_frame, int *status ) * Class Membership: * SkyFrame member function (over-rides the astTestActiveUnit protected * method inherited from the Frame class). * Description: * This function test the value of the ActiveUnit flag for a SkyFrame, * which is always "unset". * Parameters: * this * Pointer to the SkyFrame. * status * Pointer to the inherited status variable. * Returned Value: * The result of the test (0). */ return 0; } static int TestAsTime( AstSkyFrame *this, int axis, int *status ) { /* * Name: * TestAsTime * Purpose: * Determine if a value has been set for a SkyFrame's AsTime attribute. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int TestAsTime( AstSkyFrame *this, int axis, int *status ) * Class Membership: * SkyFrame member function. * Description: * This function returns a boolean value to indicate if a value has * previously been set for the AsTime attribute for a specified axis of a * SkyFrame. This attribute indicates whether axis values should be * formatted as times (as opposed to angles) by default. * Parameters: * this * Pointer to the SkyFrame. * axis * Index of the axis for which information is required (zero based). * status * Pointer to the inherited status variable. * Returned Value: * Zero or one, according to whether the AsTime attribute has been set. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables. */ AstAxis *ax; /* Pointer to Axis object */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astTestAsTime" ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis ); /* Determine if the AsTime attribute has been set for it (it cannot have been set unless the object is a SkyAxis). */ result = ( astIsASkyAxis( ax ) && astTestAxisAsTime( ax ) ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* Return the result. */ return result; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a SkyFrame. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * SkyFrame member function (over-rides the astTestAttrib protected * method inherited from the Frame class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a SkyFrame's attributes. * Parameters: * this * Pointer to the SkyFrame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ int axis; /* SkyFrame axis number */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* AsTime(axis). */ /* ------------- */ if ( nc = 0, ( 1 == astSscanf( attrib, "astime(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestAsTime( this, axis - 1 ); /* Equinox. */ /* -------- */ } else if ( !strcmp( attrib, "equinox" ) ) { result = astTestEquinox( this ); /* NegLon. */ /* ------- */ } else if ( !strcmp( attrib, "neglon" ) ) { result = astTestNegLon( this ); /* Projection. */ /* ----------- */ } else if ( !strcmp( attrib, "projection" ) ) { result = astTestProjection( this ); /* SkyRefIs. */ /* --------- */ } else if ( !strcmp( attrib, "skyrefis" ) ) { result = astTestSkyRefIs( this ); /* SkyRef. */ /* ------- */ } else if ( !strcmp( attrib, "skyref" ) ) { result = astTestSkyRef( this, 0 ) || astTestSkyRef( this, 1 ); /* SkyRef(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyref(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestSkyRef( this, axis - 1 ); /* SkyRefP. */ /* -------- */ } else if ( !strcmp( attrib, "skyrefp" ) ) { result = astTestSkyRefP( this, 0 ) || astTestSkyRefP( this, 1 ); /* SkyRefP(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "skyrefp(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestSkyRefP( this, axis - 1 ); /* AlignOffset */ /* ----------- */ } else if ( !strcmp( attrib, "alignoffset" ) ) { result = astTestAlignOffset( this ); /* If the name is not recognised, test if it matches any of the read-only attributes of this class. If it does, then return zero. */ } else if ( !strncmp( attrib, "islataxis", 9 ) || !strncmp( attrib, "islonaxis", 9 ) || !strcmp( attrib, "lataxis" ) || !strcmp( attrib, "lonaxis" ) ) { result = 0; /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static int Unformat( AstFrame *this_frame, int axis, const char *string, double *value, int *status ) { /* * Name: * Unformat * Purpose: * Read a formatted coordinate value for a SkyFrame axis. * Type: * Private function. * Synopsis: * #include "skyframe.h" * int Unformat( AstFrame *this, int axis, const char *string, * double *value, int *status ) * Class Membership: * SkyFrame member function (over-rides the public astUnformat * method inherited from the Frame class). * Description: * This function reads a formatted coordinate value for a SkyFrame * axis (supplied as a string) and returns the equivalent numerical * value as a double. It also returns the number of characters read * from the string. * Parameters: * this * Pointer to the SkyFrame. * axis * The number of the SkyFrame axis for which the coordinate * value is to be read (axis numbering starts at zero for the * first axis). * string * Pointer to a constant null-terminated string containing the * formatted coordinate value. * value * Pointer to a double in which the coordinate value read will * be returned (in radians). * status * Pointer to the inherited status variable. * Returned Value: * The number of characters read from the string to obtain the * coordinate value. * Notes: * - Any white space at the beginning of the string will be * skipped, as also will any trailing white space following the * coordinate value read. The function's return value will reflect * this. * - A function value of zero (and no coordinate value) will be * returned, without error, if the string supplied does not contain * a suitably formatted value. * - The string "" is recognised as a special case and will * generate the value AST__BAD, without error. The test for this * string is case-insensitive and permits embedded white space. * - A function result of zero will be returned and no coordinate * value will be returned via the "value" pointer if this function * is invoked with the global error status set, or if it should * fail for any reason. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ double coord; /* Coordinate value read */ int format_set; /* Format attribute set? */ int nc; /* Number of characters read */ /* Initialise. */ nc = 0; /* Check the global error status. */ if ( !astOK ) return nc; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_frame; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astUnformat" ); /* Determine if a Format value has been set for the axis and set a temporary value if it has not. Use the GetFormat member function for this class together with member functions inherited from the parent class (rather than using the object's methods directly) because if any of these methods have been over-ridden by a derived class the Format string syntax may no longer be compatible with this class. */ format_set = (*parent_testformat)( this_frame, axis, status ); if ( !format_set ) { (*parent_setformat)( this_frame, axis, GetFormat( this_frame, axis, status ), status ); } /* Use the Unformat member function inherited from the parent class to read the coordinate value. */ nc = (*parent_unformat)( this_frame, axis, string, &coord, status ); /* If necessary, clear any temporary Format value that was set above. */ if ( !format_set ) (*parent_clearformat)( this_frame, axis, status ); /* If an error occurred, clear the number of characters read. */ if ( !astOK ) { nc = 0; /* Otherwise, if characters were read, return the coordinate value. */ } else if ( nc ) { *value = coord; } /* Return the number of characters read. */ return nc; } static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) { /* * * Name: * ValidateSystem * Purpose: * Validate a value for a Frame's System attribute. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int ValidateSystem( AstFrame *this, AstSystemType system, * const char *method, int *status ) * Class Membership: * SkyFrame member function (over-rides the astValidateSystem method * inherited from the Frame class). * Description: * This function checks the validity of the supplied system value. * If the value is valid, it is returned unchanged. Otherwise, an * error is reported and a value of AST__BADSYSTEM is returned. * Parameters: * this * Pointer to the Frame. * system * The system value to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The validated system value. * Notes: * - A value of AST__BADSYSTEM will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstSystemType result; /* Validated system value */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* If the value is out of bounds, report an error. */ if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) { astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System " "or AlignSystem attribute of a %s.", status, method, astGetClass( this ), (int) system, astGetClass( this ) ); /* Otherwise, return the supplied value. */ } else { result = system; } /* Return the result. */ return result; } static void VerifyMSMAttrs( AstSkyFrame *target, AstSkyFrame *result, int which, const char *attrs, const char *method, int *status ) { /* * Name: * VerifyMSMAttrs * Purpose: * Verify that usable attribute values are available. * Type: * Private function. * Synopsis: * #include "skyframe.h" * void VerifyMSMAttrs( AstSkyFrame *target, AstSkyFrame *result, * int which, const char *attrs, const char *method, int *status ) * Class Membership: * SkyFrame member function * Description: * This function tests each attribute listed in "attrs". It returns * without action if 1) an explicit value has been set for each attribute * in the SkyFrame indicated by "which" or 2) the UseDefs attribute of the * "which" SkyFrame is non-zero. * * If UseDefs is zero (indicating that default values should not be * used for attributes), and any of the named attributes does not have * an explicitly set value, then an error is reported. * * The displayed error message assumes that tjis function was called * as part of the process of producing a Mapping from "target" to "result". * Parameters: * target * Pointer to the target SkyFrame. * result * Pointer to the result SkyFrame. * which * If 2, both the target and result SkyFrames are checked for the * supplied attributes. If less than 2, only the target SkyFrame is * checked. If greater than 2, only the result SkyFrame is checked. * attrs * A string holding a space separated list of attribute names. * method * A string holding the name of the calling method for use in error * messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ const char *a; const char *p; const char *desc; int len; int set1; int set2; int state; int usedef1; int usedef2; /* Check inherited status */ if( !astOK ) return; /* Get the UseDefs attributes of the two SkyFrames. */ usedef1 = astGetUseDefs( target ); usedef2 = astGetUseDefs( result ); /* If both SkyFrames have a non-zero value for its UseDefs attribute, then all attributes are assumed to have usable values, since the defaults will be used if no explicit value has been set. So we only need to do any checks if UseDefs is zero for either SkyFrame. */ if( !usedef1 || !usedef2 ) { /* Stop compiler warnings about uninitialised variables */ a = NULL; desc = NULL; len = 0; set1 = 0; set2 = 0; /* Loop round the "attrs" string identifying the start and length of each non-blank word in the string. */ state = 0; p = attrs; while( 1 ) { if( state == 0 ) { if( !isspace( *p ) ) { a = p; len = 1; state = 1; } } else { if( isspace( *p ) || !*p ) { /* The end of a word has just been reached. Compare it to each known attribute value. Get a flag indicating if the attribute has a set value, and a string describing the attribute.*/ if( len > 0 ) { if( !strncmp( "Equinox", a, len ) ) { set1 = astTestEquinox( target ); set2 = astTestEquinox( result ); desc = "reference equinox"; } else if( !strncmp( "Dut1", a, len ) ) { set1 = astTestDut1( target ); set2 = astTestDut1( result ); desc = "UT1-UTC correction"; } else if( !strncmp( "Epoch", a, len ) ) { set1 = astTestEpoch( target ); set2 = astTestEpoch( result ); desc = "epoch of observation"; } else if( !strncmp( "ObsLon", a, len ) ) { set1 = astTestObsLon( target ); set2 = astTestObsLon( result ); desc = "longitude of observer"; } else if( !strncmp( "ObsLat", a, len ) ) { set1 = astTestObsLat( target ); set2 = astTestObsLat( result ); desc = "latitude of observer"; } else if( !strncmp( "ObsAlt", a, len ) ) { set1 = astTestObsAlt( target ); set2 = astTestObsAlt( result ); desc = "altitude of observer"; } else { astError( AST__INTER, "VerifyMSMAttrs(SkyFrame): " "Unknown attribute name \"%.*s\" supplied (AST " "internal programming error).", status, len, a ); } /* If the attribute is not set in the target but should be, report an error. */ if( !usedef1 && !set1 && which < 3 ) { astClearTitle( target ); astClearTitle( result ); astError( AST__NOVAL, "%s(%s): Cannot convert " "celestial coordinates from %s to %s.", status, method, astGetClass( target ), astGetC( target, "Title" ), astGetC( result, "Title" ) ); astError( AST__NOVAL, "No value has been set for " "the \"%.*s\" attribute (%s) in the input %s.", status, len, a, desc, astGetClass( target ) ); break; } /* If the attribute is not set in the result but should be, report an error. */ if( !usedef2 && !set2 && which > 1 ) { astClearTitle( target ); astClearTitle( result ); astError( AST__NOVAL, "%s(%s): Cannot convert " "celestial coordinates from %s to %s.", status, method, astGetClass( result ), astGetC( target, "Title" ), astGetC( result, "Title" ) ); astError( AST__NOVAL, "No value has been set for " "the \"%.*s\" attribute (%s) in the output %s.", status, len, a, desc, astGetClass( result ) ); break; } /* Continue the word search algorithm. */ } len = 0; state = 0; } else { len++; } } if( !*(p++) ) break; } } } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* *att++ * Name: * AlignOffset * Purpose: * Align SkyFrames using the offset coordinate system? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which controls how a SkyFrame * behaves when it is used (by c astFindFrame or astConvert) as a template to match another (target) f AST_FINDFRAME or AST_CONVERT) as a template to match another (target) * SkyFrame. It determines the coordinate system in which the two * SkyFrames are aligned if a match occurs. * * If the template and target SkyFrames both have defined offset coordinate * systems (i.e. the SkyRefIs attribute is set to either "Origin" or " * Pole"), and they both have a non-zero value for AlignOffset, then * alignment occurs within the offset coordinate systems (that is, a * UnitMap will always be used to align the two SkyFrames). If either * the template or target SkyFrame has zero (the default value) for * AlignOffset, or if either SkyFrame has SkyRefIs set to "Ignored", then * alignment occurring within the coordinate system specified by the * AlignSystem attribute. * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ astMAKE_CLEAR(SkyFrame,AlignOffset,alignoffset,-INT_MAX) astMAKE_GET(SkyFrame,AlignOffset,int,0,( ( this->alignoffset != -INT_MAX ) ? this->alignoffset : 0 )) astMAKE_SET(SkyFrame,AlignOffset,int,alignoffset,( value != 0 )) astMAKE_TEST(SkyFrame,AlignOffset,( this->alignoffset != -INT_MAX )) /* *att++ * Name: * AsTime(axis) * Purpose: * Format celestal coordinates as times? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute specifies the default style of formatting to be c used (e.g. by astFormat) for the celestial coordinate values f used (e.g. by AST_FORMAT) for the celestial coordinate values * described by a SkyFrame. It takes a separate boolean value for * each SkyFrame axis so that, for instance, the setting * "AsTime(2)=0" specifies the default formatting style for * celestial latitude values. * * If the AsTime attribute for a SkyFrame axis is zero, then * coordinates on that axis will be formatted as angles by default * (using degrees, minutes and seconds), otherwise they will be * formatted as times (using hours, minutes and seconds). * * The default value of AsTime is chosen according to the sky * coordinate system being represented, as determined by the * SkyFrame's System attribute. This ensures, for example, that * right ascension values will be formatted as times by default, * following normal conventions. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - The AsTime attribute operates by changing the default value of * the corresponding Format(axis) attribute. This, in turn, may * also affect the value of the Unit(axis) attribute. * - Only the default style of formatting is affected by the AsTime * value. If an explicit Format(axis) value is set, it will * over-ride any effect from the AsTime attribute. *att-- */ /* *att++ * Name: * Equinox * Purpose: * Epoch of the mean equinox. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute is used to qualify those celestial coordinate * systems described by a SkyFrame which are notionally based on * the ecliptic (the plane of the Earth's orbit around the Sun) * and/or the Earth's equator. * * Both of these planes are in motion and their positions are * difficult to specify precisely. In practice, therefore, a model * ecliptic and/or equator are used instead. These, together with * the point on the sky that defines the coordinate origin (the * intersection of the two planes termed the "mean equinox") move * with time according to some model which removes the more rapid * fluctuations. The SkyFrame class supports both the FK4 and * FK5 models. * * The position of a fixed source expressed in any of these * coordinate systems will appear to change with time due to * movement of the coordinate system itself (rather than motion of * the source). Such coordinate systems must therefore be * qualified by a moment in time (the "epoch of the mean equinox" * or "equinox" for short) which allows the position of the model * coordinate system on the sky to be determined. This is the role * of the Equinox attribute. * * The Equinox attribute is stored as a Modified Julian Date, but * when setting or getting its value you may use the same formats * as for the Epoch attribute (q.v.). * * The default Equinox value is B1950.0 (Besselian) for the old * FK4-based coordinate systems (see the System attribute) and * J2000.0 (Julian) for all others. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - Care must be taken to distinguish the Equinox value, which * relates to the definition of a time-dependent coordinate system * (based on solar system reference planes which are in motion), * from the superficially similar Epoch value. The latter is used * to qualify coordinate systems where the positions of sources * change with time (or appear to do so) for a variety of other * reasons, such as aberration of light caused by the observer's * motion, etc. * - See the description of the System attribute for details of * which qualifying attributes apply to each celestial coordinate * system. *att-- */ /* Clear the Equinox value by setting it to AST__BAD. */ astMAKE_CLEAR(SkyFrame,Equinox,equinox,AST__BAD) /* Provide a default value of B1950.0 or J2000.0 depending on the System setting. */ astMAKE_GET(SkyFrame,Equinox,double,AST__BAD,( ( this->equinox != AST__BAD ) ? this->equinox : ( ( ( astGetSystem( this ) == AST__FK4 ) || ( astGetSystem( this ) == AST__FK4_NO_E ) ) ? palEpb2d( 1950.0 ) : palEpj2d( 2000.0 ) ) )) /* Allow any Equinox value to be set, unless the System is Helio-ecliptic (in which case clear the value so that J2000 is used). */ astMAKE_SET(SkyFrame,Equinox,double,equinox,((astGetSystem(this)!=AST__HELIOECLIPTIC)?value:AST__BAD)) /* An Equinox value is set if it is not equal to AST__BAD. */ astMAKE_TEST(SkyFrame,Equinox,( this->equinox != AST__BAD )) /* *att++ * Name: * IsLatAxis(axis) * Purpose: * Is the specified celestial axis a latitude axis? * Type: * Public attribute. * Synopsis: * Integer (boolean), read-only. * Description: * This is a read-only boolean attribute that indicates the nature of * the specified axis. The attribute has a non-zero value if the * specified axis is a celestial latitude axis (Declination, Galactic * latitude, etc), and is zero otherwise. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the SkyFrame axis to be tested. *att-- */ /* *att++ * Name: * IsLonAxis(axis) * Purpose: * Is the specified celestial axis a longitude axis? * Type: * Public attribute. * Synopsis: * Integer (boolean), read-only. * Description: * This is a read-only boolean attribute that indicates the nature of * the specified axis. The attribute has a non-zero value if the * specified axis is a celestial longitude axis (Right Ascension, Galactic * longitude, etc), and is zero otherwise. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the SkyFrame axis to be tested. *att-- */ /* *att++ * Name: * LatAxis * Purpose: * Index of the latitude axis. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This read-only attribute gives the index (1 or 2) of the latitude * axis within the SkyFrame (taking into account any current axis * permutations). * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ /* *att++ * Name: * LonAxis * Purpose: * Index of the longitude axis. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This read-only attribute gives the index (1 or 2) of the longitude * axis within the SkyFrame (taking into account any current axis * permutations). * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ /* *att++ * Name: * NegLon * Purpose: * Display negative longitude values? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which controls how longitude values c are normalized for display by astNorm. f are normalized for display by AST_NORM. * * If the NegLon attribute is zero, then normalized * longitude values will be in the range zero to 2.pi. If NegLon is * non-zero, then normalized longitude values will be in the range -pi * to pi. * * The default value depends on the current value of the SkyRefIs * attribute, If SkyRefIs has a value of "Origin", then the default for * NegLon is one, otherwise the default is zero. * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ /* Clear the NegLon value by setting it to -INT_MAX. */ astMAKE_CLEAR(SkyFrame,NegLon,neglon,-INT_MAX) /* Supply a default of 0 for absolute coords and 1 for offset coords if no NegLon value has been set. */ astMAKE_GET(SkyFrame,NegLon,int,0,( ( this->neglon != -INT_MAX ) ? this->neglon : (( astGetSkyRefIs( this ) == AST__ORIGIN_REF )? 1 : 0))) /* Set a NegLon value of 1 if any non-zero value is supplied. */ astMAKE_SET(SkyFrame,NegLon,int,neglon,( value != 0 )) /* The NegLon value is set if it is not -INT_MAX. */ astMAKE_TEST(SkyFrame,NegLon,( this->neglon != -INT_MAX )) /* *att++ * Name: * Projection * Purpose: * Sky projection description. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute provides a place to store a description of the * type of sky projection used when a SkyFrame is attached to a * 2-dimensional object, such as an image or plotting surface. For * example, typical values might be "orthographic", "Hammer-Aitoff" * or "cylindrical equal area". * * The Projection value is purely descriptive and does not affect * the celestial coordinate system represented by the SkyFrame in * any way. If it is set to a non-blank string, the description * provided may be used when forming the default value for the * SkyFrame's Title attribute (so that typically it will appear in * graphical output, for instance). The default value is an empty * string. * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ /* Clear the Projection value by freeing the allocated memory and assigning a NULL pointer. */ astMAKE_CLEAR(SkyFrame,Projection,projection,astFree( this->projection )) /* If the Projection value is not set, return a pointer to an empty string. */ astMAKE_GET(SkyFrame,Projection,const char *,NULL,( this->projection ? this->projection : "" )) /* Set a Projection value by freeing any previously allocated memory, allocating new memory, storing the string and saving the pointer to the copy. */ astMAKE_SET(SkyFrame,Projection,const char *,projection,astStore( this->projection, value, strlen( value ) + (size_t) 1 )) /* The Projection value is set if the pointer to it is not NULL. */ astMAKE_TEST(SkyFrame,Projection,( this->projection != NULL )) /* *att++ * Name: * SkyRefIs * Purpose: * Selects the nature of the offset coordinate system. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute controls how the values supplied for the SkyRef and * SkyRefP attributes are used. These three attributes together allow * a SkyFrame to represent offsets relative to some specified origin * or pole within the coordinate system specified by the System attribute, * rather than absolute axis values. SkyRefIs can take one of the * case-insensitive values "Origin", "Pole" or "Ignored". * * If SkyRefIs is set to "Origin", then the coordinate system * represented by the SkyFrame is modified to put the origin of longitude * and latitude at the position specified by the SkyRef attribute. * * If SkyRefIs is set to "Pole", then the coordinate system represented * by the SkyFrame is modified to put the north pole at the position * specified by the SkyRef attribute. * * If SkyRefIs is set to "Ignored" (the default), then any value set for the * SkyRef attribute is ignored, and the SkyFrame represents the coordinate * system specified by the System attribute directly without any rotation. * Applicability: * SkyFrame * All SkyFrames have this attribute. *att-- */ astMAKE_CLEAR(SkyFrame,SkyRefIs,skyrefis,AST__BAD_REF) astMAKE_SET(SkyFrame,SkyRefIs,int,skyrefis,value) astMAKE_TEST(SkyFrame,SkyRefIs,( this->skyrefis != AST__BAD_REF )) astMAKE_GET(SkyFrame,SkyRefIs,int,AST__IGNORED_REF,(this->skyrefis == AST__BAD_REF ? AST__IGNORED_REF : this->skyrefis)) /* *att++ * Name: * SkyRef(axis) * Purpose: * Position defining the offset coordinate system. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute allows a SkyFrame to represent offsets, rather than * absolute axis values, within the coordinate system specified by the * System attribute. If supplied, SkyRef should be set to hold the * longitude and latitude of a point within the coordinate system * specified by the System attribute. The coordinate system represented * by the SkyFrame will then be rotated in order to put the specified * position at either the pole or the origin of the new coordinate system * (as indicated by the SkyRefIs attribute). The orientation of the * modified coordinate system is then controlled using the SkyRefP * attribute. * * If an integer axis index is included in the attribute name (e.g. * "SkyRef(1)") then the attribute value should be supplied as a single * floating point axis value, in radians, when setting a value for the * attribute, and will be returned in the same form when getting the value * of the attribute. In this case the integer axis index should be "1" * or "2" (the values to use for longitude and latitude axes are * given by the LonAxis and LatAxis attributes). * * If no axis index is included in the attribute name (e.g. "SkyRef") then * the attribute value should be supplied as a character string * containing two formatted axis values (an axis 1 value followed by a * comma, followed by an axis 2 value). The same form * will be used when getting the value of the attribute. * * The default values for SkyRef are zero longitude and zero latitude. * Aligning SkyFrames with Offset Coordinate Systems: * The offset coordinate system within a SkyFrame should normally be * considered as a superficial "re-badging" of the axes of the coordinate * system specified by the System attribute - it merely provides an * alternative numerical "label" for each position in the System coordinate * system. The SkyFrame retains full knowledge of the celestial coordinate * system on which the offset coordinate system is based (given by the * System attribute). For instance, the SkyFrame retains knowledge of the * way that one celestial coordinate system may "drift" with respect to * another over time. Normally, if you attempt to align two SkyFrames (e.g. f using the AST_CONVERT or AST_FINDFRAME routine), c using the astConvert or astFindFrame routine), * the effect of any offset coordinate system defined in either SkyFrame * will be removed, resulting in alignment being performed in the * celestial coordinate system given by the AlignSystem attribute. * However, by setting the AlignOffset attribute ot a non-zero value, it * is possible to change this behaviour so that the effect of the offset * coordinate system is not removed when aligning two SkyFrames. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - If the System attribute of the SkyFrame is changed, any position * given for SkyRef is transformed into the new System. * - If a value has been assigned to SkyRef attribute, then * the default values for certain attributes are changed as follows: * the default axis Labels for the SkyFrame are modified by appending * " offset" to the end, the default axis Symbols for the SkyFrame are * modified by prepending the character "D" to the start, and the * default title is modified by replacing the projection information by the * origin information. *att-- */ MAKE_CLEAR(SkyRef,skyref,AST__BAD,2) MAKE_SET(SkyRef,double,skyref,value,2) MAKE_TEST(SkyRef,( this->skyref[axis_p] != AST__BAD ),2) MAKE_GET(SkyRef,double,0.0,((this->skyref[axis_p]!=AST__BAD)?this->skyref[axis_p]:0.0),2) /* *att++ * Name: * SkyRefP(axis) * Purpose: * Position on primary meridian of offset coordinate system. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute is used to control the orientation of the offset * coordinate system defined by attributes SkyRef and SkyRefIs. If used, * it should be set to hold the longitude and latitude of a point within * the coordinate system specified by the System attribute. The offset * coordinate system represented by the SkyFrame will then be rotated in * order to put the position supplied for SkyRefP on the zero longitude * meridian. This rotation is about an axis from the centre of the * celestial sphere to the point specified by the SkyRef attribute. * The default value for SkyRefP is usually the north pole (that is, a * latitude of +90 degrees in the coordinate system specified by the System * attribute). The exception to this is if the SkyRef attribute is * itself set to either the north or south pole. In these cases the * default for SkyRefP is the origin (that is, a (0,0) in the coordinate * system specified by the System attribute). * * If an integer axis index is included in the attribute name (e.g. * "SkyRefP(1)") then the attribute value should be supplied as a single * floating point axis value, in radians, when setting a value for the * attribute, and will be returned in the same form when getting the value * of the attribute. In this case the integer axis index should be "1" * or "2" (the values to use for longitude and latitude axes are * given by the LonAxis and LatAxis attributes). * * If no axis index is included in the attribute name (e.g. "SkyRefP") then * the attribute value should be supplied as a character string * containing two formatted axis values (an axis 1 value followed by a * comma, followed by an axis 2 value). The same form * will be used when getting the value of the attribute. * Applicability: * SkyFrame * All SkyFrames have this attribute. * Notes: * - If the position given by the SkyRef attribute defines the origin * of the offset coordinate system (that is, if the SkyRefIs attribute * is set to "origin"), then there will in general be two orientations * which will put the supplied SkyRefP position on the zero longitude * meridian. The orientation which is actually used is the one which * gives the SkyRefP position a positive latitude in the offset coordinate * system (the other possible orientation would give the SkyRefP position * a negative latitude). * - An error will be reported if an attempt is made to use a * SkyRefP value which is co-incident with SkyRef or with the point * diametrically opposite to SkyRef on the celestial sphere. The * reporting of this error is deferred until the SkyRef and SkyRefP * attribute values are used within a calculation. * - If the System attribute of the SkyFrame is changed, any position * given for SkyRefP is transformed into the new System. *att-- */ MAKE_CLEAR(SkyRefP,skyrefp,AST__BAD,2) MAKE_SET(SkyRefP,double,skyrefp,value,2) MAKE_TEST(SkyRefP,( this->skyrefp[axis_p] != AST__BAD ),2) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for SkyFrame objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for SkyFrame objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstSkyFrame *in; /* Pointer to input SkyFrame */ AstSkyFrame *out; /* Pointer to output SkyFrame */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output SkyFrames. */ in = (AstSkyFrame *) objin; out = (AstSkyFrame *) objout; /* For safety, first clear any references to the input memory from the output SkyFrame. */ out->projection = NULL; /* If necessary, allocate memory in the output SkyFrame and store a copy of the input Projection string. */ if ( in->projection ) out->projection = astStore( NULL, in->projection, strlen( in->projection ) + (size_t) 1 ); /* If an error occurred, free any allocated memory. */ if ( !astOK ) { out->projection = astFree( out->projection ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for SkyFrame objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for SkyFrame objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to SkyFrame */ /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) obj; /* Free the memory used for the Projection string if necessary. */ this->projection = astFree( this->projection ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SkyFrame objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the SkyFrame class to an output Channel. * Parameters: * this * Pointer to the SkyFrame whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSkyFrame *this; /* Pointer to the SkyFrame structure */ AstSystemType system; /* System attribute value */ char buf[ 100 ]; /* Comment buffer */ char key[ 10 ]; /* Buffer for keywords */ const char *sval; /* Pointer to string value */ const int *perm; /* Pointer to axis permutation array */ double dval; /* Double value */ int bessyr; /* Use a Besselian year value ?*/ int helpful; /* Helpful to display un-set value? */ int invperm[ 2 ]; /* Inverse permutation array */ int ival; /* Integer value */ int set; /* Attribute value set? */ int axis; /* External (i.e. permuted) zero-based axis index */ int axis_p; /* Internal zero-based axis index */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SkyFrame structure. */ this = (AstSkyFrame *) this_object; /* Get a pointer to the SkyFrame's axis permutation array (using a method, to allow for any over-ride by a derived class). */ perm = astGetPerm( this ); /* Generate an inverse axis permutation array from the forward permutation values. This will be used to determine which axis should be enquired about (using possibly over-ridden methods) to obtain data to correspond with a particular internal value (i.e. instance variable) relating to an axis. This step is needed so that the effect of any axis permutation can be un-done before values are written out, as output values are written by this function in un-permuted order. */ for ( axis = 0; axis < 2; axis++ ) invperm[ perm[ axis ] ] = axis; /* Write out values representing the instance variables for the SkyFrame class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Projection. */ /* ----------- */ set = TestProjection( this, status ); sval = set ? GetProjection( this, status ) : astGetProjection( this ); astWriteString( channel, "Proj", set, 0, sval, "Description of sky projection" ); /* NegLon. */ /* ------- */ set = TestNegLon( this, status ); ival = set ? GetNegLon( this, status ) : astGetNegLon( this ); astWriteInt( channel, "NegLon", set, 0, ival, ival ? "Display negative longitude values" : "Display positive longitude values" ); /* Equinox. */ /* -------- */ set = TestEquinox( this, status ); dval = set ? GetEquinox( this, status ) : astGetEquinox( this ); /* Decide whether the Equinox value is relevant to the current coordinate system. */ system = astGetSystem( this ); helpful = ( ( system == AST__FK4 ) || ( system == AST__FK4_NO_E ) || ( system == AST__FK5 ) || ( system == AST__ECLIPTIC ) ); /* Convert MJD to Besselian or Julian years, depending on the value. */ bessyr = ( dval < palEpj2d( 1984.0 ) ); dval = bessyr ? palEpb( dval ) : palEpj( dval ); astWriteDouble( channel, "Eqnox", set, helpful, dval, bessyr ? "Besselian epoch of mean equinox" : "Julian epoch of mean equinox" ); /* SkyRefIs. */ /* --------- */ set = TestSkyRefIs( this, status ); ival = set ? GetSkyRefIs( this, status ) : astGetSkyRefIs( this ); if( ival == AST__POLE_REF ) { astWriteString( channel, "SRefIs", set, 0, POLE_STRING, "Rotated to put pole at ref. pos." ); } else if( ival == AST__IGNORED_REF ) { astWriteString( channel, "SRefIs", set, 0, IGNORED_STRING, "Not rotated (ref. pos. is ignored)" ); } else { astWriteString( channel, "SRefIs", set, 0, ORIGIN_STRING, "Rotated to put origin at ref. pos." ); } /* SkyRef. */ /* ------- */ /* The inverse axis permutation array is used to obtain the axis index to use when accessing the SkyRef attribute. This reverses the effect of the SkyFrame's axis permutation array and yields a value appropriate to the axis with internal index "axis". */ for ( axis_p = 0; axis_p < 2; axis_p++ ) { axis = invperm[ axis_p ]; set = TestSkyRef( this, axis, status ); dval = set ? GetSkyRef( this, axis, status ) : astGetSkyRef( this, axis ); sprintf( buf, "Ref. pos. %s %s", astGetSymbol( this, axis ), astFormat( this, axis, dval ) ); sprintf( key, "SRef%d", axis_p + 1 ); astWriteDouble( channel, key, set, 0, dval, buf ); } /* SkyRefP. */ /* -------- */ for ( axis_p = 0; axis_p < 2; axis_p++ ) { axis = invperm[ axis_p ]; set = TestSkyRefP( this, axis, status ); dval = set ? GetSkyRefP( this, axis, status ) : astGetSkyRefP( this, axis ); sprintf( buf, "Ref. north %s %s", astGetSymbol( this, axis ), astFormat( this, axis, dval ) ); sprintf( key, "SRefP%d", axis_p + 1 ); astWriteDouble( channel, key, set, 0, dval, buf ); } /* AlignOffset. */ /* ------------ */ set = TestAlignOffset( this, status ); ival = set ? GetAlignOffset( this, status ) : astGetAlignOffset( this ); astWriteInt( channel, "AlOff", set, 0, ival, ival ? "Align in offset coords" : "Align in system coords" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASkyFrame and astCheckSkyFrame functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SkyFrame,Frame) astMAKE_CHECK(SkyFrame) AstSkyFrame *astSkyFrame_( const char *options, int *status, ...) { /* *+ * Name: * astSkyFrame * Purpose: * Create a SkyFrame. * Type: * Protected function. * Synopsis: * #include "skyframe.h" * AstSkyFrame *astSkyFrame( const char *options, int *status, ... ) * Class Membership: * SkyFrame constructor. * Description: * This function creates a new SkyFrame and optionally initialises its * attributes. * Parameters: * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new SkyFrame. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new SkyFrame. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- * Implementation Notes: * - This function implements the basic SkyFrame constructor which * is available via the protected interface to the SkyFrame class. * A public interface is provided by the astSkyFrameId_ function. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSkyFrame *new; /* Pointer to new SkyFrame */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SkyFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSkyFrame( NULL, sizeof( AstSkyFrame ), !class_init, &class_vtab, "SkyFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SkyFrame's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new SkyFrame. */ return new; } AstSkyFrame *astInitSkyFrame_( void *mem, size_t size, int init, AstSkyFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSkyFrame * Purpose: * Initialise a SkyFrame. * Type: * Protected function. * Synopsis: * #include "skyframe.h" * AstSkyFrame *astInitSkyFrame( void *mem, size_t size, int init, * AstFrameVtab *vtab, const char *name ) * Class Membership: * SkyFrame initialiser. * Description: * This function is provided for use by class implementations to initialise * a new SkyFrame object. It allocates memory (if necessary) to accommodate * the SkyFrame plus any additional data associated with the derived class. * It then initialises a SkyFrame structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a SkyFrame at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SkyFrame is to be created. This * must be of sufficient size to accommodate the SkyFrame data * (sizeof(SkyFrame)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the SkyFrame (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the SkyFrame * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the SkyFrame's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new SkyFrame. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * Returned Value: * A pointer to the new SkyFrame. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstSkyAxis *ax; /* Pointer to SkyAxis object */ AstSkyFrame *new; /* Pointer to the new SkyFrame */ int axis; /* Loop counter for axes */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSkyFrameVtab( vtab, name ); /* Initialise a Frame structure (the parent class) as the first component within the SkyFrame structure, allocating memory if necessary. */ new = (AstSkyFrame *) astInitFrame( mem, size, 0, (AstFrameVtab *) vtab, name, 2 ); if ( astOK ) { /* Initialise the SkyFrame data. */ /* ----------------------------- */ /* Initialise all attributes to their "undefined" values. */ new->equinox = AST__BAD; new->projection = NULL; new->neglon = -INT_MAX; new->alignoffset = -INT_MAX; new->skyrefis = AST__BAD_REF; new->skyref[ 0 ] = AST__BAD; new->skyref[ 1 ] = AST__BAD; new->skyrefp[ 0 ] = AST__BAD; new->skyrefp[ 1 ] = AST__BAD; new->last = AST__BAD; new->eplast = AST__BAD; new->klast = AST__BAD; new->diurab = AST__BAD; /* Loop to replace the Axis object associated with each SkyFrame axis with a SkyAxis object instead. */ for ( axis = 0; axis < 2; axis++ ) { /* Create the new SkyAxis, assign it to the required SkyFrame axis and then annul the SkyAxis pointer. */ ax = astSkyAxis( "", status ); astSetAxis( new, axis, ax ); ax = astAnnul( ax ); } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstSkyFrame *astLoadSkyFrame_( void *mem, size_t size, AstSkyFrameVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSkyFrame * Purpose: * Load a SkyFrame. * Type: * Protected function. * Synopsis: * #include "skyframe.h" * AstSkyFrame *astLoadSkyFrame( void *mem, size_t size, * AstSkyFrameVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * SkyFrame loader. * Description: * This function is provided to load a new SkyFrame using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SkyFrame structure in this memory, using data read from the * input Channel. * Parameters: * mem * A pointer to the memory into which the SkyFrame is to be * loaded. This must be of sufficient size to accommodate the * SkyFrame data (sizeof(SkyFrame)) plus any data used by * derived classes. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SkyFrame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SkyFrame structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSkyFrame) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SkyFrame. If this is NULL, a pointer * to the (static) virtual function table for the SkyFrame class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SkyFrame" is used instead. * Returned Value: * A pointer to the new SkyFrame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstSkyFrame *new; /* Pointer to the new SkyFrame */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char *sval; /* Pointer to string value */ const int *perm; /* Pointer to axis permutation array */ double dval; /* Floating point attribute value */ int axis; /* External axis index */ int invperm[ 2 ]; /* Inverse permutation array */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SkyFrame. In this case the SkyFrame belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSkyFrame ); vtab = &class_vtab; name = "SkyFrame"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSkyFrameVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SkyFrame. */ new = astLoadFrame( mem, size, (AstFrameVtab *) vtab, name, channel ); if ( astOK ) { /* Get a pointer to the SkyFrame's axis permutation array (using a method, to allow for any over-ride by a derived class). */ perm = astGetPerm( new ); /* Generate an inverse axis permutation array from the forward permutation values. This will be used to determine which axis should be enquired about (using possibly over-ridden methods) to obtain data to correspond with a particular internal value (i.e. instance variable) relating to an axis. This step is needed so that the effect of any axis permutation can be un-done before values are written out, as output values are written by this function in un-permuted order. */ for( axis = 0; axis < 2; axis++ ) invperm[ perm[ axis ] ] = axis; /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SkyFrame" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* The attributes defining the offset coordinate system must be loaded before the System attrivbute, since SetSystem uses them. */ /* AlignOffset */ /* ----------- */ new->alignoffset = astReadInt( channel, "aloff", -INT_MAX ); if ( TestAlignOffset( new, status ) ) SetAlignOffset( new, new->alignoffset, status ); /* SkyRefIs. */ /* --------- */ sval = astReadString( channel, "srefis", " " ); if( sval ){ new->skyrefis = AST__BAD_REF; if( astChrMatch( sval, POLE_STRING ) ) { new->skyrefis = AST__POLE_REF; } else if( astChrMatch( sval, ORIGIN_STRING ) ) { new->skyrefis = AST__ORIGIN_REF; } else if( astChrMatch( sval, IGNORED_STRING ) ) { new->skyrefis = AST__IGNORED_REF; } else if( !astChrMatch( sval, " " ) && astOK ){ astError( AST__INTER, "astRead(SkyFrame): Corrupt SkyFrame contains " "invalid SkyRefIs attribute value (%s).", status, sval ); } if( TestSkyRefIs( new, status ) ) SetSkyRefIs( new, new->skyrefis, status ); sval = astFree( sval ); } /* SkyRef. */ /* ------- */ new->skyref[ 0 ] = astReadDouble( channel, "sref1", AST__BAD ); axis = invperm[ 0 ]; if ( TestSkyRef( new, axis, status ) ) SetSkyRef( new, axis, new->skyref[ 0 ], status ); new->skyref[ 1 ] = astReadDouble( channel, "sref2", AST__BAD ); axis = invperm[ 1 ]; if ( TestSkyRef( new, axis, status ) ) SetSkyRef( new, axis, new->skyref[ 1 ], status ); /* SkyRefP. */ /* -------- */ new->skyrefp[ 0 ] = astReadDouble( channel, "srefp1", AST__BAD ); axis = invperm[ 0 ]; if ( TestSkyRefP( new, axis, status ) ) SetSkyRefP( new, axis, new->skyrefp[ 0 ], status ); new->skyrefp[ 1 ] = astReadDouble( channel, "srefp2", AST__BAD ); axis = invperm[ 1 ]; if ( TestSkyRefP( new, axis, status ) ) SetSkyRefP( new, axis, new->skyrefp[ 1 ], status ); /* System. */ /* ------- */ /* The System attribute is now part of the Frame class, but this code is retained to allow this version of AST to read SkyFrames dumped by previous versions. */ /* Check a value has not already been assigned to the Frames System attribute. */ if( !astTestSystem( new ) ){ /* Read the external representation as a string. */ sval = astReadString( channel, "system", NULL ); /* If a value was read, use the SetAttrib method to validate and store the new value in the correct place, then free the string. */ if ( sval ) { astSet( new, "System=%s", status, sval); sval = astFree( sval ); } } /* Epoch. */ /* ------ */ /* The Epoch attribute is now part of the Frame class, but this code is retained to allow this version of AST to read SkyFrames dumped by previous versions. */ /* Check a value has not already been assigned to the Frames Epoch attribute. */ if( !astTestEpoch( new ) ){ /* Get the value. */ dval = astReadDouble( channel, "epoch", AST__BAD ); /* If a value was read, use the SetAttrib method to validate and store the new value in the correct place. */ if( dval != AST__BAD ) { if( dval < 1984.0 ) { astSet( new, "Epoch=B%.*g", status, DBL_DIG, dval); } else { astSet( new, "Epoch=J%.*g", status, DBL_DIG, dval); } } } /* Projection. */ /* ----------- */ new->projection = astReadString( channel, "proj", NULL ); /* Equinox. */ /* -------- */ /* Interpret this as Besselian or Julian depending on its value. */ new->equinox = astReadDouble( channel, "eqnox", AST__BAD ); if ( TestEquinox( new, status ) ) { SetEquinox( new, ( new->equinox < 1984.0 ) ? palEpb2d( new->equinox ) : palEpj2d( new->equinox ), status ); } /* NegLon. */ /* ------- */ new->neglon = astReadInt( channel, "neglon", -INT_MAX ); if ( TestNegLon( new, status ) ) SetNegLon( new, new->neglon, status ); /* Other values */ /* ------------ */ new->last = AST__BAD; new->eplast = AST__BAD; new->klast = AST__BAD; new->diurab = AST__BAD; /* If an error occurred, clean up by deleting the new SkyFrame. */ if ( !astOK ) new = astDelete( new ); } /* Return the new SkyFrame pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astClearAsTime_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return; (**astMEMBER(this,SkyFrame,ClearAsTime))( this, axis, status ); } int astGetAsTime_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,SkyFrame,GetAsTime))( this, axis, status ); } void astSetAsTime_( AstSkyFrame *this, int axis, int value, int *status ) { if ( !astOK ) return; (**astMEMBER(this,SkyFrame,SetAsTime))( this, axis, value, status ); } int astTestAsTime_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,SkyFrame,TestAsTime))( this, axis, status ); } int astGetIsLatAxis_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,SkyFrame,GetIsLatAxis))( this, axis, status ); } int astGetIsLonAxis_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,SkyFrame,GetIsLonAxis))( this, axis, status ); } int astGetLatAxis_( AstSkyFrame *this, int *status ) { if ( !astOK ) return 1; return (**astMEMBER(this,SkyFrame,GetLatAxis))( this, status ); } int astGetLonAxis_( AstSkyFrame *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,SkyFrame,GetLonAxis))( this, status ); } double astGetSkyRefP_( AstSkyFrame *this, int axis, int *status ) { if ( !astOK ) return 0.0; return (**astMEMBER(this,SkyFrame,GetSkyRefP))( this, axis, status ); } AstMapping *astSkyOffsetMap_( AstSkyFrame *this, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,SkyFrame,SkyOffsetMap))( this, status ); } /* Special public interface functions. */ /* =================================== */ /* These provide the public interface to certain special functions whose public interface cannot be handled using macros (such as astINVOKE) alone. In general, they are named after the corresponding protected version of the function, but with "Id" appended to the name. */ /* Public Interface Function Prototypes. */ /* ------------------------------------- */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSkyFrame *astSkyFrameId_( const char *, ... ); /* Special interface function implementations. */ /* ------------------------------------------- */ AstSkyFrame *astSkyFrameId_( const char *options, ... ) { /* *++ * Name: c astSkyFrame f AST_SKYFRAME * Purpose: * Create a SkyFrame. * Type: * Public function. * Synopsis: c #include "skyframe.h" c AstSkyFrame *astSkyFrame( const char *options, ... ) f RESULT = AST_SKYFRAME( OPTIONS, STATUS ) * Class Membership: * SkyFrame constructor. * Description: * This function creates a new SkyFrame and optionally initialises * its attributes. * * A SkyFrame is a specialised form of Frame which describes * celestial longitude/latitude coordinate systems. The particular * celestial coordinate system to be represented is specified by * setting the SkyFrame's System attribute (currently, the default * is ICRS) qualified, as necessary, by a mean Equinox value and/or * an Epoch. * * For each of the supported celestial coordinate systems, a SkyFrame * can apply an optional shift of origin to create a coordinate system * representing offsets within the celestial coordinate system from some * specified point. This offset coordinate system can also be rotated to * define new longitude and latitude axes. See attributes SkyRef, SkyRefIs * and SkyRefP * * All the coordinate values used by a SkyFrame are in * radians. These may be formatted in more conventional ways for c display by using astFormat. f display by using AST_FORMAT. * Parameters: c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SkyFrame. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SkyFrame. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSkyFrame() f AST_SKYFRAME = INTEGER * A pointer to the new SkyFrame. * Examples: c frame = astSkyFrame( "" ); c Creates a SkyFrame to describe the default ICRS celestial c coordinate system. c frame = astSkyFrame( "System = FK5, Equinox = J2005, Digits = 10" ); c Creates a SkyFrame to describe the FK5 celestial c coordinate system, with a mean Equinox of J2005.0. c Because especially accurate coordinates will be used, c additional precision (10 digits) has been requested. This will c be used when coordinate values are formatted for display. c frame = astSkyFrame( "System = FK4, Equinox = 1955-sep-2" ); c Creates a SkyFrame to describe the old FK4 celestial c coordinate system. A default Epoch value (B1950.0) is used, c but the mean Equinox value is given explicitly as "1955-sep-2". c frame = astSkyFrame( "System = GAPPT, Epoch = %s", date ); c Creates a SkyFrame to describe the Geocentric Apparent c celestial coordinate system. The Epoch value, which specifies c the date of observation, is obtained from a date/time string c supplied via the string pointer "date". f FRAME = AST_SKYFRAME( ' ', STATUS ) f Creates a SkyFrame to describe the default ICRS celestial f coordinate system. f FRAME = AST_SKYFRAME( 'System = FK5, Equinox = J2005, Digits = 10', STATUS ) f Creates a SkyFrame to describe the FK5 celestial f coordinate system, with a mean Equinox of J2005.0. f Because especially accurate coordinates will be used, f additional precision (10 digits) has been requested. This will f be used when coordinate values are formatted for display. f FRAME = AST_SKYFRAME( 'System = FK4, Equinox = 1955-SEP-2', STATUS ) f Creates a SkyFrame to describe the old FK4 celestial f coordinate system. A default Epoch value (B1950.0) is used, f but the mean Equinox value is given explicitly as "1955-SEP-2". f FRAME = AST_SKYFRAME( 'System = GAPPT, Epoch = ' // DATE, STATUS ) f Creates a SkyFrame to describe the Geocentric Apparent f celestial coordinate system. The Epoch value, which specifies f the date of observation, is obtained from a date/time string f contained in the character variable DATE. * Notes: * - Currently, the default celestial coordinate system is * ICRS. However, this default may change in future as new * astrometric standards evolve. The intention is to track the most * modern appropriate standard. For this reason, you should use the * default only if this is what you intend (and can tolerate any * associated slight change in behaviour with future versions of * this function). If you intend to use the ICRS system * indefinitely, then you should specify it explicitly using an c "options" value of "System=ICRS". f OPTIONS value of "System=ICRS". * - Whichever celestial coordinate system is represented, it will * have two axes. The first of these will be the longitude axis * and the second will be the latitude axis. This order can be c changed using astPermAxes if required. f changed using AST_PERMAXES if required. * - When conversion between two SkyFrames is requested (as when c supplying SkyFrames to astConvert), f supplying SkyFrames AST_CONVERT), * account will be taken of the nature of the celestial coordinate * systems they represent, together with any qualifying mean Equinox or * Epoch values, etc. The AlignSystem attribute will also be taken into * account. The results will therefore fully reflect the * relationship between positions on the sky measured in the two * systems. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astSkyFrame constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astSkyFrame_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - The variable argument list also prevents this function from * invoking astSkyFrame_ directly, so it must be a * re-implementation of it in all respects, except for the final * conversion of the result to an ID value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSkyFrame *new; /* Pointer to new SkyFrame */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SkyFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSkyFrame( NULL, sizeof( AstSkyFrame ), !class_init, &class_vtab, "SkyFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SkyFrame's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new SkyFrame. */ return astMakeId( new ); } ./ast-7.3.3/timeframe.h0000644000175000017500000002665712262533650013304 0ustar olesoles#if !defined( TIMEFRAME_INCLUDED ) /* Include this file only once */ #define TIMEFRAME_INCLUDED /* *+ * Name: * timeframe.h * Type: * C include file. * Purpose: * Define the interface to the TimeFrame class. * Invocation: * #include "timeframe.h" * Description: * This include file defines the interface to the TimeFrame class * and provides the type definitions, function prototypes and * macros, etc. needed to use this class. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 20-MAY-2005 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ #include "frame.h" /* Parent Frame class */ #include "skyframe.h" /* Celestial coordinate systems */ /* Macros. */ /* ======= */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif #if defined(astCLASS) /* Protected */ /* Values used to represent different System attribute values. */ #define AST__MJD 1 #define AST__JD 2 #define AST__JEPOCH 3 #define AST__BEPOCH 4 /* Values used to represent different TimeScale attribute values. */ #define AST__BADTS 0 #define AST__TAI 1 #define AST__UTC 2 #define AST__UT1 3 #define AST__GMST 4 #define AST__LAST 5 #define AST__LMST 6 #define AST__TT 7 #define AST__TDB 8 #define AST__TCB 9 #define AST__TCG 10 #define AST__LT 11 /* Define constants used to size global arrays in this module. */ #define AST__TIMEFRAME_FORMAT_BUFF_LEN 200 #define AST__TIMEFRAME_GETATTRIB_BUFF_LEN 50 #define AST__TIMEFRAME_GETLABEL_BUFF_LEN 200 #define AST__TIMEFRAME_GETSYMBOL_BUFF_LEN 20 #define AST__TIMEFRAME_GETTITLE_BUFF_LEN 200 #endif /* Type Definitions. */ /* ================= */ /* Integer type used to store the TimeScale attribute. */ typedef int AstTimeScaleType; /* TimeFrame structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstTimeFrame { /* Attributes inherited from the parent class. */ AstFrame frame; /* Parent class structure */ /* Attributes specific to objects in this class. */ double ltoffset; /* Offset from UTC to Local Time */ double timeorigin; /* Zero point for time axis */ AstTimeScaleType timescale; /* Time scale */ AstTimeScaleType aligntimescale; /* Alignment time scale */ } AstTimeFrame; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstTimeFrameVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstFrameVtab frame_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ double (* CurrentTime)( AstTimeFrame *, int * ); double (* GetLTOffset)( AstTimeFrame *, int * ); int (* TestLTOffset)( AstTimeFrame *, int * ); void (* ClearLTOffset)( AstTimeFrame *, int * ); void (* SetLTOffset)( AstTimeFrame *, double, int * ); double (* GetTimeOrigin)( AstTimeFrame *, int * ); int (* TestTimeOrigin)( AstTimeFrame *, int * ); void (* ClearTimeOrigin)( AstTimeFrame *, int * ); void (* SetTimeOrigin)( AstTimeFrame *, double, int * ); AstTimeScaleType (* GetTimeScale)( AstTimeFrame *, int * ); int (* TestTimeScale)( AstTimeFrame *, int * ); void (* ClearTimeScale)( AstTimeFrame *, int * ); void (* SetTimeScale)( AstTimeFrame *, AstTimeScaleType, int * ); AstTimeScaleType (* GetAlignTimeScale)( AstTimeFrame *, int * ); int (* TestAlignTimeScale)( AstTimeFrame *, int * ); void (* ClearAlignTimeScale)( AstTimeFrame *, int * ); void (* SetAlignTimeScale)( AstTimeFrame *, AstTimeScaleType, int * ); } AstTimeFrameVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstTimeFrameGlobals { AstTimeFrameVtab Class_Vtab; int Class_Init; char Format_Buff[ AST__TIMEFRAME_FORMAT_BUFF_LEN + 1 ]; char GetAttrib_Buff[ AST__TIMEFRAME_GETATTRIB_BUFF_LEN + 1 ]; char GetLabel_Buff[ AST__TIMEFRAME_GETLABEL_BUFF_LEN + 1 ]; char GetSymbol_Buff[ AST__TIMEFRAME_GETSYMBOL_BUFF_LEN + 1 ]; char GetTitle_Buff[ AST__TIMEFRAME_GETTITLE_BUFF_LEN + 1 ]; } AstTimeFrameGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(TimeFrame) /* Check class membership */ astPROTO_ISA(TimeFrame) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected */ AstTimeFrame *astTimeFrame_( const char *, int *, ...); #else AstTimeFrame *astTimeFrameId_( const char *, ... )__attribute__((format(printf,1,2))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstTimeFrame *astInitTimeFrame_( void *, size_t, int, AstTimeFrameVtab *, const char *, int * ); /* Vtab initialiser. */ void astInitTimeFrameVtab_( AstTimeFrameVtab *, const char *, int * ); /* Loader. */ AstTimeFrame *astLoadTimeFrame_( void *, size_t, AstTimeFrameVtab *, const char *, AstChannel *channel, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitTimeFrameGlobals_( AstTimeFrameGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ double astCurrentTime_( AstTimeFrame *, int * ); #if defined(astCLASS) /* Protected */ double astGetLTOffset_( AstTimeFrame *, int * ); int astTestLTOffset_( AstTimeFrame *, int * ); void astClearLTOffset_( AstTimeFrame *, int * ); void astSetLTOffset_( AstTimeFrame *, double, int * ); double astGetTimeOrigin_( AstTimeFrame *, int * ); int astTestTimeOrigin_( AstTimeFrame *, int * ); void astClearTimeOrigin_( AstTimeFrame *, int * ); void astSetTimeOrigin_( AstTimeFrame *, double, int * ); AstTimeScaleType astGetTimeScale_( AstTimeFrame *, int * ); int astTestTimeScale_( AstTimeFrame *, int * ); void astClearTimeScale_( AstTimeFrame *, int * ); void astSetTimeScale_( AstTimeFrame *, AstTimeScaleType, int * ); AstTimeScaleType astGetAlignTimeScale_( AstTimeFrame *, int * ); int astTestAlignTimeScale_( AstTimeFrame *, int * ); void astClearAlignTimeScale_( AstTimeFrame *, int * ); void astSetAlignTimeScale_( AstTimeFrame *, AstTimeScaleType, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckTimeFrame(this) astINVOKE_CHECK(TimeFrame,this,0) #define astVerifyTimeFrame(this) astINVOKE_CHECK(TimeFrame,this,1) /* Test class membership. */ #define astIsATimeFrame(this) astINVOKE_ISA(TimeFrame,this) /* Constructor. */ #if defined(astCLASS) /* Protected */ #define astTimeFrame astINVOKE(F,astTimeFrame_) #else #define astTimeFrame astINVOKE(F,astTimeFrameId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitTimeFrame(mem,size,init,vtab,name) \ astINVOKE(O,astInitTimeFrame_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitTimeFrameVtab(vtab,name) astINVOKE(V,astInitTimeFrameVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadTimeFrame(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadTimeFrame_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* None. */ /* Interfaces to protected member functions. */ /* ----------------------------------------- */ /* Here we make use of astCheckTimeFrame to validate TimeFrame pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #define astCurrentTime(this) astINVOKE(V,astCurrentTime_(astCheckTimeFrame(this),STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astGetTimeOrigin(this) astINVOKE(V,astGetTimeOrigin_(astCheckTimeFrame(this),STATUS_PTR)) #define astTestTimeOrigin(this) astINVOKE(V,astTestTimeOrigin_(astCheckTimeFrame(this),STATUS_PTR)) #define astClearTimeOrigin(this) astINVOKE(V,astClearTimeOrigin_(astCheckTimeFrame(this),STATUS_PTR)) #define astSetTimeOrigin(this,value) astINVOKE(V,astSetTimeOrigin_(astCheckTimeFrame(this),value,STATUS_PTR)) #define astGetLTOffset(this) astINVOKE(V,astGetLTOffset_(astCheckTimeFrame(this),STATUS_PTR)) #define astTestLTOffset(this) astINVOKE(V,astTestLTOffset_(astCheckTimeFrame(this),STATUS_PTR)) #define astClearLTOffset(this) astINVOKE(V,astClearLTOffset_(astCheckTimeFrame(this),STATUS_PTR)) #define astSetLTOffset(this,value) astINVOKE(V,astSetLTOffset_(astCheckTimeFrame(this),value,STATUS_PTR)) #define astGetTimeScale(this) astINVOKE(V,astGetTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astTestTimeScale(this) astINVOKE(V,astTestTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astClearTimeScale(this) astINVOKE(V,astClearTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astSetTimeScale(this,value) astINVOKE(V,astSetTimeScale_(astCheckTimeFrame(this),value,STATUS_PTR)) #define astGetAlignTimeScale(this) astINVOKE(V,astGetAlignTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astTestAlignTimeScale(this) astINVOKE(V,astTestAlignTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astClearAlignTimeScale(this) astINVOKE(V,astClearAlignTimeScale_(astCheckTimeFrame(this),STATUS_PTR)) #define astSetAlignTimeScale(this,value) astINVOKE(V,astSetAlignTimeScale_(astCheckTimeFrame(this),value,STATUS_PTR)) #endif #endif ./ast-7.3.3/funitmap.c0000644000175000017500000000600412262533650013131 0ustar olesoles/* *+ * Name: * funitmap.c * Purpose: * Define a FORTRAN 77 interface to the AST UnitMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the UnitMap class. * Routines Defined: * AST_ISAUNITMAP * AST_UNITMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 25-SEP-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "unitmap.h" /* C interface to the UnitMap class */ F77_LOGICAL_FUNCTION(ast_isaunitmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAUNITMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAUnitMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_unitmap)( INTEGER(NCOORD), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NCOORD) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_UNITMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astUnitMap( *NCOORD, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/nullregion.c0000644000175000017500000022002712262533650013467 0ustar olesoles/* *class++ * Name: * NullRegion * Purpose: * A boundless region within a Frame. * Constructor Function: c astNullRegion f AST_NULLREGION * Description: * The NullRegion class implements a Region with no bounds within a Frame. * If the Negated attribute of a NullRegion is false, the NullRegion * represents a Region containing no points. If the Negated attribute of * a NullRegion is true, the NullRegion represents an infinite Region * (that is, all points in the coordinate system are inside the NullRegion). * Inheritance: * The NullRegion class inherits from the Region class. * Attributes: * The NullRegion class does not define any new attributes beyond * those which are applicable to all Regions. * Functions: c The NullRegion class does not define any new functions beyond those f The NullRegion class does not define any new routines beyond those * which are applicable to all Regions. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 11-OCT-2004 (DSB): * Original version. * 20-JAN-2009 (DSB): * Over-ride astRegBasePick. * 26-JAN-2009 (DSB): * Over-ride astMapMerge. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS NullRegion /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "region.h" /* Coordinate regions (parent class) */ #include "channel.h" /* I/O channels */ #include "nullregion.h" /* Interface definition for this class */ #include "mapping.h" /* Position mappings */ #include "circle.h" /* Circle regions */ #include "prism.h" /* Extruded Regions */ #include "unitmap.h" /* Unit Mapping */ #include "cmpframe.h" /* Compound Frames */ #include "cmpmap.h" /* Compound Mappings */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstMapping *(* parent_simplify)( AstMapping *, int * ); #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(NullRegion) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(NullRegion,Class_Init) #define class_vtab astGLOBAL(NullRegion,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstNullRegionVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstNullRegion *astNullRegionId_( void *, void *, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *Simplify( AstMapping *, int * ); static AstPointSet *RegBaseMesh( AstRegion *, int * ); static AstPointSet *RegMesh( AstRegion *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstRegion *RegBasePick( AstRegion *this, int, const int *, int * ); static AstRegion *GetDefUnc( AstRegion *, int * ); static AstRegion *MergeNullRegion( AstNullRegion *, AstRegion *, int, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int Overlap( AstRegion *, AstRegion *, int * ); static int OverlapX( AstRegion *, AstRegion *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void RegBaseBox( AstRegion *this, double *, double *, int * ); static void GetRegionBounds( AstRegion *this, double *, double *, int * ); /* Member functions. */ /* ================= */ static AstRegion *GetDefUnc( AstRegion *this, int *status ) { /* *+ * Name: * astGetDefUnc * Purpose: * Obtain a pointer to the default uncertainty Region for a given Region. * Type: * Protected function. * Synopsis: * #include "nullregion.h" * AstRegion *astGetDefUnc( AstRegion *this ) * Class Membership: * NullRegion member function (over-rides the astGetDefUnc protected * method inherited from the Region class). * Description: * This function returns a pointer to a Region which represents the * default uncertainty associated with a position on the boundary of the * given Region. The returned Region refers to the base Frame within the * FrameSet encapsulated by the supplied Region. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstRegion *result; double *cen; double rad; int i; int n; /* Initialise */ result = NULL; /* Check inherited status */ if( !astOK ) return result; /* Create a Circle centred on the origin with zero radius. */ n = astGetNaxes( this ); cen = astMalloc( sizeof(double)*(size_t) n ); if( cen ) { for( i = 0; i < n; i++ ) cen[ i ] = 0.0; rad = 0.0; result = (AstRegion *) astCircle( this, 1, cen, &rad, NULL, "", status ); cen = astFree( cen ); } /* Return the default uncertainty Region. */ return result; } void astInitNullRegionVtab_( AstNullRegionVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitNullRegionVtab * Purpose: * Initialise a virtual function table for a NullRegion. * Type: * Protected function. * Synopsis: * #include "nullregion.h" * void astInitNullRegionVtab( AstNullRegionVtab *vtab, const char *name ) * Class Membership: * NullRegion vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the NullRegion class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstRegionVtab *region; /* Pointer to Region component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitRegionVtab( (AstRegionVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsANullRegion) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstRegionVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ mapping = (AstMappingVtab *) vtab; region = (AstRegionVtab *) vtab; parent_transform = mapping->Transform; mapping->Transform = Transform; parent_simplify = mapping->Simplify; mapping->Simplify = Simplify; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ mapping->MapMerge = MapMerge; region->GetDefUnc = GetDefUnc; region->Overlap = Overlap; region->OverlapX = OverlapX; region->RegBaseBox = RegBaseBox; region->RegBaseMesh = RegBaseMesh; region->GetRegionBounds = GetRegionBounds; region->RegMesh = RegMesh; region->RegBasePick = RegBasePick; /* Declare the copy constructor, destructor and class dump functions. */ astSetDump( vtab, Dump, "NullRegion", "Boundless region" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a NullRegion. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * NullRegion method (over-rides the protected astMapMerge method * inherited from the Region class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated NullRegion in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated NullRegion with a Mapping which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated NullRegion which is to be merged with * its neighbours. This should be a cloned copy of the NullRegion * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * NullRegion it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated NullRegion resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstNullRegion *oldint; /* Pointer to supplied NullRegion */ AstMapping *map; /* Pointer to adjacent Mapping */ AstMapping *new; /* Simplified or merged Region */ int i1; /* Index of first Mapping merged */ int i; /* Loop counter */ int result; /* Result value to return */ /* Initialise. */ result = -1; i1 = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the NullRegion. */ oldint = (AstNullRegion *) this; /* First of all, see if the NullRegion can be replaced by a simpler Region, without reference to the neighbouring Regions in the list. */ /* =====================================================================*/ /* Try to simplify the NullRegion. If the pointer value has changed, we assume some simplification took place. */ new = astSimplify( oldint ); if( new != (AstMapping *) oldint ) { /* Annul the NullRegion pointer in the list and replace it with the new Region pointer, and indicate that the forward transformation of the returned Region should be used (not really needed but keeps things clean). */ (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = new; ( *invert_list )[ where ] = 0; /* Return the index of the first modified element. */ result = where; /* If the NullRegion itself could not be simplified, see if it can be merged with the Regions on either side of it in the list. We can only merge in parallel. */ /* =====================================================================*/ } else if( ! series ){ new = astAnnul( new ); /* Attempt to merge the NullRegion with its lower neighbour (if any). */ if( where > 0 ) { i1 = where - 1; map = ( *map_list )[ where - 1 ]; if( astIsARegion( map ) ) { new = (AstMapping *) MergeNullRegion( oldint, (AstRegion *) map, 0, status ); } } /* If this did not produced a merged Region, attempt to merge the NullRegion with its upper neighbour (if any). */ if( !new && where < *nmap - 1 ) { i1 = where; map = ( *map_list )[ where + 1 ]; if( astIsARegion( map ) ) { new = (AstMapping *) MergeNullRegion( oldint, (AstRegion *) map, 1, status ); } } /* If succesfull... */ if( new ){ /* Annul the first of the two Mappings, and replace it with the merged Region. Also clear the invert flag. */ (void) astAnnul( ( *map_list )[ i1 ] ); ( *map_list )[ i1 ] = new; ( *invert_list )[ i1 ] = 0; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ i1 + 1 ] ); for ( i = i1 + 2; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = i1; } } else { new = astAnnul( new ); } /* Return the result. */ return result; } static AstRegion *MergeNullRegion( AstNullRegion *this, AstRegion *reg, int intfirst, int *status ) { /* * Name: * MergeNullRegion * Purpose: * Attempt to merge a NullRegion with another Region to form a Region of * higher dimensionality. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstRegion *MergeNullRegion( AstNullRegion *this, AstRegion *reg, * int intfirst, int *status ) * Class Membership: * NullRegion member function. * Description: * This function attempts to combine the supplied Regions together * into a Region of higher dimensionality. * Parameters: * this * Pointer to a NullRegion. * reg * Pointer to another Region. * intfirst * If non-zero, then the NullRegion axes are put first in the new Region. * Otherwise, the other Region's axes are put first. * status * Pointer to the inherited status value. * Returned Value: * A pointer to a new region, or NULL if the supplied Regions could * not be merged. */ /* Local Variables: */ AstFrame *bfrm; /* Pointer to base Frame for "result" */ AstFrame *cfrm; /* Pointer to current Frame for "result" */ AstFrame *frm_reg; /* Pointer to Frame from "reg" */ AstFrame *frm_this; /* Pointer to Frame from "this" */ AstMapping *bcmap; /* Base->current Mapping for "result" */ AstMapping *map_reg; /* Base->current Mapping from "reg" */ AstMapping *map_this; /* Base->current Mapping from "this" */ AstMapping *sbunc; /* Simplified uncertainty */ AstRegion *bunc; /* Base Frame uncertainty Region */ AstRegion *new; /* Pointer to new NullRegion in base Frame */ AstRegion *result; /* Pointer to returned NullRegion in current Frame */ AstRegion *unc_reg; /* Current Frame uncertainty Region from "reg" */ AstRegion *unc_this; /* Current Frame uncertainty Region from "this" */ double fac_reg; /* Ratio of used to default MeshSize for "reg" */ double fac_this; /* Ratio of used to default MeshSize for "this" */ int msz_reg; /* Original MeshSize for "reg" */ int msz_reg_set; /* Was MeshSize originally set for "reg"? */ int msz_this; /* Original MeshSize for "this" */ int msz_this_set; /* Was MeshSize originally set for "this"? */ int nax; /* Number of axes in "result" */ int nax_reg; /* Number of axes in "reg" */ int nax_this; /* Number of axes in "this" */ int neg_reg; /* Negated attribute value for other supplied Region */ int neg_this; /* Negated attribute value for supplied NullRegion */ /* Initialise */ result = NULL; /* Check the local error status. */ if ( !astOK ) return result; /* Get the Closed attributes of the two Regions. They must be the same in each Region if we are to merge the Regions. In addition, in order to merge, either both Regions must have a defined uncertainty, or neither Region must have a defined Uncertainty. */ if( astGetClosed( this ) == astGetClosed( reg ) && astTestUnc( this ) == astTestUnc( reg ) ) { /* Get the Nagated attributes of the two Regions. */ neg_this = astGetNegated( this ); neg_reg = astGetNegated( reg ); /* Get the number of axes in the two supplied Regions. */ nax_reg = astGetNaxes( reg ); nax_this = astGetNaxes( this ); /* If the Regions can be combined, get the number of axes the combination will have. */ nax = nax_reg + nax_this; /* Get the base Frames from the two Region FrameSets, and combine them into a single CmpFrame that will be used to create any new Region. */ frm_this = astGetFrame( ((AstRegion *) this)->frameset, AST__BASE ); frm_reg = astGetFrame( reg->frameset, AST__BASE ); if( intfirst ) { bfrm = (AstFrame *) astCmpFrame( frm_this, frm_reg, "", status ); } else { bfrm = (AstFrame *) astCmpFrame( frm_reg, frm_this, "", status ); } frm_this = astAnnul( frm_this ); frm_reg = astAnnul( frm_reg ); /* Indicate we do not yet have a merged Region. */ new = NULL; /* We only check for merging with another NullRegion (other classes such as Box and Interval check for merging of NullRegions with other classes). The result will be an NullRegion. Both Regions must have the same value for the Negated flag. */ if( astIsANullRegion( reg ) && neg_this == neg_reg ) { new = (AstRegion *) astNullRegion( bfrm, NULL, "", status ); /* Propagate remaining attributes of the supplied Region to it. */ astRegOverlay( new, this, 1 ); /* Ensure the Negated flag is set correctly in the returned NullRegion. */ if( neg_this ) { astSetNegated( new, neg_this ); } else { astClearNegated( new ); } /* If both the supplied Regions have uncertainty, assign the new Region an uncertainty. */ if( astTestUnc( this ) && astTestUnc( reg ) ) { /* Get the uncertainties from the two supplied Regions. */ unc_this = astGetUncFrm( this, AST__BASE ); unc_reg = astGetUncFrm( reg, AST__BASE ); /* Combine them into a single Region (a Prism), in the correct order. */ if( intfirst ) { bunc = (AstRegion *) astPrism( unc_this, unc_reg, "", status ); } else { bunc = (AstRegion *) astPrism( unc_reg, unc_this, "", status ); } /* Attempt to simplify the Prism. */ sbunc = astSimplify( bunc ); /* Use the simplified Prism as the uncertainty for the returned Region. */ astSetUnc( new, sbunc ); /* Free resources. */ sbunc = astAnnul( sbunc ); bunc = astAnnul( bunc ); unc_reg = astAnnul( unc_reg ); unc_this = astAnnul( unc_this ); } /* Get the current Frames from the two Region FrameSets, and combine them into a single CmpFrame. */ frm_this = astGetFrame( ((AstRegion *) this)->frameset, AST__CURRENT ); frm_reg = astGetFrame( reg->frameset, AST__CURRENT ); if( intfirst ) { cfrm = (AstFrame *) astCmpFrame( frm_this, frm_reg, "", status ); } else { cfrm = (AstFrame *) astCmpFrame( frm_reg, frm_this, "", status ); } /* Get the base -> current Mappings from the two Region FrameSets, and combine them into a single parallel CmpMap that connects bfrm and cfrm. */ map_this = astGetMapping( ((AstRegion *) this)->frameset, AST__BASE, AST__CURRENT ); map_reg = astGetMapping( reg->frameset, AST__BASE, AST__CURRENT ); if( intfirst ) { bcmap = (AstMapping *) astCmpMap( map_this, map_reg, 0, "", status ); } else { bcmap = (AstMapping *) astCmpMap( map_reg, map_this, 0, "", status ); } /* Map the new Region into the new current Frame. */ result = astMapRegion( new, bcmap, cfrm ); /* The filling factor in the returned is the product of the filling factors for the two supplied Regions. */ if( astTestFillFactor( reg ) || astTestFillFactor( this ) ) { astSetFillFactor( result, astGetFillFactor( reg )* astGetFillFactor( this ) ); } /* If the MeshSize value is set in either supplied Region, set a value for the returned Region which scales the default value by the product of the scaling factors for the two supplied Regions. First see if either MeshSize value is set. */ msz_this_set = astTestMeshSize( this ); msz_reg_set = astTestMeshSize( reg ); if( msz_this_set || msz_reg_set ) { /* If so, get the two MeshSize values (one of which may be a default value), and then clear them so that the default value will be returned in future. */ msz_this = astGetMeshSize( this ); msz_reg = astGetMeshSize( reg ); astClearMeshSize( this ); astClearMeshSize( reg ); /* Get the ratio of the used MeshSize to the default MeshSize for both Regions. */ fac_this = (double)msz_this/(double)astGetMeshSize( this ); fac_reg = (double)msz_reg/(double)astGetMeshSize( reg ); /* The MeshSize of the returned Returned is the default value scaled by the product of the two ratios found above. */ astSetMeshSize( result, fac_this*fac_reg*astGetMeshSize( result ) ); /* Re-instate the original MeshSize values for the supplied Regions (if set) */ if( msz_this_set ) astSetMeshSize( this, msz_this ); if( msz_reg_set ) astSetMeshSize( reg, msz_reg ); } /* Free remaining resources */ frm_this = astAnnul( frm_this ); frm_reg = astAnnul( frm_reg ); map_this = astAnnul( map_this ); map_reg = astAnnul( map_reg ); bcmap = astAnnul( bcmap ); new = astAnnul( new ); cfrm = astAnnul( cfrm ); } } /* If an error has occurred, annul the returned pointer. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static int Overlap( AstRegion *this, AstRegion *that, int *status ){ /* * Name: * Overlap * Purpose: * Test if two regions overlap each other. * Type: * Private function. * Synopsis: * #include "nullregion.h" * int Overlap( AstRegion *this, AstRegion *that ) * Class Membership: * NullRegion member function (over-rides the astOverlap method inherited * from the Region class). * Description: * This function returns an integer value indicating if the two * supplied Regions overlap. The two Regions are converted to a commnon * coordinate system before performing the check. If this conversion is * not possible (for instance because the two Regions represent areas in * different domains), then the check cannot be performed and a zero value * is returned to indicate this. * Parameters: * this * Pointer to the first Region. * that * Pointer to the second Region. * Returned Value: * astOverlap() * A value indicating if there is any overlap between the two Regions. * Possible values are: * * 0 - The check could not be performed because the second Region * could not be mapped into the coordinate system of the first * Region. * * 1 - There is no overlap between the two Regions. * * 2 - The first Region is completely inside the second Region. * * 3 - The second Region is completely inside the first Region. * * 4 - There is partial overlap between the two Regions. * * 5 - The Regions are identical. * * 6 - The second Region is the negation of the first Region. * Notes: * - The returned values 5 and 6 do not check the value of the Closed * attribute in the two Regions. * - A value of zero will be returned if this function is invoked with the * AST error status set, or if it should fail for any reason. * Implementation Notes: * - This function is simply a wrap-up for the OverlapX function * which performs the required processing but swaps the order of the * two arguments. This is a trick to allow the astOverlap * method to be over-ridden by derived classes on the basis of the * class of either of the two arguments. */ /* Check the inherited status. */ if ( !astOK ) return 0; /* Invoke the private "OverlapX" member function with the two arguments swapped. */ return OverlapX( that, this, status ); } static int OverlapX( AstRegion *that, AstRegion *this, int *status ){ /* * Name: * OverlapX * Purpose: * Test if two regions overlap each other. * Type: * Private function. * Synopsis: * #include "nullregion.h" * int OverlapX( AstRegion *that, AstRegion *this ) * Class Membership: * NullRegion member function (over-rides the astOverlapX method inherited * from the Region class). * Description: * This function performs the processing for the public astOverlap * method (as inherited from the Region class and over-ridden by the * NullRegion class) and has exactly the same interface except that * the order of the two arguments is swapped. This is a trick * to allow the astOverlap method to be over-ridden by derived * classes on the basis of the class of either of its two * arguments. * * See the astOverlap method for details of the interface. */ /* Local Variables: */ AstFrameSet *fs; /* FrameSet connecting Region Frames */ int result; /* Returned value */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the Regions can be compared meaningfully. */ fs = astConvert( this, that, "" ); if( fs ) { fs = astAnnul( fs ); /* If both the supplied Regions are NullRegion... */ if( astIsANullRegion( this ) && astIsANullRegion( that ) ) { /* If the Negated attributes are equal, the Regions are identical. Otherwise they are mutually exclusive. */ if( astGetNegated( this ) == astGetNegated( that ) ) { result = 5; } else { result = 6; } /* If one of the supplied Region is a NullRegion containing no points, then there is no overlap. */ } else if( ( astIsANullRegion( this ) && !astGetNegated( this ) ) || ( astIsANullRegion( that ) && !astGetNegated( that ) ) ) { result = 1; /* If "that" is infinite and "this" is not infinite, then "this" is entirely inside "that". */ } else if( astIsANullRegion( that ) && astGetNegated( that ) ) { result = 2; /* If "this" is infinite and "that" is not infinite, then "that" is entirely inside "this". */ } else if( astIsANullRegion( this ) && astGetNegated( this ) ){ result = 3; /* Otherwise there is partial overlap. */ } else { result = 4; } } /* If not OK, return zero. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){ /* * Name: * RegBaseBox * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "nullregion.h" * void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * NullRegion member function (over-rides the astRegBaseBox protected * method inherited from the Region class). * Description: * This function returns the upper and lower axis bounds of a Region in * the base Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstNullRegion *this; /* Pointer to NullRegion structure */ int i; /* Axis index */ int nc; /* No. of axes in base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the NullRegion structure */ this = (AstNullRegion *) this_region; /* Get the number of base Frame axes. */ nc = astGetNin( this_region->frameset ); /* Set the upper bound less than the lower bound to indicate that the region contains no points. */ for( i = 0; i < nc; i++ ) { lbnd[ i ] = 1.0; ubnd[ i ] = -1.0; } } static AstPointSet *RegBaseMesh( AstRegion *this, int *status ){ /* * Name: * RegBaseMesh * Purpose: * Return a PointSet containing a mesh of points on the boundary of a * Region in its base Frame. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstPointSet *astRegBaseMesh( AstRegion *this, int *status ) * Class Membership: * NullRegion member function (over-rides the astRegBaseMesh protected * method inherited from the Region class). * Description: * This function returns a PointSet containing a mesh of points on the * boundary of the Region. The points refer to the base Frame of * the encapsulated FrameSet. Note, a NullRegion has no boundary. This * is indicated by returned a PointSet containing a single point with a * value of AST__BAD on every axis. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a new PointSet containing a single point with value of * AST__BAD on every axis. *- */ /* Local Variables: */ AstPointSet *result; double **ptr; int i; int nc; /* Initialise */ result = NULL; /* Check the inherited status */ if( !astOK ) return result; /* If the Region structure contains a pointer to a PointSet holding a previously created mesh, return it. */ if( this->basemesh ) { result = astClone( this->basemesh ); /* Otherwise, create a new mesh. */ } else { /* Get the number of base Frame axes */ nc = astGetNin( this->frameset ); /* Create the PointSet. */ result = astPointSet( 1, nc, "", status ); /* Get a pointer to the axis values. */ ptr = astGetPoints( result ); /* If OK, store AST__BAD on every axis. */ if( ptr ) for( i = 0; i < nc; i++ ) ptr[ i ][ 0 ] = AST__BAD; /* Same the returned pointer in the Region structure so that it does not need to be created again next time this function is called. */ if( astOK && result ) this->basemesh = astClone( result ); } /* Return the result. */ return result; } static AstRegion *RegBasePick( AstRegion *this_region, int naxes, const int *axes, int *status ){ /* * Name: * RegBasePick * Purpose: * Return a Region formed by picking selected base Frame axes from the * supplied Region. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes, * int *status ) * Class Membership: * NullRegion member function (over-rides the astRegBasePick protected * method inherited from the Region class). * Description: * This function attempts to return a Region that is spanned by selected * axes from the base Frame of the encapsulated FrameSet of the supplied * Region. This may or may not be possible, depending on the class of * Region. If it is not possible a NULL pointer is returned. * Parameters: * this * Pointer to the Region. * naxes * The number of base Frame axes to select. * axes * An array holding the zero-based indices of the base Frame axes * that are to be selected. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the Region, or NULL if no region can be formed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstFrame *bfrm; /* The base Frame in the supplied Region */ AstFrame *frm; /* The base Frame in the returned Region */ AstRegion *bunc; /* The uncertainty in the supplied Region */ AstRegion *result; /* Returned Region */ AstRegion *unc; /* The uncertainty in the returned Region */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the base Frame of the encapsulated FrameSet. */ bfrm = astGetFrame( this_region->frameset, AST__BASE ); /* Create a Frame by picking the selected axes from the base Frame of the encapsulated FrameSet. */ frm = astPickAxes( bfrm, naxes, axes, NULL ); /* Get the uncertainty Region (if any) within the base Frame of the supplied Region, and select the required axes from it. If the resulting Object is not a Region, annul it so that the returned Region will have no uncertainty. */ if( astTestUnc( this_region ) ) { bunc = astGetUncFrm( this_region, AST__BASE ); unc = astPickAxes( bunc, naxes, axes, NULL ); bunc = astAnnul( bunc ); if( ! astIsARegion( unc ) ) unc = astAnnul( unc ); } else { unc = NULL; } /* Create the new NullRegion. */ result = (AstRegion *) astNullRegion( frm, unc, "", status ); /* Free resources */ frm = astAnnul( frm ); bfrm = astAnnul( bfrm ); if( unc ) unc = astAnnul( unc ); /* Return a NULL pointer if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static void GetRegionBounds( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){ /* * Name: * GetRegionBounds * Purpose: * Returns the bounding box of an un-negated Region in the current Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "nullregion.h" * void astGetRegionBounds( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * NullRegion member function (over-rides the astGetRegionBounds protected * method inherited from the Region class). * Description: * This function returns the upper and lower axis bounds of a Region in * the current Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the current Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the Region. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the current Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the Region. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstNullRegion *this; /* Pointer to NullRegion structure */ int i; /* Axis index */ int nc; /* No. of axes in base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the NullRegion structure */ this = (AstNullRegion *) this_region; /* Get the number of base Frame axes. */ nc = astGetNin( this_region->frameset ); /* Set the upper bound less than the lower bound to indicate that the region contains no points. */ for( i = 0; i < nc; i++ ) { lbnd[ i ] = 1.0; ubnd[ i ] = -1.0; } } static AstPointSet *RegMesh( AstRegion *this, int *status ){ /* * Name: * RegMesh * Purpose: * Return a PointSet containing points spread over the boundary of a * Region. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstPointSet *astRegMesh( AstRegion *this, int *status ) * Class Membership: * NullRegion member function (over-rides the astRegMesh protected * method inherited from the Region class). * Description: * This function returns a PointSet containing a mesh of points on the * boundary of the Region. The points refer to the current Frame of * the encapsulated FrameSet. Note, a NullRegion has no boundary and * so an error is reported if this function is called. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * NULL pointer. * Notes: * - This implementation reports and error and returns NULL since a * NullRegion has no boundary. *- */ astError( AST__INTER, "astRegMesh(%s): The %s class does not implement " "the astRegMesh method inherited from the Region class " "(internal AST programming error).", status, astGetClass( this ), astGetClass( this ) ); return NULL; } static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { /* * Name: * Simplify * Purpose: * Simplify the Mapping represented by a Region. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstMapping *Simplify( AstMapping *this, int *status ) * Class Membership: * NullRegion method (over-rides the astSimplify method inherited * from the Region class). * Description: * This function invokes the parent Region Simplify method, and then * performs any further region-specific simplification. * * If the Mapping from base to current Frame is not a UnitMap, this * will include attempting to fit a new Region to the boundary defined * in the current Frame. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the simplified Region. A cloned pointer to the * supplied Region will be returned if no simplication could be * performed. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *frm; /* Current Frame */ AstMapping *map; /* Base->current Mapping */ AstMapping *result; /* Result pointer to return */ AstRegion *new; /* Simplified Region */ AstRegion *this; /* Pointer to supplied Region structure */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the supplied Region structure. */ this = (AstRegion *) this_mapping; /* Invoke the parent Simplify method inherited from the Region class. This will simplify the encapsulated FrameSet and uncertainty Region. */ new = (AstRegion *) (*parent_simplify)( this_mapping, status ); /* Is the Mapping from base Frame to current Frame in the Region a UnitMap? If so, no simplification is possible. */ map = astGetMapping( new->frameset, AST__BASE, AST__CURRENT ); if( astIsAUnitMap( map ) ){ result = astClone( new ); } else { /* Create a NullRegion from the current Frame. */ frm = astGetFrame( new->frameset, AST__CURRENT ); result = (AstMapping *) astNullRegion( frm, astGetUnc( new, 0 ), "", status ); /* Free resources. */ frm = astAnnul( frm ); } map = astAnnul( map ); new = astAnnul( new ); /* If any simplification could be performed, copy Region attributes from the supplied Region to the returned Region, and return a pointer to it. If the supplied Region had no uncertainty, ensure the returned Region has no uncertainty. Otherwise, return a clone of the supplied pointer. */ if( result != this_mapping ) astRegOverlay( result, this, 1 ); /* If an error occurred, annul the returned pointer. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a NullRegion to transform a set of points. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * NullRegion member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a NullRegion and a set of points encapsulated in a * PointSet and transforms the points by setting axis values to * AST__BAD for all points which are outside the region. Points inside * the region are copied unchanged from input to output. * Parameters: * this * Pointer to the NullRegion. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - The forward and inverse transformations are identical for a * Region. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of axes in the Frame represented by the NullRegion. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstNullRegion *this; /* Pointer to NullRegion */ AstPointSet *result; /* Pointer to output PointSet */ double **ptr_out; /* Pointer to output coordinate data */ double *p; /* Pointer to next axis value */ int coord; /* Zero-based index for coordinates */ int ncoord_out; /* No. of coordinates per output point */ int npoint_out; /* No. of points */ int point; /* Loop counter for points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the NullRegion structure. */ this = (AstNullRegion *) this_mapping; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Region class. This function validates all arguments and generates an output PointSet if necessary, containing a copy of the input PointSet. */ result = (*parent_transform)( this_mapping, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* If the NullRegion has been inverted, it represents an infinite region which includes all points, so just retain the copy of the supplied PointSet created by the parent Transform method above. If the NullRegion has not been inverted, it contains no points and so set all output points bad. */ if( !astGetNegated( this ) ) { ncoord_out = astGetNcoord( result ); npoint_out = astGetNpoint( result ); ptr_out = astGetPoints( result ); if ( astOK ) { for ( coord = 0; coord < ncoord_out; coord++ ) { p = ptr_out[ coord ]; for ( point = 0; point < npoint_out; point++ ) { *(p++) = AST__BAD; } } } } /* Annul the result if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ /* None */ /* Destructor. */ /* ----------- */ /* None */ /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for NullRegion objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the NullRegion class to an output Channel. * Parameters: * this * Pointer to the NullRegion whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstNullRegion *this; /* Pointer to the NullRegion structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the NullRegion structure. */ this = (AstNullRegion *) this_object; /* Write out values representing the instance variables for the NullRegion class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* There are no values to write, so return without further action. */ } /* Standard class functions. */ /* ========================= */ /* Implement the astIsANullRegion and astCheckNullRegion functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(NullRegion,Region) astMAKE_CHECK(NullRegion) AstNullRegion *astNullRegion_( void *frame_void, AstRegion *unc, const char *options, int *status, ...) { /* *++ * Name: c astNullRegion f AST_NULLREGION * Purpose: * Create a NullRegion. * Type: * Public function. * Synopsis: c #include "nullregion.h" c AstNullRegion *astNullRegion( AstFrame *frame, AstRegion *unc, const char *options, ... ) f RESULT = AST_NULLREGION( FRAME, UNC, OPTIONS, STATUS ) * Class Membership: * NullRegion constructor. * Description: * This function creates a new NullRegion and optionally initialises its * attributes. * * A NullRegion is a Region with no bounds. If the Negated attribute of a * NullRegion is false, the NullRegion represents a Region containing no * points. If the Negated attribute of a NullRegion is true, the NullRegion * represents an infinite Region containing all points within the * coordinate system. * Parameters: c frame f FRAME = INTEGER (Given) * A pointer to the Frame in which the region is defined. A deep * copy is taken of the supplied Frame. This means that any * subsequent changes made to the Frame using the supplied pointer * will have no effect the Region. c unc f UNC = INTEGER (Given) * An optional pointer to an existing Region which specifies the * uncertainties associated with positions in the supplied Frame. * The uncertainty in any point in the Frame is found by shifting the * supplied "uncertainty" Region so that it is centred at the point * being considered. The area covered by the shifted uncertainty * Region then represents the uncertainty in the position. The * uncertainty is assumed to be the same for all points. * * If supplied, the uncertainty Region must be of a class for which * all instances are centro-symetric (e.g. Box, Circle, Ellipse, etc.) * or be a Prism containing centro-symetric component Regions. A deep * copy of the supplied Region will be taken, so subsequent changes to * the uncertainty Region using the supplied pointer will have no * effect on the created Box. Alternatively, f a null Object pointer (AST__NULL) c a NULL Object pointer * may be supplied, in which case a default uncertainty of zero is * used. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new NullRegion. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new NullRegion. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astNullRegion() f AST_NULLREGION = INTEGER * A pointer to the new NullRegion. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstNullRegion *new; /* Pointer to new NullRegion */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate a pointer to the supplied Frame structure. */ frame = astCheckFrame( frame_void ); /* Initialise the NullRegion, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitNullRegion( NULL, sizeof( AstNullRegion ), !class_init, &class_vtab, "NullRegion", frame, unc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new NullRegion's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new NullRegion. */ return new; } AstNullRegion *astNullRegionId_( void *frame_void, void *unc_void, const char *options, ... ) { /* * Name: * astNullRegionId_ * Purpose: * Create a NullRegion. * Type: * Private function. * Synopsis: * #include "nullregion.h" * AstNullRegion *astNullRegionId_( AstFrame *frame, AstRegion *unc, const char *options, ... ) * Class Membership: * NullRegion constructor. * Description: * This function implements the external (public) interface to the * astNullRegion constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astNullRegion_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astNullRegion_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astNullRegion_. * Returned Value: * The ID value associated with the new NullRegion. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstNullRegion *new; /* Pointer to new NullRegion */ AstRegion *unc; /* Pointer to Region structure */ va_list args; /* Variable argument list */ int *status; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain a Frame pointer from the supplied ID and validate the pointer to ensure it identifies a valid Frame. */ frame = astVerifyFrame( astMakePointer( frame_void ) ); /* Obtain a Region pointer from the supplied "unc" ID and validate the pointer to ensure it identifies a valid Region . */ unc = unc_void ? astCheckRegion( astMakePointer( unc_void ) ) : NULL; /* Initialise the NullRegion, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitNullRegion( NULL, sizeof( AstNullRegion ), !class_init, &class_vtab, "NullRegion", frame, unc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new NullRegion's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new NullRegion. */ return astMakeId( new ); } AstNullRegion *astInitNullRegion_( void *mem, size_t size, int init, AstNullRegionVtab *vtab, const char *name, AstFrame *frame, AstRegion *unc, int *status ) { /* *+ * Name: * astInitNullRegion * Purpose: * Initialise a NullRegion. * Type: * Protected function. * Synopsis: * #include "nullregion.h" * AstNullRegion *astInitNullRegion_( void *mem, size_t size, int init, * AstNullRegionVtab *vtab, const char *name, * AstFrame *frame, AstRegion *unc ) * Class Membership: * NullRegion initialiser. * Description: * This function is provided for use by class implementations to initialise * a new NullRegion object. It allocates memory (if necessary) to accommodate * the NullRegion plus any additional data associated with the derived class. * It then initialises a NullRegion structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a NullRegion at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the NullRegion is to be initialised. * This must be of sufficient size to accommodate the NullRegion data * (sizeof(NullRegion)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the NullRegion (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the NullRegion * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the NullRegion's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new NullRegion. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * frame * A pointer to the Frame in which the region is defined. * unc * A pointer to a Region which specifies the uncertainty of positions * within the supplied Frame. A NULL pointer can be supplied, in which * case default uncertainties of zero are used. If an uncertainty * Region is supplied, it must be either a Box, a Circle or an Ellipse, * and its encapsulated Frame must be related to the Frame supplied * for parameter "frame" (i.e. astConvert should be able to find a * Mapping between them). The centre of the supplied uncertainty * Region is immaterial since it will be re-centred on the point * being tested before use. A deep copy is taken of the supplied * Region. * Returned Value: * A pointer to the new NullRegion. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstNullRegion *new; /* Pointer to new NullRegion */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitNullRegionVtab( vtab, name ); /* Initialise a Region structure (the parent class) as the first component within the NullRegion structure, allocating memory if necessary. */ new = (AstNullRegion *) astInitRegion( mem, size, 0, (AstRegionVtab *) vtab, name, frame, NULL, unc ); /* If an error occurred, clean up by deleting the new NullRegion. */ if ( !astOK ) new = astDelete( new ); /* Return a pointer to the new NullRegion. */ return new; } AstNullRegion *astLoadNullRegion_( void *mem, size_t size, AstNullRegionVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadNullRegion * Purpose: * Load a NullRegion. * Type: * Protected function. * Synopsis: * #include "nullregion.h" * AstNullRegion *astLoadNullRegion( void *mem, size_t size, AstNullRegionVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * NullRegion loader. * Description: * This function is provided to load a new NullRegion using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * NullRegion structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a NullRegion at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the NullRegion is to be * loaded. This must be of sufficient size to accommodate the * NullRegion data (sizeof(NullRegion)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the NullRegion (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the NullRegion structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstNullRegion) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new NullRegion. If this is NULL, a pointer * to the (static) virtual function table for the NullRegion class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "NullRegion" is used instead. * Returned Value: * A pointer to the new NullRegion. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstNullRegion *new; /* Pointer to the new NullRegion */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this NullRegion. In this case the NullRegion belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstNullRegion ); vtab = &class_vtab; name = "NullRegion"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitNullRegionVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built NullRegion. */ new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "NullRegion" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* There are no values to read. */ /* ---------------------------- */ /* If an error occurred, clean up by deleting the new NullRegion. */ if ( !astOK ) new = astDelete( new ); } /* Return the new NullRegion pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/fintramap.c0000644000175000017500000003024412262533650013272 0ustar olesoles/* *+ * Name: * fintramap.c * Purpose: * Define a FORTRAN 77 interface to the AST IntraMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the IntraMap class. * Routines Defined: * AST_INTRAMAP * AST_INTRAREG * AST_ISAINTRAMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 18-MAR-1998 (RFWS): * Original version. * 15-SEP-1999 (RFWS): * Added a THIS pointer to the external transformation function * used by an IntraMap. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "intramap.h" /* C interface to the IntraMap class */ #include #include /* Prototypes for private functions. */ /* ================================= */ static void TranWrap( void (*)( AstMapping *, int, int, const double *[], int, int, double *[] ), AstMapping *, int, int, const double *[], int, int, double *[], int * ); /* Transformation function interface. */ /* ================================== */ /* This is concerned with allowing FORTRAN implementations of transformation functions to be passed to the IntraMap class and invoked when necessary by C code in the main class implementation. All FORTRAN-specific aspects of this interface are encapsulated here. */ static void TranWrap( void (* tran)( AstMapping *, int, int, const double *[], int, int, double *[] ), AstMapping *this, int npoint, int ncoord_in, const double *ptr_in[], int forward, int ncoord_out, double *ptr_out[], int *status ) { /* * Name: * TranWrap * Purpose: * Wrapper function to invoke a FORTRAN transformation function. * Type: * Private function. * Synopsis: * void TranWrap( void (* tran)( AstMapping *, int, int, const double *[], * int, int, double *[] ), * AstMapping *this, int npoint, int ncoord_in, * const double *ptr_in[], int forward, int ncoord_out, * double *ptr_out[], int *status ) * Description: * This function invokes a FORTRAN implementation of a * transformation function (which resembles AST_TRANN from the * Mapping class FORTRAN interface) in order to make it callable by * C code which would prefer to call a C function that resembles * astTranP (from the Mapping class C interface). * Parameters: * tran * Pointer to the FORTRAN transformation function to be invoked. * This should result from a cast applied to a pointer to a * function that resembles AST_TRANN (but with the first * argument omitted). * this * An external Mapping ID associated with the internal (true C) pointer * for the IntraMap whose transformation is being evaluated. * npoint * The number of points to be transformed. * ncoord_in * The number of coordinates being supplied for each input point * (i.e. the number of dimensions of the space in which the * input points reside). * ptr_in * An array of pointers to double, with "ncoord_in" * elements. Element "ptr_in[coord]" should point at the first * element of an array of double (with "npoint" elements) which * contain the values of coordinate number "coord" for each * input (untransformed) point. The value of coordinate number * "coord" for input point number "point" is therefore given by * "ptr_in[coord][point]". * forward * A non-zero value indicates that the forward coordinate * transformation is to be applied, while a zero value indicates * that the inverse transformation should be used. * ncoord_out * The number of coordinates being generated for each output * point (i.e. the number of dimensions of the space in which * the output points reside). This need not be the same as * "ncoord_in". * ptr_out * An array of pointers to double, with "ncoord_out" * elements. Element "ptr_out[coord]" should point at the first * element of an array of double (with "npoint" elements) into * which the values of coordinate number "coord" for each output * (transformed) point will be written. The value of coordinate * number "coord" for output point number "point" will therefore * be found in "ptr_out[coord][point]". * status * Pointer to the inherited status value. */ /* Local Variables; */ DECLARE_INTEGER(INDIM); /* First dimension size of input array */ DECLARE_INTEGER(NCOORD_IN); /* Number of input coordinates */ DECLARE_INTEGER(NCOORD_OUT); /* Number of output coordinates */ DECLARE_INTEGER(NPOINT); /* Number of points */ DECLARE_INTEGER(OUTDIM); /* First dimension size of output array */ DECLARE_INTEGER(STATUS); /* FORTRAN error status variable */ DECLARE_INTEGER(THIS); /* External ID for the IntraMap */ DECLARE_LOGICAL(FORWARD); /* Use forward transformation? */ F77_DOUBLE_TYPE *IN; /* Input coordinate array for FORTRAN */ F77_DOUBLE_TYPE *OUT; /* Output coordinate array for FORTRAN */ int coord; /* Loop counter for coordinates */ int i; /* Index into FORTRAN arrays */ /* Check the global error status. */ if ( !astOK ) return; /* Assign input values to the arguments for the FORTRAN transformation function. */ THIS = astP2I( this ); NPOINT = npoint; NCOORD_IN = ncoord_in; INDIM = npoint; FORWARD = forward ? F77_TRUE : F77_FALSE; NCOORD_OUT = ncoord_out; OUTDIM = npoint; /* Since the input/output coordinate values may be stored in separate arrays, we must move them temporarily into new 2-dimensional arrays, as required by the FORTRAN transformation function interface. Allocate memory for these arrays. */ IN = astMalloc( (size_t) ( npoint * ncoord_in ) * sizeof( F77_DOUBLE_TYPE ) ); OUT = astMalloc( (size_t) ( npoint * ncoord_out ) * sizeof( F77_DOUBLE_TYPE ) ); /* If OK, fill the input array with coordinate values. Use "memcpy" to avoid numerical errors if the data contain junk - this allows the transformation function to produce the appropriate error instead of it happening here. */ if ( astOK ) { i = 0; for ( coord = 0; coord < ncoord_in; coord++ ) { (void) memcpy( IN + i, ptr_in[ coord ], (size_t) npoint * sizeof( F77_DOUBLE_TYPE ) ); i += npoint; } } /* Cast the transformation function pointer to a pointer to the FORTRAN subroutine and then invoke it. Transfer the AST error status to and from the subroutine's error status argument. */ if ( astOK ) { STATUS = astStatus; ( *(void (*)()) tran )( INTEGER_ARG(&THIS), INTEGER_ARG(&NPOINT), INTEGER_ARG(&NCOORD_IN), INTEGER_ARG(&INDIM), DOUBLE_ARRAY_ARG(IN), LOGICAL_ARG(&FORWARD), INTEGER_ARG(&NCOORD_OUT), INTEGER_ARG(&OUTDIM), DOUBLE_ARRAY_ARG(OUT), INTEGER_ARG(&STATUS) ); astSetStatus( STATUS ); } /* If OK, transfer the transformed coordinate values to the output arrays. */ if ( astOK ) { i = 0; for ( coord = 0; coord < ncoord_out; coord++ ) { (void) memcpy( ptr_out[ coord ], OUT + i, (size_t) npoint * sizeof( F77_DOUBLE_TYPE ) ); i += npoint; } } /* Free the temporary arrays. */ astFree( IN ); astFree( OUT ); } /* FORTRAN interface functions. */ /* ============================ */ /* These functions implement the remainder of the FORTRAN interface. */ F77_SUBROUTINE(ast_intrareg)( CHARACTER(NAME), INTEGER(NIN), INTEGER(NOUT), void (* TRAN)(), INTEGER(FLAGS), CHARACTER(PURPOSE), CHARACTER(AUTHOR), CHARACTER(CONTACT), INTEGER(STATUS) TRAIL(NAME) TRAIL(PURPOSE) TRAIL(AUTHOR) TRAIL(CONTACT) ) { GENPTR_CHARACTER(NAME) GENPTR_INTEGER(NIN) GENPTR_INTEGER(NOUT) GENPTR_INTEGER(FLAGS) GENPTR_CHARACTER(PURPOSE) GENPTR_CHARACTER(AUTHOR) GENPTR_CHARACTER(CONTACT) char *name; void (* tran)( AstMapping *, int, int, const double *[], int, int, double *[] ); char *purpose; char *author; char *contact; astAt( "AST_INTRAREG", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); tran = (void (*)( AstMapping *, int, int, const double *[], int, int, double *[] )) TRAN; purpose = astString( PURPOSE, PURPOSE_length ); author = astString( AUTHOR, AUTHOR_length ); contact = astString( CONTACT, CONTACT_length ); astIntraRegFor( name, *NIN, *NOUT, tran, TranWrap, *FLAGS, purpose, author, contact ); astFree( name ); astFree( purpose ); astFree( author ); astFree( contact ); ) } F77_INTEGER_FUNCTION(ast_intramap)( CHARACTER(NAME), INTEGER(NIN), INTEGER(NOUT), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(NAME) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(NAME) GENPTR_INTEGER(NIN) GENPTR_INTEGER(NOUT) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *name; char *options; int i; astAt( "AST_INTRAMAP", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astIntraMap( name, *NIN, *NOUT, "%s", options ) ); astFree( name ); astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isaintramap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAINTRAMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAIntraMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } ./ast-7.3.3/specfluxframe.c0000644000175000017500000022621012262533650014155 0ustar olesoles/* *class++ * Name: * SpecFluxFrame * Purpose: * Compound spectrum/flux Frame. * Constructor Function: c astSpecFluxFrame f AST_SPECFLUXFRAME * Description: * A SpecFluxFrame combines a SpecFrame and a FluxFrame into a single * 2-dimensional compound Frame. Such a Frame can for instance be used * to describe a Plot of a spectrum in which the first axis represents * spectral position and the second axis represents flux. * Inheritance: * The SpecFluxFrame class inherits from the CmpFrame class. * Attributes: * The SpecFluxFrame class does not define any new attributes beyond * those which are applicable to all CmpFrames. However, the attributes * of the component Frames can be accessed as if they were attributes * of the SpecFluxFrame. For instance, the SpecFluxFrame will recognise * the "StdOfRest" attribute and forward access requests to the component * SpecFrame. An axis index can optionally be appended to the end of any * attribute name, in which case the request to access the attribute will * be forwarded to the primary Frame defining the specified axis. * Functions: c The SpecFluxFrame class does not define any new functions beyond those f The SpecFluxFrame class does not define any new routines beyond those * which are applicable to all CmpFrames. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 8-DEC-2004 (DSB): * Original version. * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SpecFluxFrame /* Define the first and last acceptable System values. */ #define FIRST_SYSTEM AST__COMP #define LAST_SYSTEM AST__COMP /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "mapping.h" /* Coordinate Mappings */ #include "unitmap.h" /* Unit Mappings */ #include "permmap.h" /* Coordinate permutation Mappings */ #include "cmpmap.h" /* Compound Mappings */ #include "axis.h" /* Coordinate axes */ #include "cmpframe.h" /* Parent CmpFrame class */ #include "tranmap.h" /* Separated transformation Mappings */ #include "mathmap.h" /* Algebraic Mappings */ #include "ratemap.h" /* Differential Mappings */ #include "specframe.h" /* SpecFrame class */ #include "fluxframe.h" /* FluxFrame class */ #include "specfluxframe.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static const char *(* parent_gettitle)( AstFrame *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetTitle_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SpecFluxFrame) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SpecFluxFrame,Class_Init) #define class_vtab astGLOBAL(SpecFluxFrame,Class_Vtab) #define gettitle_buff astGLOBAL(SpecFluxFrame,GetTitle_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char gettitle_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSpecFluxFrameVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSpecFluxFrame *astSpecFluxFrameId_( void *, void *, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *, int, int * ); static AstMapping *MakeMap2( AstSpecFluxFrame *, int * ); static AstMapping *MakeMap3( AstSpecFluxFrame *, AstSpecFluxFrame *, int * ); static AstMapping *MakeMapF( AstFluxFrame *, AstSpecFrame *, AstFluxFrame *, AstSpecFrame *, int * ); static AstMapping *MakeMapI( AstFluxFrame *, AstSpecFrame *, AstFluxFrame *, AstSpecFrame *, int * ); static AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *, int, int * ); static const char *GetTitle( AstFrame *, int * ); static int MakeSFMapping( AstSpecFluxFrame *, AstSpecFluxFrame *, AstMapping **, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static void Dump( AstObject *, AstChannel *, int * ); /* Member functions. */ /* ================= */ static AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *this, int std, int *status ){ /* * Name: * GetFluxFrame * Purpose: * Return a pointer to the FluxFrame in a FluxSpecFrame. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstFluxFrame *GetFluxFrame( AstSpecFluxFrame *this, int std, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * Returns a pointer to the FluxFrame in a SpecFluxFrame. * Parameters: * this * Pointer to the SpecFluxFrame. * std * If non zero, then the returned FluxFrame is a standardised copy of * the FluxFrame in the supplied SpecFluxFrame, in which the System has * been set explicitly (rather than potentially being defaulted), and * the Units have been cleared to use default units appropriate to * the flux System. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the FluxFrame. Should be freed using astAnnul when no * longer needed. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables; */ AstFluxFrame *ff; AstFluxFrame *ret; /* Check the global error status. */ if ( !astOK ) return NULL; /* The FluxFrame is always the second Frame in the parent CmpFrame. */ ff = (AstFluxFrame *) ((AstCmpFrame *)this)->frame2; /* Produce a standardised copy of the FluxFrame if required, or clone the above pointer otherwise. */ if( std ) { ret = astCopy( ff ); astSetSystem( ret, astGetSystem( ff ) ); astClearUnit( ret, 0 ); } else { ret = astClone( ff ); } /* Annul the returned pointer if anything went wrong. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result. */ return ret; } static AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *this, int std, int *status ){ /* * Name: * GetSpecFrame * Purpose: * Return a pointer to the SpecFrame in a FluxSpecFrame. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstSpecFrame *GetSpecFrame( AstSpecFluxFrame *this, int std, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * Returns a pointer to the SpecFrame in a SpecFluxFrame. * Parameters: * this * Pointer to the SpecFluxFrame. * std * If non zero, then the returned SpecFrame is a standardised copy of * the SpecFrame in the supplied SpecFluxFrame, in which the System * and Units have been set explicitly to the values appropriate to the * flux system in use in the FluxFrame in the supplied SpecFluxFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the FluxFrame. Should be freed using astAnnul when no * longer needed. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables; */ AstFluxFrame *ff; AstSpecFrame *ret; AstSpecFrame *sf; /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the SpecFrame (the first Frame in the parent CmpFrame). */ sf = (AstSpecFrame *) ((AstCmpFrame *)this)->frame1; /* If we want a standardised version of the SpecFrame... */ if( std ) { /* The FluxFrame is always the second Frame in the parent CmpFrame. */ ff = (AstFluxFrame *) ((AstCmpFrame *)this)->frame2; /* Produce a copy of the SpecFrame and set its System and Units appropriate to the flux system (expressed in default units). */ ret = astCopy( sf ); astSetSystem( ret, astGetDensitySystem( ff ) ); astSetUnit( ret, 0, astGetDensityUnit( ff ) ); /* If we are not standardising the SpecFrame, just return a clone of the pointer in the parent CmpFrame. */ } else { ret = astClone( sf ); } /* Annul the returned pointer if anything went wrong. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result. */ return ret; } static const char *GetTitle( AstFrame *this_frame, int *status ) { /* * Name: * GetTitle * Purpose: * Obtain a pointer to the Title string for a SpecFluxFrame. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * const char *GetTitle( AstFrame *this_frame, int *status ) * Class Membership: * SpecFluxFrame member function (over-rides the astGetTitle method * inherited from the CmpFrame class). * Description: * This function returns a pointer to the Title string for a SpecFluxFrame. * A pointer to a suitable default string is returned if no Title value has * previously been set. * Parameters: * this * Pointer to the SpecFluxFrame. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a null-terminated character string containing the requested * information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS AstSpecFluxFrame *this; AstSpecFrame *sf; AstFluxFrame *ff; const char *result; /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_frame); /* Initialise. */ result = NULL; /* Obtain a pointer to the SpecFluxFrame structure. */ this = (AstSpecFluxFrame *) this_frame; /* See if a Title string has been set. If so, use the parent astGetTitle method to obtain a pointer to it. */ if ( astTestTitle( this ) ) { result = (*parent_gettitle)( this_frame, status ); /* Otherwise, we will generate a default Title string. Obtain the values of the SpecFrame's attributes that determine what this string will be. */ } else { ff = GetFluxFrame( this, 0, status ); sf = GetSpecFrame( this, 0, status ); if( astOK ) { sprintf( gettitle_buff, "%s versus %s", astGetLabel( ff, 0 ), astGetLabel( sf, 0 ) ); gettitle_buff[ 0 ] = toupper( gettitle_buff[ 0 ] ); result = gettitle_buff; } ff = astAnnul( ff ); sf = astAnnul( sf ); } /* If an error occurred, clear the returned pointer value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } void astInitSpecFluxFrameVtab_( AstSpecFluxFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSpecFluxFrameVtab * Purpose: * Initialise a virtual function table for a SpecFluxFrame. * Type: * Protected function. * Synopsis: * #include "specfluxframe.h" * void astInitSpecFluxFrameVtab( AstSpecFluxFrameVtab *vtab, const char *name ) * Class Membership: * SpecFluxFrame vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SpecFluxFrame class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitCmpFrameVtab( (AstCmpFrameVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASpecFluxFrame) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstCmpFrameVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; frame = (AstFrameVtab *) vtab; mapping = (AstMappingVtab *) vtab; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ parent_match = frame->Match; frame->Match = Match; parent_subframe = frame->SubFrame; frame->SubFrame = SubFrame; parent_gettitle = frame->GetTitle; frame->GetTitle = GetTitle; /* Declare the copy constructor, destructor and class dump function. */ astSetDump( vtab, Dump, "SpecFluxFrame", "Compound spectral/flux coordinate system description" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static AstMapping *MakeMap2( AstSpecFluxFrame *this, int *status ){ /* * Name: * MakeMap2 * Purpose: * Generate the second Mapping required by MakeSFMapping * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstMapping *MakeMap2( AstSpecFluxFrame *this, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * The second Mapping used by MakeSFMapping contains three Mappings in * parallel which converts v1 (flux value) and x1 (spectral position) into * default units, and passes the third axis (a copy of flux value) * unchanged. * Parameters: * this * Pointer to the SpecFluxFrame to use. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the required Mapping, or NULL if the Mapping cannot be * created. The Mapping will have 3 inputs and 3 outputs. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables: */ AstFrame *f1; AstFrame *f2; AstFrameSet *fs; AstMapping *ax1_map; AstMapping *ax2_map; AstMapping *ax3_map; AstMapping *ret; AstMapping *tmap; /* Initialise. */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* Input 0 is the supplied FluxFrame value and output 0 is the corresponding value in the default units for the FluxFrame system. Take a copy of the supplied FluxFrame, and fix its System value (which may be a default value based on the Units string), and then clear the Units so that it represents default units for the System. */ f1 = (AstFrame *) GetFluxFrame( this, 0, status ); f2 = (AstFrame *) GetFluxFrame( this, 1, status ); /* Now, if conversion was possible, get the Mapping from the supplied FluxFrame to the default units FluxFrame. */ fs = astConvert( f1, f2, "" ); f1 = astAnnul( f1 ); f2 = astAnnul( f2 ); if( fs ) { ax1_map = astGetMapping( fs, AST__BASE, AST__CURRENT ); fs = astAnnul( fs ); /* Input 1 is the supplied SpecFrame value and output 1 is the corresponding value in the spectral system used by the flux system (wavelength or frequency). Take a copy of the supplied SpecFrame, and fix its System value to wavelength or frequency (depending on the System value of the FluxFrame), and set up units of Hz or Angstrom (these are the spectral position units used within the default flux units for a FluxFrame). */ f1 = (AstFrame *) GetSpecFrame( this, 0, status ); f2 = (AstFrame *) GetSpecFrame( this, 1, status ); /* Now, if conversion was possible, get the Mapping from the supplied SpecFrame to the required SpecFrame. */ fs = astConvert( f1, f2, "" ); f1 = astAnnul( f1 ); f2 = astAnnul( f2 ); if( fs ) { ax2_map = astGetMapping( fs, AST__BASE, AST__CURRENT ); fs = astAnnul( fs ); /* Create a UnitMap for the 3rd axis. */ ax3_map = (AstMapping *) astUnitMap( 1, "", status ); /* Create a parallel CmpMap containing the three Mappings. */ tmap = (AstMapping *) astCmpMap( ax1_map, ax2_map, 0, "", status ); ret = (AstMapping *) astCmpMap( tmap, ax3_map, 0, "", status ); /* Free remaining resources. */ tmap = astAnnul( tmap ); ax2_map = astAnnul( ax2_map ); ax3_map = astAnnul( ax3_map ); } ax1_map = astAnnul( ax1_map ); } /* If an error has occurred, return NULL. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result */ return ret; } static AstMapping *MakeMap3( AstSpecFluxFrame *target, AstSpecFluxFrame *result, int *status ){ /* * Name: * MakeMap3 * Purpose: * Generate the third Mapping required by MakeSFMapping * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstMapping *MakeMap3( AstSpecFluxFrame *target, AstSpecFluxFrame *result, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * The third Mapping used by MakeSFMapping converts input (v1,x1) in * default units to output (v2,x2) in default units. The third axis (x1) * in original units is converted to x2 in original units. * Parameters: * target * Pointer to the first SpecFluxFrame. * result * Pointer to the second SpecFluxFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the required Mapping, or NULL if the Mapping cannot be * created. The Mapping will have 3 inputs and 3 outputs. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables: */ AstFluxFrame *ff2; AstFluxFrame *ff1; AstFrameSet *fs; AstMapping *fmap; AstMapping *imap; AstMapping *mapa; AstMapping *mapb; AstMapping *ret; AstSpecFrame *sf2; AstSpecFrame *sf1; /* Initialise */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* The first two inputs and outputs are related by a TranMap which converts between standardised (v1,x1) and standardised (v2,x2). Get pointers to the standardised SpecFrames and FluxFrames in the two supplied SpecFluxFrames. */ ff1 = GetFluxFrame( target, 1, status ); sf1 = GetSpecFrame( target, 1, status ); ff2 = GetFluxFrame( result, 1, status ); sf2 = GetSpecFrame( result, 1, status ); /* Create the Mapping which defines the forward transformation of the required TranMap. The forward transformation of this Mapping goes from (v1,x1) to (v2,x2). */ fmap = MakeMapF( ff1, sf1, ff2, sf2, status ); /* Create the Mapping which defines the inverse transformation of the required TranMap. The inverse transformation of this Mapping goes from (v2,x2) to (v1,x1). */ imap = MakeMapI( ff1, sf1, ff2, sf2, status ); /* Combine these into a TranMap */ if( fmap && imap ) { mapa = (AstMapping *) astTranMap( fmap, imap, "", status ); } else { mapa = NULL; } /* Free resources. */ ff1 = astAnnul( ff1 ); sf1 = astAnnul( sf1 ); ff2 = astAnnul( ff2 ); sf2 = astAnnul( sf2 ); if( fmap ) fmap = astAnnul( fmap ); if( imap ) imap = astAnnul( imap ); /* The third input and output are related by a Mapping which converts between supplied (x1) and supplied (x2). Get pointers to the original unmodified SpecFrames in the two supplied SpecFluxFrames. */ sf1 = GetSpecFrame( target, 0, status ); sf2 = GetSpecFrame( result, 0, status ); /* Find the Mapping from the first to the second. */ fs = astConvert( sf1, sf2, "" ); if( fs ) { mapb = astGetMapping( fs, AST__BASE, AST__CURRENT ); fs = astAnnul( fs ); } else { mapb = NULL; } /* Free resources. */ sf1 = astAnnul( sf1 ); sf2 = astAnnul( sf2 ); /* Combine the two Mappings in parallel. */ if( mapa && mapb ) ret = (AstMapping *) astCmpMap( mapa, mapb, 0, "", status ); if( mapa ) mapa = astAnnul( mapa ); if( mapb ) mapb = astAnnul( mapb ); /* If an error has occurred, return NULL. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result */ return ret; } static AstMapping *MakeMapF( AstFluxFrame *v1, AstSpecFrame *x1, AstFluxFrame *v2, AstSpecFrame *x2, int *status ){ /* * Name: * MakeMapF * Purpose: * Generate the forward part of the third Mapping required by MakeSFMapping * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstMapping *MakeMapF( AstFluxFrame *v1, AstSpecFrame *x1, * AstFluxFrame *v2, AstSpecFrame *x2, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * Theis creates a 2-input 2-output Mapping which transforms * input (v1,x1) in default units to output (v2,x2) in default units. * Parameters: * v1 * Pointer to the standardised input FluxFrame. * x1 * Pointer to the standardised input SpecFrame. * v2 * Pointer to the standardised output FluxFrame. * x2 * Pointer to the standardised output SpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the required Mapping, or NULL if the Mapping cannot be * created. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables: */ AstCmpMap *cmap1; AstCmpMap *cmap2; AstCmpMap *cmap3; AstFrameSet *fs; AstMapping *m; AstMapping *ret; AstMathMap *div; AstPermMap *perm; AstRateMap *rate; AstUnitMap *unit; const char *fwd[1]; const char *inv[2]; int inperm[ 2 ]; int outperm[ 3 ]; /* Initialise */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* First create the required component Mappings. --------------------------------------------- */ /* A Mapping which maps input spectral position (x1) into output spectral position (x2). */ fs = astConvert( x1, x2, "" ); if( fs ) { m = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* A 1-input 1-output Mapping in which the input is spectral position (x1) and the output is the rate of change of output spectral position (x2) with respect to input spectral position (x1). */ rate = astRateMap( m, 0, 0, "", status ); /* A MathMap which is used to divide the flux value (v1) by the absolute rate of change of x2 wrt x1 */ fwd[ 0 ] = "out=in0/abs(in1)"; inv[ 0 ] = "in0"; inv[ 1 ] = "in1"; div = astMathMap( 2, 1, 1, fwd, 2, inv, "", status ); /* A 1D UnitMap used to copy v1. */ unit = astUnitMap( 1, "", status ); /* A PermMap which is used to produce an extra output copy of x1. */ inperm[ 0 ] = 0; inperm[ 1 ] = 2; outperm[ 0 ] = 0; outperm[ 1 ] = 1; outperm[ 2 ] = 1; perm = astPermMap( 2, inperm, 3, outperm, NULL, "", status ); /* Now combine these component Mappings together. --------------------------------------------- */ /* First put the UnitMap and the RateMap in parallel. This produces a 2-in 2-out Mapping in which the inputs are (v1,x1) and the outputs are (v1,dx2/dx1). */ cmap1 = astCmpMap( unit, rate, 0, "", status ); /* Now put this in series with the dividing MathMap. This results in a 2-in, 1-out Mapping in which the inputs are v1 and x1 and the single output is v2. */ cmap2 = astCmpMap( cmap1, div, 1, "", status ); /* Now put this in parallel with the x1->x2 Mapping. This results in a 3-in, 2-out Mapping in which the inputs are (v1,x1,x1) and the outputs are (v2,x2). */ cmap3 = astCmpMap( cmap2, m, 0, "", status ); /* Finally put this in series with the PermMap. This results in a 2-in, 2-out Mapping in which the inputs are (v1,x1) and the outputs are (v2,x2). */ ret = (AstMapping *) astCmpMap( perm, cmap3, 1, "", status ); /* Free resources. */ fs = astAnnul( fs ); m = astAnnul( m ); rate = astAnnul( rate ); div= astAnnul( div ); unit = astAnnul( unit ); perm = astAnnul( perm ); cmap1 = astAnnul( cmap1 ); cmap2 = astAnnul( cmap2 ); cmap3 = astAnnul( cmap3 ); } /* If an error has occurred, return NULL. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result */ return ret; } static AstMapping *MakeMapI( AstFluxFrame *v1, AstSpecFrame *x1, AstFluxFrame *v2, AstSpecFrame *x2, int *status ){ /* * Name: * MakeMapI * Purpose: * Generate the inverse part of the third Mapping required by MakeSFMapping * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstMapping *MakeMapI( AstFluxFrame *v1, AstSpecFrame *x1, * AstFluxFrame *v2, AstSpecFrame *x2 ) * Class Membership: * SpecFluxFrame member function. * Description: * This creates a 2-input 2-output Mapping in which the inverse * transformation transforms "outputs" representing (v2,x2) into * "inputs" representing (v1,x1). * Parameters: * v1 * Pointer to the standardised input FluxFrame. * x1 * Pointer to the standardised input SpecFrame. * v2 * Pointer to the standardised output FluxFrame. * x2 * Pointer to the standardised output SpecFrame. * Returned Value: * A pointer to the required Mapping, or NULL if the Mapping cannot be * created. * Notes: * NULL is returned if this function is invoked with the global error * status set or if it should fail for any reason. */ /* Local Variables: */ AstCmpMap *cmap1; AstCmpMap *cmap2; AstCmpMap *cmap3; AstCmpMap *cmap4; AstCmpMap *cmap5; AstFrameSet *fs; AstMapping *m; AstMapping *ret; AstMathMap *mult; AstPermMap *perm; AstRateMap *rate; AstUnitMap *unit; const char *fwd[1]; const char *inv[2]; int inperm[ 2 ]; int outperm[ 3 ]; /* Initialise */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* We create a CmpMap in which the forward transformation foes from (v2,x2) to (v1,x1) and we finally invert this Mapping to get the required Mapping in which the *inverse* transformation goes from (v2,x2) to (v1,x1). First create the required component Mappings. --------------------------------------------- */ /* A Mapping which maps spectral position x1 into spectral position x2. */ fs = astConvert( x1, x2, "" ); if( fs ) { m = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* A 1-input 1-output Mapping in which the input is spectral position x1 and the output is the rate of change of spectral position x2 with respect to spectral position x1. */ rate = astRateMap( m, 0, 0, "", status ); /* Now invert "m" so that its forward transformation goes from x2 to x1. The RateMap created above retains a copy of the original Invert flag for "m" and uses it in preference to the current value when transforming points. */ astInvert( m ); /* A MathMap which is used to multiple the flux value v2 by the absolute rate of change of x2 wrt x1 */ fwd[ 0 ] = "out=in0*abs(in1)"; inv[ 0 ] = "in0"; inv[ 1 ] = "in1"; mult = astMathMap( 2, 1, 1, fwd, 2, inv, "", status ); /* A 1D UnitMap used to copy various values. */ unit = astUnitMap( 1, "", status ); /* A PermMap which is used to produce an extra copy of x1. */ inperm[ 0 ] = 0; inperm[ 1 ] = 2; outperm[ 0 ] = 0; outperm[ 1 ] = 1; outperm[ 2 ] = 1; perm = astPermMap( 2, inperm, 3, outperm, NULL, "", status ); /* Now combine these component Mappings together. --------------------------------------------- */ /* First put the UnitMap and the RateMap in parallel. This produces a 2-in 2-out Mapping in which the inputs are (v2,x1) and the outputs are (v2,dx2/dx1). */ cmap1 = astCmpMap( unit, rate, 0, "", status ); /* Now put this in series with the multiplying MathMap. This results in a 2-in, 1-out Mapping in which the inputs are (v2,x1) and the single output is v1. */ cmap2 = astCmpMap( cmap1, mult, 1, "", status ); /* Now put this in parallel with the UnitMap to get a 3-in, 2-out Mapping in which the inputs are (v2,x1,x1) and the outputs are (v1,x1). */ cmap3 = astCmpMap( cmap2, unit, 0, "", status ); /* Now put this in series with the PermMap to get a 2-in, 2-out Mapping in which the inputs are (v2,x1) and the outputs are (v1,x1). */ cmap4 = astCmpMap( perm, cmap3, 1, "", status ); /* Now put the UnitMap in parallel with the (x2->x1 Mapping to get a 2-in, 2-out Mapping in which the inputs are (v2,x2) and the outputs are (v2,x1). */ cmap5 = astCmpMap( unit, m, 0, "", status ); /* Finally put this in series with "cmap4" to get a 2-in 2-out Mapping from (v2,x2) to (v1,x1). */ ret = (AstMapping *) astCmpMap( cmap5, cmap4, 1, "", status ); /* Invert this so that the inverse transformation goes from (v2,x2) to (v1,x1). */ astInvert( ret ); /* Free resources. */ fs = astAnnul( fs ); m = astAnnul( m ); rate = astAnnul( rate ); mult = astAnnul( mult ); unit = astAnnul( unit ); perm = astAnnul( perm ); cmap1 = astAnnul( cmap1 ); cmap2 = astAnnul( cmap2 ); cmap3 = astAnnul( cmap3 ); cmap4 = astAnnul( cmap4 ); cmap5 = astAnnul( cmap5 ); } /* If an error has occurred, return NULL. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result */ return ret; } static int MakeSFMapping( AstSpecFluxFrame *target, AstSpecFluxFrame *result, AstMapping **map, int *status ){ /* * Name: * MakeSFMapping * Purpose: * Generate a Mapping between two SpecFluxFrames. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * int MakeSFMapping( AstSpecFluxFrame *target, AstSpecFluxFrame *result, * AstMapping **map, int *status ) * Class Membership: * SpecFluxFrame member function. * Description: * This function takes two SpecFluxFrames and generates a Mapping that * converts between them, taking account of differences in their * coordinate systems, systems, units, etc. (but not allowing for any * axis permutations). * Parameters: * target * Pointer to the first SpecFluxFrame. * result * Pointer to the second SpecFluxFrame. * map * Pointer to a location which is to receive a pointer to the * returned Mapping. The forward transformation of this Mapping * will convert from "target" coordinates to "result" * coordinates, and the inverse transformation will convert in * the opposite direction (all coordinate values in radians). * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Mapping could be generated, or zero if the two * SpecFluxFrames are sufficiently un-related that no meaningful Mapping * can be produced. * Notes: * A value of zero is returned if this function is invoked with the * global error status set or if it should fail for any reason. */ /* Local Variables: */ AstMapping *map1; AstMapping *map2; AstMapping *map3; AstMapping *map4; AstMapping *map5; AstMapping *tmap1; AstMapping *tmap2; AstMapping *tmap3; AstMapping *tmap4; int inperm[2]; int match; int outperm[3]; /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise the returned values. */ match = 0; *map = NULL; /* Initialise other things. */ map1 = NULL; map2 = NULL; map3 = NULL; map4 = NULL; map5 = NULL; tmap1 = NULL; tmap2 = NULL; tmap3 = NULL; tmap4 = NULL; /* At the top level, the required Mapping consists of five Mappings in series. Inputs 0 and 1 of the total Mapping correspond to the SpecFrame and FluxFrame in the target SpecFluxFrame. These are referred to as X1 and V1. Outputs 0 and 1 of the total Mapping correspond to the SpecFrame and FluxFrame in the result SpecFluxFrame. These are referred to as X2 and V2. */ /* Map1 is a PermMap which copies v1 to its first output and x1 to its second and third outputs. The inverse transformation copies v1 from its first output and x1 from its third output. */ inperm[ 0 ] = 2; inperm[ 1 ] = 0; outperm[ 0 ] = 1; outperm[ 1 ] = 0; outperm[ 2 ] = 0; map1 = (AstMapping *) astPermMap( 2, inperm, 3, outperm, NULL, "", status ); /* Map2 contains three Mappings in parallel which converts v1 and x1 into default units, and passes the third axis unchanged. */ map2 = MakeMap2( target, status ); /* Map3 converts ( v1,x1) in default units to (v2,x2) in default units. The third axis (x1) in original units is convert to x2 in original units. */ map3 = map2 ? MakeMap3( target, result, status ) : NULL; /* Map4 converts (v2,x2) in default units to (v2,x2) in original units and passes the third axis unchanged. This is similar to Map2 but based on the result ratherthan the target, and in the opposite direction. */ if( map3 ) { map4 = MakeMap2( result, status ); if( map4 ) astInvert( map4 ); } else { map4 = NULL; } /* Map5 is a PermMap which is the inverse of Map1. */ map5 = map4 ? astCopy( map1 ) : NULL; if( map5 ) astInvert( map5 ); /* Combine all 6 Mappings in series. */ if( map5 ) { tmap1 = (AstMapping *) astCmpMap( map1, map2, 1, "", status ); tmap2 = (AstMapping *) astCmpMap( tmap1, map3, 1, "", status ); tmap3 = (AstMapping *) astCmpMap( tmap2, map4, 1, "", status ); tmap4 = (AstMapping *) astCmpMap( tmap3, map5, 1, "", status ); /* Return the simplified total Mapping. */ *map = astSimplify( tmap4 ); match = 1; } /* Free resources. */ if( map1 ) map1 = astAnnul( map1 ); if( map2 ) map2 = astAnnul( map2 ); if( map3 ) map3 = astAnnul( map3 ); if( map4 ) map4 = astAnnul( map4 ); if( map5 ) map5 = astAnnul( map5 ); if( tmap1 ) tmap1 = astAnnul( tmap1 ); if( tmap2 ) tmap2 = astAnnul( tmap2 ); if( tmap3 ) tmap3 = astAnnul( tmap3 ); if( tmap4 ) tmap4 = astAnnul( tmap4 ); /* If an error occurred, annul the returned Mapping and clear the returned values. */ if ( !astOK ) { *map = astAnnul( *map ); match = 0; } /* Return the result. */ return match; } static int Match( AstFrame *template_frame, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * Match * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * int Match( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * SpecFluxFrame member function (over-rides the protected astMatch * method inherited from the Frame class). * Description: * This function matches a "template" SpecFluxFrame to a "target" Frame * and determines whether it is possible to convert coordinates * between them. If it is, a Mapping that performs the * transformation is returned along with a new Frame that describes * the coordinate system that results when this Mapping is applied * to the "target" coordinate system. In addition, information is * returned to allow the axes in this "result" Frame to be * associated with the corresponding axes in the "target" Frame and * "template" SpecFluxFrame from which they are derived. * Parameters: * template * Pointer to the template SpecFluxFrame. This describes the * coordinate system (or set of possible coordinate systems) * into which we wish to convert our coordinates. * target * Pointer to the target Frame. This describes the coordinate * system in which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case. * template_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the (zero-based) index of the * template SpecFluxFrame axis from which it is derived. If it is not * derived from any template axis, a value of -1 will be * returned instead. * target_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the (zero-based) index of the * target Frame axis from which it is derived. If it is not * derived from any target axis, a value of -1 will be returned * instead. * map * Address of a location where a pointer to a new Mapping will * be returned if the requested coordinate conversion is * possible. If returned, the forward transformation of this * Mapping may be used to convert coordinates between the * "target" Frame and the "result" Frame (see below) and the * inverse transformation will convert in the opposite * direction. * result * Address of a location where a pointer to a new Frame will be * returned if the requested coordinate conversion is * possible. If returned, this Frame describes the coordinate * system that results from applying the returned Mapping * (above) to the "target" coordinate system. In general, this * Frame will combine attributes from (and will therefore be * more specific than) both the target Frame and the template * SpecFluxFrame. In particular, when the template allows the * possibility of transformaing to any one of a set of * alternative coordinate systems, the "result" Frame will * indicate which of the alternatives was used. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the requested coordinate * conversion is possible. Otherwise zero is returned (this will * not in itself result in an error condition). * Notes: * - By default, the "result" Frame will have its number of axes * and axis order determined by the "template" SpecFluxFrame. However, * if the PreserveAxes attribute of the template SpecFluxFrame is * non-zero, then the axis count and axis order of the "target" * Frame will be used instead. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstSpecFluxFrame *template; /* Pointer to template SpecFluxFrame structure */ int match; /* Coordinate conversion possible? */ int swap1; /* Template axes swapped? */ int swap2; /* Target axes swapped? */ int swap; /* Additional axis swap needed? */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain a pointer to the template SpecFluxFrame structure. */ template = (AstSpecFluxFrame *) template_frame; /* If the target is not a SpecFluxFrame, use the results returned by the parent Match method inherited from the CmpFrame class. */ if( !astIsASpecFluxFrame( target ) ) { match = (*parent_match)( template_frame, target, matchsub, template_axes, target_axes, map, result, status ); /* If the target is a SpecFluxFrame, see if we can convert between target and template */ } else { /* We must now decide how the order of the axes in the result Frame relates to the order of axes in the target Frame. There are two factors involved. The first depends on whether the axis permutation array for the template SpecFluxFrame (whose method we are executing) causes an axis reversal. Determine this by permuting axis index zero. */ swap1 = ( astValidateAxis( template, 0, 1, "astMatch" ) != 0 ); /* The second factor depends on whether the axes of the target SpecFluxFrame causes an axis reversal. Determine this by permuting axis index zero. */ swap2 = ( astValidateAxis( target, 0, 1, "astMatch" ) != 0 ); /* Combine these to determine if an additional axis swap will be needed. */ swap = ( swap1 != swap2 ); /* Now check to see if this additional swap is permitted by the template's Permute attribute. */ match = ( !swap || astGetPermute( template ) ); /* Allocate the target and template axes arrays. */ *template_axes = astMalloc( sizeof(int)*2 ); *target_axes = astMalloc( sizeof(int)*2 ); /* If the Frames still match, we next set up the axis association arrays. */ if ( astOK && match ) { /* If the target axis order is to be preserved, then the target axis association involves no permutation but the template axis association may involve an axis swap. */ if ( astGetPreserveAxes( template ) ) { (*template_axes)[ 0 ] = swap; (*template_axes)[ 1 ] = !swap; (*target_axes)[ 0 ] = 0; (*target_axes)[ 1 ] = 1; /* Otherwise, any swap applies to the target axis association instead. */ } else { (*template_axes)[ 0 ] = 0; (*template_axes)[ 1 ] = 1; (*target_axes)[ 0 ] = swap; (*target_axes)[ 1 ] = !swap; } /* Use the target's "astSubFrame" method to create a new Frame (the result Frame) with copies of the target axes in the required order. This process also overlays the template attributes on to the target Frame and returns a Mapping between the target and result Frames which effects the required coordinate conversion. */ match = astSubFrame( target, template, 2, *target_axes, *template_axes, map, result ); /* If an error occurred, or conversion to the result Frame's coordinate system was not possible, then free all memory, annul the returned objects, and reset the returned value. */ if ( !astOK || !match ) { *template_axes = astFree( *template_axes ); *target_axes = astFree( *target_axes ); if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } } } /* Return the result. */ return match; } static int SubFrame( AstFrame *target_frame, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * SubFrame * Purpose: * Select axes from a SpecFluxFrame and convert to the new coordinate system. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * int SubFrame( AstFrame *target, AstFrame *template, * int result_naxes, const int *target_axes, * const int *template_axes, AstMapping **map, * AstFrame **result, int *status ) * Class Membership: * SpecFluxFrame member function (over-rides the protected astSubFrame * method inherited from the Frame class). * Description: * This function selects a requested sub-set (or super-set) of the * axes from a "target" SpecFluxFrame and creates a new Frame with * copies of the selected axes assembled in the requested order. It * then optionally overlays the attributes of a "template" Frame on * to the result. It returns both the resulting Frame and a Mapping * that describes how to convert between the coordinate systems * described by the target and result Frames. If necessary, this * Mapping takes account of any differences in the Frames' * attributes due to the influence of the template. * Parameters: * target * Pointer to the target SpecFluxFrame, from which axes are to be selected. * template * Pointer to the template Frame, from which new attributes for * the result Frame are to be obtained. Optionally, this may be * NULL, in which case no overlaying of template attributes will * be performed. * result_naxes * Number of axes to be selected from the target Frame. This * number may be greater than or less than the number of axes in * this Frame (or equal). * target_axes * Pointer to an array of int with result_naxes elements, giving * a list of the (zero-based) axis indices of the axes to be * selected from the target SpecFluxFrame. The order in which these * are given determines the order in which the axes appear in * the result Frame. If any of the values in this array is set * to -1, the corresponding result axis will not be derived from * the target Frame, but will be assigned default attributes * instead. * template_axes * Pointer to an array of int with result_naxes elements. This * should contain a list of the template axes (given as * zero-based axis indices) with which the axes of the result * Frame are to be associated. This array determines which axes * are used when overlaying axis-dependent attributes of the * template on to the result. If any element of this array is * set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not * used and a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned * Mapping. The forward transformation of this Mapping will * describe how to convert coordinates from the coordinate * system described by the target SpecFluxFrame to that described by * the result Frame. The inverse transformation will convert in * the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if coordinate conversion is * possible between the target and the result Frame. Otherwise zero * is returned and *map and *result are returned as NULL (but this * will not in itself result in an error condition). In general, * coordinate conversion should always be possible if no template * Frame is supplied but may not always be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * Implementation Deficiencies: * - It is not clear that the method of handling "extra" axes is * the best one, nor is the method of setting the "following" flag * necessarily correct. However, it is also not obvious that this * feature will ever be needed, so improvements have been left * until the requirement is clearer. */ /* Local Variables: */ AstMapping *tmpmap; /* Temporary Mapping pointer */ AstPermMap *permmap; /* Pointer to PermMap */ AstSpecFluxFrame *target; /* Pointer to target SpecFluxFrame structure */ int match; /* Coordinate conversion is possible? */ int perm[ 2 ]; /* Permutation array for axis swap */ int result_swap; /* Swap result SpecFluxFrame coordinates? */ int target_swap; /* Swap target SpecFluxFrame coordinates? */ /* Initialise the returned values. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* If the template is not a SpecFluxFrame we use the parent SubFrame method inherited form the CmpFrame class. */ if( !template || !astIsASpecFluxFrame( template ) || result_naxes != 2 ) { match = (*parent_subframe)( target_frame, template, result_naxes, target_axes, template_axes, map, result, status ); /* Otherwise... */ } else { /* Obtain a pointer to the target SpecFluxFrame structure. */ target = (AstSpecFluxFrame *) target_frame; /* Form the result from a copy of the target and then permute its axes into the order required. */ *result = astCopy( target ); astPermAxes( *result, target_axes ); /* Overlay the template attributes on to the result SpecFrame. */ astOverlay( template, template_axes, *result ); /* Generate a Mapping that takes account of changes in the coordinate system (system, units, etc.) between the target SpecFluxFrame and the result SpecFluxFrame. If this Mapping can be generated, set "match" to indicate that coordinate conversion is possible. */ match = MakeSFMapping( target, (AstSpecFluxFrame *) *result, map, status ); /* If a Mapping has been obtained, it will expect coordinate values to be supplied in (flux,spec) pairs. Test whether we need to swap the order of the target SpecFluxFrame coordinates to conform with this. */ if ( astOK && match ) { target_swap = ( astValidateAxis( target, 0, 1, "astSubFrame" ) != 0 ); /* Coordinates will also be delivered in (flux,spec) pairs, so check to see whether the result SpecFluxFrame coordinate order should be swapped. */ result_swap = ( target_swap != ( target_axes[ 0 ] != 0 ) ); /* If either set of coordinates needs swapping, create a PermMap that will swap a pair of coordinates. */ permmap = NULL; if ( target_swap || result_swap ) { perm[ 0 ] = 1; perm[ 1 ] = 0; permmap = astPermMap( 2, perm, 2, perm, NULL, "", status ); } /* If necessary, prefix this PermMap to the main Mapping. */ if ( target_swap ) { tmpmap = (AstMapping *) astCmpMap( permmap, *map, 1, "", status ); *map = astAnnul( *map ); *map = tmpmap; } /* Also, if necessary, append it to the main Mapping. */ if ( result_swap ) { tmpmap = (AstMapping *) astCmpMap( *map, permmap, 1, "", status ); *map = astAnnul( *map ); *map = tmpmap; } /* Annul the pointer to the PermMap (if created). */ if ( permmap ) permmap = astAnnul( permmap ); } } /* If an error occurred, clean up by annulling the result pointers and returning appropriate null values. */ if ( !astOK ) { *map = astAnnul( *map ); *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with the axes of a SpecFluxFrame using the private macros defined for this purpose at the start of this file. */ /* Copy constructor. */ /* ----------------- */ /* Destructor. */ /* ----------- */ /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SpecFluxFrame objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the SpecFluxFrame class to an output Channel. * Parameters: * this * Pointer to the SpecFluxFrame whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSpecFluxFrame *this; /* Pointer to the SpecFluxFrame structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SpecFluxFrame structure. */ this = (AstSpecFluxFrame *) this_object; /* Write out values representing the instance variables for the SpecFluxFrame class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASpecFluxFrame and astCheckSpecFluxFrame functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SpecFluxFrame,CmpFrame) astMAKE_CHECK(SpecFluxFrame) AstSpecFluxFrame *astSpecFluxFrame_( void *frame1_void, void *frame2_void, const char *options, int *status, ...) { /* *++ * Name: c astSpecFluxFrame f AST_SPECFLUXFRAME * Purpose: * Create a SpecFluxFrame. * Type: * Public function. * Synopsis: c #include "specfluxframe.h" c AstSpecFluxFrame *astSpecFluxFrame( AstSpecFrame *frame1, AstFluxFrame *frame2, c const char *options, ... ) f RESULT = AST_SPECFLUXFRAME( FRAME1, FRAME2, OPTIONS, STATUS ) * Class Membership: * SpecFluxFrame constructor. * Description: * This function creates a new SpecFluxFrame and optionally initialises * its attributes. * * A SpecFluxFrame combines a SpecFrame and a FluxFrame into a single * 2-dimensional compound Frame. Such a Frame can for instance be used * to describe a Plot of a spectrum in which the first axis represents * spectral position and the second axis represents flux. * Parameters: c frame1 f FRAME1 = INTEGER (Given) * Pointer to the SpecFrame. This will form the first axis in the * new SpecFluxFrame. c frame2 f FRAME2 = INTEGER (Given) * Pointer to the FluxFrame. This will form the second axis in the * new SpecFluxFrame. The "SpecVal" attribute of this FluxFrame is * not used by the SpecFluxFrame class and so may be set to AST__BAD * when the FluxFrame is created. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SpecFluxFrame. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SpecFluxFrame. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSpecFluxFrame() f AST_SPECFLUXFRAME = INTEGER * A pointer to the new SpecFluxFrame. * Notes: * - The supplied Frame pointers are stored directly, rather than * being used to create deep copies of the supplied Frames. This means * that any subsequent changes made to the Frames via the supplied * pointers will result in equivalent changes being visible in the * SpecFluxFrame. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- * Implementation Notes: * - This function implements the basic SpecFluxFrame constructor which * is available via the protected interface to the SpecFluxFrame class. * A public interface is provided by the astSpecFluxFrameId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "frame1" and "frame2" parameters are of type (void *) and are * converted and validated within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSpecFluxFrame *new; /* Pointer to new SpecFluxFrame */ AstFluxFrame *frame2; /* Pointer to FluxFrame structure */ AstSpecFrame *frame1; /* Pointer to SpecFrame structure */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ new = NULL; if ( !astOK ) return new; /* Obtain and validate pointers to the Frame structures provided. */ frame1 = astCheckSpecFrame( frame1_void ); frame2 = astCheckFluxFrame( frame2_void ); if ( astOK ) { /* Initialise the SpecFluxFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSpecFluxFrame( NULL, sizeof( AstSpecFluxFrame ), !class_init, &class_vtab, "SpecFluxFrame", frame1, frame2 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SpecFluxFrame's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new SpecFluxFrame. */ return new; } AstSpecFluxFrame *astSpecFluxFrameId_( void *frame1_void, void *frame2_void, const char *options, ... ) { /* * Name: * astSpecFluxFrameId_ * Purpose: * Create a SpecFluxFrame. * Type: * Private function. * Synopsis: * #include "specfluxframe.h" * AstSpecFluxFrame *astSpecFluxFrameId_( void *frame1_void, void *frame2_void, * const char *options, ... ) * Class Membership: * SpecFluxFrame constructor. * Description: * This function implements the external (public) interface to the * astSpecFluxFrame constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astSpecFluxFrame_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). For the same reason, the "frame1" and "frame2" * parameters are of type (void *) and are converted and validated * within the function itself. * * The variable argument list also prevents this function from * invoking astSpecFluxFrame_ directly, so it must be a * re-implementation of it in all respects, except for the final * conversion of the result to an ID value. * Parameters: * As for astSpecFluxFrame_. * Returned Value: * The ID value associated with the new SpecFluxFrame. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSpecFluxFrame *new; /* Pointer to new SpecFluxFrame */ AstSpecFrame *frame1; /* Pointer to first Frame structure */ AstFluxFrame *frame2; /* Pointer to second Frame structure */ va_list args; /* Variable argument list */ int *status; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ new = NULL; if ( !astOK ) return new; /* Obtain the Frame pointers from the ID's supplied and validate the pointers to ensure they identify valid Frames. */ frame1 = astVerifySpecFrame( astMakePointer( frame1_void ) ); frame2 = astVerifyFluxFrame( astMakePointer( frame2_void ) ); if ( astOK ) { /* Initialise the SpecFluxFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSpecFluxFrame( NULL, sizeof( AstSpecFluxFrame ), !class_init, &class_vtab, "SpecFluxFrame", frame1, frame2 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SpecFluxFrame's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return an ID value for the new SpecFluxFrame. */ return astMakeId( new ); } AstSpecFluxFrame *astInitSpecFluxFrame_( void *mem, size_t size, int init, AstSpecFluxFrameVtab *vtab, const char *name, AstSpecFrame *frame1, AstFluxFrame *frame2, int *status ) { /* *+ * Name: * astInitSpecFluxFrame * Purpose: * Initialise a SpecFluxFrame. * Type: * Protected function. * Synopsis: * #include "specfluxframe.h" * AstSpecFluxFrame *astInitSpecFluxFrame( void *mem, size_t size, int init, * AstSpecFluxFrameVtab *vtab, const char *name, * AstSpecFrame *frame1, AstFluxFrame *frame2 ) * Class Membership: * SpecFluxFrame initialiser. * Description: * This function is provided for use by class implementations to * initialise a new SpecFluxFrame object. It allocates memory (if * necessary) to accommodate the SpecFluxFrame plus any additional data * associated with the derived class. It then initialises a * SpecFluxFrame structure at the start of this memory. If the "init" * flag is set, it also initialises the contents of a virtual * function table for a SpecFluxFrame at the start of the memory passed * via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SpecFluxFrame is to be * created. This must be of sufficient size to accommodate the * SpecFluxFrame data (sizeof(SpecFluxFrame)) plus any data used by the * derived class. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SpecFluxFrame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SpecFluxFrame structure, so a valid value must be * supplied even if not required for allocating memory. * init * A logical flag indicating if the SpecFluxFrame's virtual function * table is to be initialised. If this value is non-zero, the * virtual function table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be * associated with the new SpecFluxFrame. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the Object astClass function). * frame1 * Pointer to the SpecFrame * frame2 * Pointer to the FluxFrame * Returned Value: * A pointer to the new SpecFluxFrame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstSpecFluxFrame *new; /* Pointer to new SpecFluxFrame */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSpecFluxFrameVtab( vtab, name ); /* Initialise a Frame structure (the parent class) as the first component within the SpecFluxFrame structure, allocating memory if necessary. Set the number of Frame axes to zero, since all axis information is stored within the component Frames. */ new = astInitCmpFrame( mem, size, 0, (AstCmpFrameVtab *) vtab, name, frame1, frame2 ); if ( astOK ) { /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstSpecFluxFrame *astLoadSpecFluxFrame_( void *mem, size_t size, AstSpecFluxFrameVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSpecFluxFrame * Purpose: * Load a SpecFluxFrame. * Type: * Protected function. * Synopsis: * #include "specfluxframe.h" * AstSpecFluxFrame *astLoadSpecFluxFrame( void *mem, size_t size, * AstSpecFluxFrameVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * SpecFluxFrame loader. * Description: * This function is provided to load a new SpecFluxFrame using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SpecFluxFrame structure in this memory, using data read from the * input Channel. * Parameters: * mem * A pointer to the memory into which the SpecFluxFrame is to be * loaded. This must be of sufficient size to accommodate the * SpecFluxFrame data (sizeof(SpecFluxFrame)) plus any data used by * derived classes. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SpecFluxFrame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SpecFluxFrame structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSpecFluxFrame) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SpecFluxFrame. If this is NULL, a pointer * to the (static) virtual function table for the SpecFluxFrame class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SpecFluxFrame" is used instead. * Returned Value: * A pointer to the new SpecFluxFrame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstSpecFluxFrame *new; /* Pointer to the new SpecFluxFrame */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SpecFluxFrame. In this case the SpecFluxFrame belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSpecFluxFrame ); vtab = &class_vtab; name = "SpecFluxFrame"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSpecFluxFrameVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SpecFluxFrame. */ new = astLoadCmpFrame( mem, size, (AstCmpFrameVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SpecFluxFrame" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* (none) */ /* If an error occurred, clean up by deleting the new SpecFluxFrame. */ if ( !astOK ) new = astDelete( new ); } /* Return the new SpecFluxFrame pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/grf3d.h0000644000175000017500000000407012262533650012321 0ustar olesoles#if !defined( GRF3D_INCLUDED ) /* Include this file only once */ #define GRF3D_INCLUDED /* *+ * Name: * grf3d.h * Type: * C include file. * Purpose: * Define the interface to the grf3d module * Invocation: * #include "grf3d.h" * Description: * This include file defines the interface to the grf3d module and * provides the type definitions, function prototypes and macros, etc. * needed to use this module. * Inheritance: * The grf3d module is not a class and does not inherit. * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (JACH - UCLan) * History: * 20-JUN-2007 (DSB): * Original version. *- */ /* Include the 2D grf header file in order to inherit the GRF__ macros. */ #include "grf.h" /* Function prototypes. */ /* ==================== */ int astG3DAttr( int, double, double *, int ); int astG3DCap( int, int ); int astG3DFlush( void ); int astG3DLine( int, float *, float *, float * ); int astG3DMark( int, float *, float *, float *, int, float[3] ); int astG3DQch( float * ); int astG3DText( const char *, float[3], const char *, float[3], float[3] ); int astG3DTxExt( const char *, float[3], const char *, float[3], float[3], float *, float *, float *, float[3] ); #endif ./ast-7.3.3/plot.c0000644000175000017500000431071212262533650012274 0ustar olesoles/* *class++ * Name: * Plot * Purpose: * Provide facilities for 2D graphical output. * Constructor Function: c astPlot f AST_PLOT * Description: * This class provides facilities for producing 2D graphical output. * A Plot is a specialised form of FrameSet, in which the base * Frame describes a "graphical" coordinate system and is * associated with a rectangular plotting area in the underlying * graphics system. This plotting area is where graphical output * appears. It is defined when the Plot is created. * * The current Frame of a Plot describes a "physical" coordinate * system, which is the coordinate system in which plotting * operations are specified. The results of each plotting operation * are automatically transformed into graphical coordinates so as * to appear in the plotting area (subject to any clipping which * may be in effect). * * Because the Mapping between physical and graphical coordinates * may often be non-linear, or even discontinuous, most plotting * does not result in simple straight lines. The basic plotting * element is therefore not a straight line, but a geodesic curve c (see astCurve, astGenCurve and astPolyCurve). A Plot also provides facilities for c drawing markers or symbols (astMark), text (astText) and grid lines c (astGridLine). It is also possible to draw curvilinear axes with c optional coordinate grids (astGrid). f (see AST_CURVE, AST_GENCURVE and AST_POLYCURVE). A Plot also provides facilities f for drawing markers or symbols (AST_MARK), text (AST_TEXT) and grid f lines (AST_GRIDLINE). It is also possible to draw curvilinear axes f with optional coordinate grids (AST_GRID). * A range of Plot attributes is available to allow precise control * over the appearance of graphical output produced by these c functions. f routines. * * You may select different physical coordinate systems in which to * plot (including the native graphical coordinate system itself) * by selecting different Frames as the current Frame of a Plot, * using its Current attribute. You may also set up clipping (see c astClip) to limit the extent of any plotting you perform, and f AST_CLIP) to limit the extent of any plotting you perform, and * this may be done in any of the coordinate systems associated * with the Plot, not necessarily the one you are plotting in. * * Like any FrameSet, a Plot may also be used as a Frame. In this * case, it behaves like its current Frame, which describes the * physical coordinate system. * * When used as a Mapping, a Plot describes the inter-relation * between graphical coordinates (its base Frame) and physical * coordinates (its current Frame). It differs from a normal * FrameSet, however, in that an attempt to transform points which * lie in clipped areas of the Plot will result in bad coordinate * values (AST__BAD). * Inheritance: * The Plot class inherits from the FrameSet class. * Attributes: * In addition to those attributes common to all FrameSets, every * Plot also has the following attributes: * * - Abbrev: Abbreviate leading fields? * - Border: Draw a border around valid regions of a Plot? * - Clip: Clip lines and/or markers at the Plot boundary? * - ClipOp: Combine Plot clipping limits using a boolean OR? * - Colour(element): Colour index for a Plot element * - DrawAxes(axis): Draw axes for a Plot? * - DrawTitle: Draw a title for a Plot? * - Escape: Allow changes of character attributes within strings? * - Edge(axis): Which edges to label in a Plot * - Font(element): Character font for a Plot element * - Gap(axis): Interval between linearly spaced major axis values * - Grf: Select the graphics interface to use. * - Grid: Draw grid lines for a Plot? * - Invisible: Draw graphics in invisible ink? * - LabelAt(axis): Where to place numerical labels for a Plot * - LabelUnits(axis): Use axis unit descriptions in a Plot? * - LabelUp(axis): Draw numerical Plot labels upright? * - Labelling: Label and tick placement option for a Plot * - LogGap(axis): Interval between logarithmically spaced major axis values * - LogPlot(axis): Map the plot onto the screen logarithmically? * - LogTicks(axis): Space the major tick marks logarithmically? * - MajTickLen(axis): Length of major tick marks for a Plot * - MinTickLen(axis): Length of minor tick marks for a Plot * - MinTick(axis): Density of minor tick marks for a Plot * - NumLab(axis): Draw numerical axis labels for a Plot? * - NumLabGap(axis): Spacing of numerical axis labels for a Plot * - Size(element): Character size for a Plot element * - Style(element): Line style for a Plot element * - TextLab(axis): Draw descriptive axis labels for a Plot? * - TextLabGap(axis): Spacing of descriptive axis labels for a Plot * - TickAll: Draw tick marks on all edges of a Plot? * - TitleGap: Vertical spacing for a Plot title * - Tol: Plotting tolerance * - Width(element): Line width for a Plot element * Functions: c In addition to those functions applicable to all FrameSets, the c following functions may also be applied to all Plots: f In addition to those routines applicable to all FrameSets, the f following routines may also be applied to all Plots: * c - astBBuf: Begin a new graphical buffering context c - astBorder: Draw a border around valid regions of a Plot c - astBoundingBox: Returns a bounding box for previously drawn graphics c - astClip: Set up or remove clipping for a Plot c - astCurve: Draw a geodesic curve c - astEBuf: End the current graphical buffering context c - astGenCurve: Draw a generalized curve c - astGetGrfContext: Get the graphics context for a Plot c - astGrfPop: Retrieve previously saved graphics functions c - astGrfPush: Save the current graphics functions c - astGrfSet: Register a graphics routine for use by a Plot c - astGrid: Draw a set of labelled coordinate axes c - astGridLine: Draw a grid line (or axis) for a Plot c - astMark: Draw a set of markers for a Plot c - astPolyCurve: Draw a series of connected geodesic curves c - astText: Draw a text string for a Plot f - AST_BBUF: Begin a new graphical buffering context f - AST_BORDER: Draw a border around valid regions of a Plot f - AST_BOUNDINGBOX: Returns a bounding box for previously drawn graphics f - AST_CLIP: Set up or remove clipping for a Plot f - AST_CURVE: Draw a geodesic curve f - AST_EBUF: End the current graphical buffering context f - AST_GENCURVE: Draw a generalized curve f - AST_GETGRFCONTEXT: Get the graphics context for a Plot f - AST_GRFPOP: Retrieve previously saved graphics functions f - AST_GRFPUSH: Save the current graphics functions f - AST_GRFSET: Register a graphics routine for use by the Plot class f - AST_GRID: Draw a set of labelled coordinate axes f - AST_GRIDLINE: Draw a grid line (or axis) for a Plot f - AST_MARK: Draw a set of markers for a Plot f - AST_POLYCURVE: Draw a series of connected geodesic curves f - AST_TEXT: Draw a text string for a Plot * Graphical Elements: * The colour index, character font, character size, line style and * line width used for plotting can be set independently for * various elements of the graphical output produced by a Plot. * The different graphical elements are identified by appending the * strings listed below as subscripts to the Plot attributes * Colour(element), Font(element), Size(element), Style(element) * and Width(element). These strings are case-insensitive and * unambiguous abbreviations may be used. Elements of the graphical * output which relate to individual axes can be referred to either * independently (e.g. "(Grid1)" and "(Grid2)" ) or together (e.g. * "(Grid)"): * c - Axes: Axis lines drawn through tick marks using astGrid f - Axes: Axis lines drawn through tick marks using AST_GRID c - Axis1: Axis line drawn through tick marks on axis 1 using astGrid f - Axis1: Axis line drawn through tick marks on axis 1 using AST_GRID c - Axis2: Axis line drawn through tick marks on axis 2 using astGrid f - Axis2: Axis line drawn through tick marks on axis 2 using AST_GRID c - Border: The Plot border drawn using astBorder or astGrid f - Border: The Plot border drawn using AST_BORDER or AST_GRID c - Curves: Geodesic curves drawn using astCurve, astGenCurve or astPolyCurve f - Curves: Geodesic curves drawn using AST_CURVE, AST_GENCURVE or AST_POLYCURVE c - Grid: Grid lines drawn using astGridLine or astGrid f - Grid: Grid lines drawn using AST_GRIDLINE or AST_GRID c - Grid1: Grid lines which cross axis 1, drawn using astGridLine or astGrid f - Grid1: Grid lines which cross axis 1, drawn using AST_GRIDLINE or AST_GRID c - Grid2: Grid lines which cross axis 2, drawn using astGridLine or astGrid f - Grid2: Grid lines which cross axis 2, drawn using AST_GRIDLINE or AST_GRID c - Markers: Graphical markers (symbols) drawn using astMark f - Markers: Graphical markers (symbols) drawn using AST_MARK c - NumLab: Numerical axis labels drawn using astGrid f - NumLab: Numerical axis labels drawn using AST_GRID c - NumLab1: Numerical labels for axis 1 drawn using astGrid f - NumLab1: Numerical labels for axis 1 drawn using AST_GRID c - NumLab2: Numerical labels for axis 2 drawn using astGrid f - NumLab2: Numerical labels for axis 2 drawn using AST_GRID c - Strings: Text strings drawn using astText f - Strings: Text strings drawn using AST_TEXT c - TextLab: Descriptive axis labels drawn using astGrid f - TextLab: Descriptive axis labels drawn using AST_GRID c - TextLab1: Descriptive label for axis 1 drawn using astGrid f - TextLab1: Descriptive label for axis 1 drawn using AST_GRID c - TextLab2: Descriptive label for axis 2 drawn using astGrid f - TextLab2: Descriptive label for axis 2 drawn using AST_GRID c - Ticks: Tick marks (both major and minor) drawn using astGrid f - Ticks: Tick marks (both major and minor) drawn using AST_GRID c - Ticks1: Tick marks (both major and minor) for axis 1 drawn using astGrid f - Ticks1: Tick marks (both major and minor) for axis 1 drawn using AST_GRID c - Ticks2: Tick marks (both major and minor) for axis 2 drawn using astGrid f - Ticks2: Tick marks (both major and minor) for axis 2 drawn using AST_GRID c - Title: The Plot title drawn using astGrid f - Title: The Plot title drawn using AST_GRID * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * RFWS: R.F. Warren-Smith (Starlink) * History: * 18-SEP-1996 (DSB): * Original version. * 25-FEB-1997 (RFWS): * Tidied all public prologues. * 18-AUG-1997 (DSB): * Changes made to ensure that the first label on each axis is * never abbreviated, and to avoid segmentation violation when NumLab * is set to zero. * 1-SEP-1997 (DSB): * astGetGap changed so that it returns the default value which will * be used (instead of AST__BAD) if no value has been set for Gap. * The Border attribute modified so that it is off (zero) by default. * 19-SEP-1997 (DSB): * o Check that something has been plotted before using the bounding * box to determine title and label positions. * o Fixed bug which caused a tick mark at the pole to be draw at * a random angle. * o The size of the increment used to determine the tangent to a grid * line at the position to a label has been reduced to make sure the * labls are drawn parallel to grid line. * o Correct the logic for catering with reversed axes when determining * the displacement of a label's reference point from the associated * axis. * o Corrected logic which determined if two numerical labels overlap. * o Corrected logic for determining when to abbreviate numerical * labels. * o Use of strtok replaced by local function FindWord. * o Correct logic which determines which side of the axis to draw * tick marks when using interior labelling. * o If the base Frame of the FrameSet supplied to astPlot has more * than 2 axes, then use a sub-frame formed from the first two axes, * instead of simply reporting an error. * o If the current Frame of the Plot supplied to astGrid or * astBorder has more than 2 axes, then use a sub-frame formed from * the first two axes, instead of simply reporting an error. * o Default for Border is now to draw the border if exterior * Labelling is used, but not to draw it if interior labelling is * used. * o Public astGet function now returns actual used values for all * attributes. Protected astGetXyz functions still return the requested * value (which may differ from the used value), or the "unset" value * if no value has been set for the attribute. * o The defaults for Edge now depend on Labelling. If exterior * labelling was requested but cannot be produced using defaults of * Edge(1)=Bottom and Edge(2)=Left, then these default Edge values * are swapped. If exterior labelling is still not possible, the * original default Edge values are re-instated. * o Unset attributes which use dynamic defaults are now flagged as * "unhelpful" in the dump function. * o Added attribute Escape which allows text strings to include * escape sequences (see function GrText). This attribute and * associated functionality is currently not available for use, search * for all occurences of ENABLE-ESCAPE for instructions on how to * enable the facilities. * o Strings now used instead of integers to represent "choice" * attributes externally (eg Edge and Labelling). * 24-NOV-1997 (DSB): * o Fixed bug in function Grid which caused units to be included in * SkyFrame axis labels by default. * o Replaced calls to DrawText by calls to astGText, and replaced * references to "U" and "D" justifications by "T" and "B". This * stops labels drifting to the bottom left when GAIA zooms. * 23-MAR-1998 (DSB): * Added extra checks on global status into routine Grid to avoid * segmentation violations occuring due to null pointers being used. * 10-JUN-1998 (DSB): * Modify DrawTicks so that ticks are drawn closer to singularities * than previously. Also normalise this constraint to the screen size * rather than the length of a major tick mark. * 28-OCT-1998 (DSB): * o Added method astPolyCurve. * o Extract the Current Frame from the Plot prior to using Frame * methods such as astOffset, astNorm, etc. * o PlotLabel modified to ensure labels are abbreviated even if * they are next to the "root" label (i.e. the label with most * trailing zeros). * o Modified description of Width attribute. Width no longer gives * the absolute line width in inches. Instead it is a scale factor, * where 1.0 corresponds to a "typical thin line" on the device. * o Modified LabelUnits attribute so that the default value is zero * for SkyAxes and non-zero for other Axes. * 10-DEC-1998 (DSB): * Modified all calls to the "pow" maths function to avoid using * literal constants as arguments. This seems to cause segmentation * violations on some systems. * 16-JUL-1999 (DSB): * Fixed memory leaks in EdgeCrossings and EdgeLabels. * 16-SEP-1999 (DSB): * Avoid writing out clipping limits if they are undefined. * 12-OCT-1999 (DSB): * o Modified use of the NumLab attribute so that setting it to zero * does not prevent exterior labels from being produced. * o Allow length of tick marks to be specified separately for * both axes. * 13-OCT-2000 (DSB): * o Purge zero length sections from CurveData structures. * o Increase tolerance for edge labels from 0.0005 to 0.005. * 9-JAN-2001 (DSB): * o Change argument "in" for astMark and astPolyCurve from type * "const double (*)[]" to "const double *". * o Check success of astReadString before using the returned * pointer. * o Change method for choosing default LabelAt values to ignore * values which produce no visible labels. * 10-JAN-2001 (DSB): * o Modified FindMajTick to choose the size of fillable holes in * the axis range on the basis of the number of ticks on the axis. * This avoids holes being visible in the displayed tick marks when * using very small gaps. * 22-MAY-2001 (DSB): * Added a check when using interior labelling, to ensure that the * most appropriate edges are used for text labels. * 13-JUN-2001 (DSB): * Added public method astGenCurve, astGrfSet, astGrfPop, astGrfPush. * Made DrawAxes attribute axis specific. * 4-JUL-2001 (DSB): * The Crv function used to have a restriction that if *any* * subsection was very short, then *none* of the subsections were * subdivided. This meant that long subsections which needed * subdividing were not subdivided if there was also a very short * subsection. To get round this problem the restriction was changed * to "if *all* subsections are very short then none are divided. * This was implemented by changing dl2_min to dl2_max, and adding * a check for very short segments (which are then not sub-divided). * 16-AUG-2001 (DSB): * Remove the check for very short segments introduced above, as it * caused south pole tan projection to include some spurious lines. * 20-SEP-2001 (DSB): * - Initialize baseframe to NULL in astInitPlot (prevents segvios). * - Modified astInitPlot to allow the "frame" argument to the astPlot * constructor to be a Plot. * 10-JAN-2002 (DSB): * - Added axis-specific graphical elements "axis1", "axis2", etc. * - FullForm returns a match without ambiguity if the test string * matches an option exactly, including length. * 31-JAN-2002 (DSB): * - Added RejectOOB to reject tick marks which are not in their primary * domain. * 14-FEB-2002 (DSB): * - Relaxed the conditions for equality within the EQUALS macro. * Guard aginst no ticks being found. * 18-FEB-2002 (DSB): * - Make a permanent copy of any old axis format string in TickMarks. * Previously a mere pointer into the astGet string buffer was stored, * which could be over-written after many calls to astGet. * - If a user specifies an axis format, use it whether or not it * results in any identical adjacent labels. * 4-MAR-2002 (DSB): * - Made fairly extesive changes to the creation and use of tick * mark values in order to circumvent problems with CAR projections, * and "1 to many" mappings (such as 2D cartesian->polar). The * policy now is that axis normalization is only performed when * necessary (i.e. to create labels for display, etc). Tick mark * values are stored and handled as non-normalized values as much as * possible. * 13-JUN-2002 (DSB): * Modified Norm1 to prevent major tick value from being removed if * the supplied reference value is out of bounds, resulting in the * Mapping producing bad values * 14-JUN-2002 (DSB): * Re-wrote PlotLabels to improve abbreviation of labels and the * choice of which labels not to print. * 14-AUG-2002 (DSB): * - Added method astBoundingBox. * - Added attribute Invisible. * - Correct handling of "axis specific" plot elements cuch as * (Axis1), (Axis2), etc. * 12-SEP-2002 (DSB): * - Modified Map1 to remove slow normalization method (it is now * faster but the changes result in some longer-than-needed grids * lines when (e.g.) plotting pixel coordins in Polar coords). * - Modified Axlot so that SkyFrames positions which are out of * their normal ranges are not rejected by Map1. * 10-OCT-2002 (DSB): * grfAttrs:Modified to test element attributes explicitly using the * relevant TestUse functions, instead of relying on the * "GetUse" function returning the NO constant if not set. * - Modified Axplot so that SkyFrames positions which are out of * their normal ranges are not rejected by Map1. * - Only use tick marks which are within the axis range given by the * Bottom and Top Axis attributes. * - Norm1: If the normalized current frame coords are bad, do not * reinstate the original unnormalized values. For instance, current * Frame values which are outside the valid domain of the projection * should result in bad values when normalized, not the original * good values. The original comment stated "If the normalization * produced bad coords (e.g. as may happen if the supplied refernce * value corresponds to a point on the line through the tick mark * which is outside the valid region of the mapping) leave the original * tick mark values unchanged". * - GetTicks: Limit maxticks to be no less than 8. * 8-JAN-2003 (DSB): * - Changed private InitVtab method to protected astInitPlotVtab * method. * - Use private IsASkyFrame method in place of astIsASkyFrame. * - Modify PlotLabels to excluding exponents when counting trailing * zeros, and also to pad trailing fields with trailing zeros up to * the max number of decimal places when estimating label priorities. * - Modified Overlap to ensure that axis labels are speced by at * least two spaces. * 22-JAN-2003 (DSB): * - Modified PlotLabels so that labels are rejected in a regular * pattern rather than semi-random. * - Modified the way PlotLabels abbreviates leading fields. * - Introdued the skipbad parameter for the Crv function, in order * to provide some degree of protection against the Crv algorithm * skipping over small sections of valid coordinates (such as when * a curve crosses the plot very close to a corner of the plot). * 25-MAR-2003 (DSB): * - Modified FindMajTicks to avoid losing tick marks when dealing * with high precision data. * 8-AUG-2003 (DSB): * - Modified PlotLabels to ensure that the root label for the * second axis is not omitted due to it overlapping a label from * the first axis (a different root label is now chosen if this would * be the case). * - Modify FindMajTicks to avoid tick marks which should be at * exactly zero being placed at some very small non-zero axis value. * 22-OCT-2003 (DSB): * - DrawTicks modified to correctly reset graphical attributes and * pass on to the next axis if an axis has zero length major and minor * tick marks. * 9-JAN-2004 (DSB): * DrawGrid: Report error if no grid curves can be drawn. * AxPlot: Initialise returned CDATA structure before checking argument * validity. * GetTicks: Calculate the reference value on the other axis using * function "Typical" rather than simply using the man of the supplied * values (the supplied values may be clustered around 0 and 2*PI if the * field is centred on the origin, resulting in the mean being at about * 1.PI and therefore inappropriate). * 13-JAN-2004 (DSB): * - Added LogPlot attribute, and the facility for mapping the base * coordinate system logarithmically onto the plotting area instead of * linearly. * - Added LogTicks attribute, and the facility for spacing the * major tick marks logarithmically instead of linearly. * - Added LogGap attribute, and the facility for storing separate * gap sizes for linear and log tick spacing. * 15-JAN-2004 (DSB): * - Added LogLabel attribute. * - Re-instated the inclusion of escape sequences in strings (see * function GrText). * 12-FEB-2004 (DSB): * - RightVector: Corrected usage of chh and chv. * - GQch and GScales: Check that values returned by grf module are * usable. * - DrawAxis: Extend axis section by one section (if possible) at * each end (overcomes problems where the axis does not reach a pole). * - DrawAxis: Check axis does not extend beyond a pole. * - Labels: Correct logic of loop which plots interior labels * (previously it missed out labels if there were only 3) * - Allow for some rounding error in FindMajTicks when comparing an * axis value with a loweror upper axis limit. * 19-FEB-2004 (DSB): * - Reduced the dynamic range restriction for log ticks from 2 decades * to 1. * - Temporarily clear any error status before re-instating the * original Format in TickMarks. * - Add LogTicks to the GetAttrib function so that the value of the * LogTicks attribute can be got by the public. * - Modify Crv to include a check that he vector scale has not * changed much between adjacent segments. * - Modify Crv so that a segment is only subdivided if at least * half of the subsegments are longer than the shortest significant * length. Also put a restriction on subdivision so that * subdivision only occurs if the bounding box of the segment being * sub-divided is smaller than the bounding box of its parent * segment. * 27-FEB-2004 (DSB): * - Reduce the default Tol value from 0.001 to 0.01 in order to * speed up curve drawing.. * - Use 0.1*Tol in Boundary because the boundary tracing algorithm * seems to produce much worse visible errors than it should do for a * given Tol. * 2-MAR-2004 (DSB): * - Corrected handling of bounding boxes in Crv so that * subdivision is allowed if the bounding box shrinks on only 1 axis * (previously required shrinkage on both axes but this fails if * all the points are on a horizontal or vertical line). * - Modified FindMajTicks to use a better algorithm for finding an * appropriate nfill value (previously logplot=1 axes could have * unfilled holes at the high end). * - Modified GetTicks so that FindMajTicks is not called * repeatedly with the same gap size. * - Modify AxPlot/Map1 so that the axis curve is sampled logarithmically * if the corresponding axis is mapped logarithmically. * 10-MAR-2004 (DSB): * - Modified Typical to give less weight to vaalues close to the * edges of the range covered by the plotting area. * - Increased minimum angle between curve and edge required to * create an edge label from 3 degs to 5 degs. * - Modified PlotLabels to ignore duplicate adjacent labels which * determining overlap of labels. * 17-MAR-2004 (DSB): * - Modified Typical to give normal weight to edge bins in * histogram if these bins contain all the counts. * - Modified DrawTicks to add extra minor ticks below first major * tick value and above last major tick value. * - Norm1 can reject usable tick mark values because of an * inappropriate value being used on the other axis (i.e. one for * which the position is undefined in grapics coords). Therfoer * Norm1 has been modified to use 3 different reference values * in an attempt to find one which gives good axis values. * 25-AUG-2004 (DSB): * - Correct handling of "fmt" pointer in TickMarks function (identified * and reported by Bill Joye). * 14-SEP-2004 (DSB): * - In EdgeLabels change definition of "distinct labels". Used to * be that labels were distinct if they had different formatted * labels. Now they are distinct if they have different floating * point numerical values. Fixes a bug reported by Micah Johnson. * - TickMarks re-structured to optimise the precision (no. of digits) * even if a value has been assigned for the Format attribute, but only * if the format specifier includes a wildcard precision specifier. For * instance, to get graphical separators a format must be specified * which included the "g" flag. As things were, this would prevent * the optimisation of the digits value. Can now use "dms.*g" to * allow the number of digits to be optimised. * 29-SEP-2004 (DSB): * - In FindMajTicks, begin the process of increasing "nfill" from * a value of zero rather than one (in many cases no filling is * needed). * - In GetTicks (linear tick marks section) ensure that 10 * *different* gap sizes are used before giving up. Previously, the * 10 tests could include duplicated gap values. * 8-NOV-2004 (DSB): * - In Norm1, try more alternative "other axis" values before * accepting that a tick mark value cannot be normalised. * 2-FEB-2005 (DSB): * - Avoid using astStore to allocate more storage than is supplied * in the "data" pointer. This can cause access violations since * astStore will then read beyond the end of the "data" area. * 15-MAR-2005 (DSB): * - Modified GridLines to use appropriate algorithm for choosing * start of grid lines in cases where one axis has logarithmic tick * spacing and the other has linear tick spacing. * 21-MAR-2005 (DSB): * - Added the Clip attribute. * 12-JUL-2005 (DSB): * - Modified AxPlot so that Map1 only normalises if neither axis * is a SkyAxis. Previously it normalised if either axis was not a * SkyAxis. * 7-DEC-2005 (DSB): * Free memory allocated by calls to astReadString. * 18-JAN-2006 (DSB) * Add Abbrev attribute. * 14-FEB-2006 (DSB) * Correct EdgeLabels to use gap size rather than EQUAL macro when * comparing label values. * 17-FEB-2006 (DSB) * Added escape sequences "%h+" and "%g+". * 21-MAR-2006 (DSB) * Added extra status checks in TickMarks. * 18-MAY-2006 (DSB) * Trans: use correct PointSet when tranforming to arbitrary * clipping frame. * 26-MAY-2006 (DSB) * Added LabelAt to TestAttrib. * 2-JUN-2006 (DSB) * - In MAKE_GET2, return the set value if a value has been set * without recalculating the defaults. * - Fix bug that could cause segvio in Grid if clipping is used. * 5-JUN-2006 (DSB) * Do not change the box returned by astBoundBox as a consequence * of calling astGetAttrib. * 19-JUN-2006 (DSB) * Changed the default line 0.0 from zero to 1.0. * 22-JUN-2006 (DSB) * Include axis textual labels and title in the bounding box * created by AST_GRID and returned by AST_BOUNDINGBOX. * 26-JUN-2006 (DSB) * Set the Direction attribute in the base Frame of a Plot if an * axis is reversed. * 29-JUN-2006 (DSB) * - Guard against astGap calls that reach a minimum gap size. * - Sort out splitting of long axis labels (such as date/time * strings produced by TimeFrames). * 30-JUN-2006 (DSB) * If abbreviating labels, display the last field for identical * neighbours rather than the whole value. * 10-JUL-2006 (DSB) * Make astStripEscapes public so it can be used by the NDF library. * 7-AUG-2006 (DSB) * Increase the number of attempts to find a new gap size from 5 to * 25 in GetTicks. * 24-OCT-2006 (DSB) * Add the ForceExterior attribute so that SPLAT can have external * axes even if there are no usable horizontal axis ticks (as requested * by PWD). Currently this attribute is not included in the public * documentation, as it may cause problems. If it seems to work OK * then it can be made public. * 25-JAN-2006 (DSB) * Do not draw ticks marks that start outside the bounds of the * axis they are labelling. * 27-FEB-2007 (DSB) * - Change nominal Crv_scerr value from 5.0 to 1.5 (this avoids gaps * in HPX grid plots being bridged by grid lines). * - Double the dimension of the grid used by GoodGrid to avoid * missing the pointy bits in a HPX projection. * 17-MAY-2007 (DSB) * Exclude corner positions when determining the range of axis * values covered by the plot. This gives better default gap sizes. * 11-JUN-2007 (DSB) * Plug memory leaks. * 20-JUN-2007 (DSB) * - Add attribute GrfContext. * - Pass the GrfContext attribute value to each external grf function. * External code that uses the astGrfSet function must be changed * so that the external grf functions registered using astGrfSet * accept this new parameter. * 21-JUN-2007 (DSB) * - Change GrfContext to be an Object rather than an integer. * 22-JUN-2007 (DSB) * - Do not dump the GrfContext Object since it may cause an * infinite dumping loop. * - Allow a NULL vtab to be supplied when initialising a Plot * structure. This causes the vtab defined locally within this * class to be used so that the new object behaves as a simple Plot. * 25-JUN-2007 (DSB) * - Free the graphics context object when then the Plot is deleted. * - Fix memory leak in FullForm. * - Since the grfcontext object is only used by external code, store * a public object identifier for it in the Plot structure rather * than a true C pointer. * 26-JUN-2007 (DSB) * Honour the LabelUp attribute value even if labels are drawn * around the edges of the plot. * 28-JUN-2007 (DSB) * - Make all axis attribute arrays 3 elements long rather than 2. * - Add the protected methods astCopyPlotDefaults and astMirror. * - Add public method astGetGrfContext, remove astSetGrfContext. * - Fix memory leak. * 6-SEP-2007 (DSB): * Dump and load any user-specified tick mark values. * 20-OCT-2009 (DSB): * - Modify SplitValue so that it only splits long values if * previous long values were split, or if the value contains a * space. * - Take account of zero height bounding boxes in UpdateConcat. * - Correct Dump so that it dumps attributes for all available * axes (2 for a Plot, 3 for a Plot3D). * 12-JAN-2010 (DSB): * Fix various memory leaks. * 4-MAR-2011 (DSB): * - Added grf functions BBuf and EBuf. * - Added public method astBBuf and astEBuf. * 23-AUG-2011 (DSB): * - If exterior labelling was requested but would produced too * few labels, only swap to interior labelling if doing so would * allow more labels to be drawn (i.e. do not swap to interior if * it does not gain us anything). * - Slightly decrease the dynamic range of an axis needed to produce * logarithmic ticks (this is to avoid problems with round errors). * 6-OCT-2011 (DSB): * - Prevent grf qch and scales functions being called lots of times * during each drawing operation (since the information returned by * these functions will not change during the course of a single drawing * operation). * 11-OCT-2011 (DSB): * - Combine multiple continuous polylines into a single polyline * before calling the grf polyline function. Reducing the number of * calls to the underlying graphics system can make a big difference * if the graphics system is written in an interpreted language * such as python. * - Take account of differing axis scales when rotating vectors by * 90 degrees. * 12-OCT-2011 (DSB): * - Fix the change made yesterday to correct rotation of numerical axis * rotations. I forgot that the astGText function in the grf module * expects the up vector in equally scaled coords, not graphics coords. * - Take account of unequal axis scales when working out the * length of each grid curve. * 15-OCT-2011 (DSB): * Always check that the grf module implements the scales function * before trying to invoke the scales function. * 21-MAY-2012 (DSB): * Correct text strings used to represent the "Labelling" attribute * within dumps of a Plot. Previously they were reversed. * 7-JUN-2012 (DSB): * Speed up plotting of CmpRegion boundaries by splitting the * CmpRegion up into a set of disjoint Regions, and plotting each * one separately. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Plot /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macros to check for equality of floating point values. */ #define EQUAL(aa,bb) (fabs((aa)-(bb))<=1.0E8*DBL_EPSILON*MAX(fabs(aa)+fabs(bb),DBL_EPSILON*1.0E-7)) /* Values for constants used in this class. */ #define CRV_NSEG 14 /* No. of curve segments drawn by function Crv */ #define CRV_NPNT 15 /* CRV_NSEG plus one */ #define CRV_MXENT 10 /* Max. no. of recursive entries into function Crv */ #define MAJTICKS_OPT 10 /* Optimum number of major axiss or grid lines */ #define MAJTICKS_MAX 14 /* Max. number of major ticks or grid lines */ #define MAJTICKS_MIN 6 /* Min. number of major ticks or grid lines */ #define EDGETICKS_DIM 100 /* No. of edge samples used to find tick marks */ #define LEFT 0 /* Id for the left edge of the plotting area */ #define TOP 1 /* Id for the top edge of the plotting area */ #define RIGHT 2 /* Id for the right edge of the plotting area */ #define BOTTOM 3 /* Id for the bottom edge of the plotting area */ #define NOSTYLE -999 /* A value which represents a null Style value */ #define NOWIDTH -99.9 /* A value which represents a null Style value */ #define NOFONT -999 /* A value which represents a null Style value */ #define NOCOLOUR -999 /* A value which represents a null Style value */ #define NOSIZE -99.9 /* A value which represents a null Style value */ #if defined(THREAD_SAFE) #define GLOBALS_PROTO , AstGlobals * #define GLOBALS_ARG , AstGlobals *AST__GLOBALS #define GLOBALS_NAME , AST__GLOBALS #else #define GLOBALS_PROTO #define GLOBALS_ARG #define GLOBALS_NAME #endif /* * * Name: * MAKE_CLEAR * Purpose: * Implement a method to clear a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "plot.h" * MAKE_CLEAR(attr,component,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Clear( AstPlot *this, int axis ) * * and an external interface function of the form: * * void astClear_( AstPlot *this, int axis ) * * which implement a method for clearing a single value in a specified * multi-valued attribute for an axis of a Plot. * Parameters: * attr * The name of the attribute to be cleared, as it appears in the function * name (e.g. LabelAt in "astClearLabelAt"). * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to assign to the component * to clear its value. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_CLEAR(attr,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Clear##attr( AstPlot *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astClear" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* Assign the "clear" value. */ \ } else { \ this->component[ axis ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astClear##attr##_( AstPlot *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,Plot,Clear##attr))( this, axis, status ); \ } /* * * Name: * MAKE_GET * Purpose: * Implement a method to get a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "plot.h" * MAKE_GET(attr,type,bad_value,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( AstPlot *this, int axis ) * * and an external interface function of the form: * * astGet_( AstPlot *this, int axis ) * * which implement a method for getting a single value from a specified * multi-valued attribute for an axis of a Plot. * Parameters: * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astGetLabel"). * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. This can * use the string "axis" to represent the zero-based value index. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_GET(attr,type,bad_value,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type Get##attr( AstPlot *this, int axis, int *status ) { \ type result; /* Result to be returned */ \ \ /* Initialise */ \ result = (bad_value); \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astGet" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* Assign the result value. */ \ } else { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ type astGet##attr##_( AstPlot *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,Plot,Get##attr))( this, axis, status ); \ } /* * * Name: * MAKE_SET * Purpose: * Implement a method to set a single value in a multi-valued attribute * for a Plot. * Type: * Private macro. * Synopsis: * #include "plot.h" * MAKE_SET(attr,type,component,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( AstPlot *this, int axis, value ) * * and an external interface function of the form: * * void astSet_( AstPlot *this, int axis, value ) * * which implement a method for setting a single value in a specified * multi-valued attribute for a Plot. * Parameters: * attr * The name of the attribute to be set, as it appears in the function * name (e.g. LabelAt in "astSetLabelAt"). * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_SET(attr,type,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Set##attr( AstPlot *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astSet" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* Store the new value in the structure component. */ \ } else { \ this->component[ axis ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astSet##attr##_( AstPlot *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,Plot,Set##attr))( this, axis, value, status ); \ } /* * * Name: * MAKE_TEST * Purpose: * Implement a method to test if a single value has been set in a * multi-valued attribute for a class. * Type: * Private macro. * Synopsis: * #include "plot.h" * MAKE_TEST(attr,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static int Test( AstPlot *this, int axis ) * * and an external interface function of the form: * * int astTest_( AstPlot *this, int axis ) * * which implement a method for testing if a single value in a specified * multi-valued attribute has been set for a class. * Parameters: * attr * The name of the attribute to be tested, as it appears in the function * name (e.g. LabelAt in "astTestLabelAt"). * assign * An expression that evaluates to 0 or 1, to be used as the returned * value. This can use the string "axis" to represent the zero-based * index of the value within the attribute. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_TEST(attr,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static int Test##attr( AstPlot *this, int axis, int *status ) { \ int result; /* Value to return */ \ \ /* Initialise */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astTest" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* Assign the result value. */ \ } else { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ int astTest##attr##_( AstPlot *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,Plot,Test##attr))( this, axis, status ); \ } /* * * Name: * MAKE_GET3 * Purpose: * Implement a method to get a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * MAKE_GET3(attr,attr,type,bad_value,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( AstPlot *this, int axis ) * * which implements a method for getting a single value from a specified * multi-valued attribute for an axis of a Plot. Note, no public * interface function is created. * * The value returned is the value which would actually be used if * astGrid was called with the current set of Plot attributes. This * includes calculating any dynamic defaults which would be used, and is * consequently rather slow. * Parameters: * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astGetLabel"). The * string "Used" is added on to the front of the supplied value. * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. This can * use the string "axis" to represent the zero-based value index. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_GET3(attr,type,bad_value,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type GetUsed##attr( AstPlot *, int, int *status ); \ static type GetUsed##attr( AstPlot *this, int axis, int *status ) { \ type result; /* Result to be returned */ \ \ /* Initialise */ \ result = (bad_value); \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astGetUsed" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* If the attribute is set, use its normal accessor. */\ } else if( astTest##attr( this, axis ) ) {\ result = astGet##attr( this, axis );\ \ /* Otherwise, re-calculate dynamic defaults by going through the motions of \ drawing the grid. Nothing is actually drawn because we set the protected \ attribute Ink to zero first. The calculated values are stored in the \ Plot structure. */ \ } else { \ astSetInk( this, 0 ); \ astGrid( this ); \ astClearInk( this ); \ \ /* Assign the result value. */ \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } /* * * Name: * MAKE_SET3 * Purpose: * Implement a method to set a single value in a multi-valued attribute * for a Plot. This is identical to MAKE_SET except that no external * interface function is created. * Type: * Private macro. * Synopsis: * MAKE_SET3(attr,type,component,assign,nval) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( AstPlot *this, int axis, value ) * * which implements a method for setting a single value in a specified * multi-valued attribute for a Plot. * Parameters: * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astSetLabel"). The * string "Used" is added on to the front of the supplied value. * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). If a value of 0 is supplied, the * value of the Plot's Nin attribute is used instead. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_SET3(attr,type,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void SetUsed##attr( AstPlot *, int, type, int *status ); \ static void SetUsed##attr( AstPlot *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= ( nval ? nval : astGetNin( this ) ) ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astSetUsed" #attr, astGetClass( this ), \ axis + 1, ( nval ? nval : astGetNin( this ) ) ); \ \ /* Store the new value in the structure component. */ \ } else { \ this->component[ axis ] = (assign); \ } \ } /* *+ * Name: * MAKE_GET2 * Purpose: * Implement a method to get an attribute value for a class. * Type: * Protected macro. * Synopsis: * MAKE_GET2(class,attr,type,bad_value,assign) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static GetUsed( AstPlot *this ) * * which implement a method for getting a specified attribute value for a * class. Note, no public interface function is created. * * The value returned is the value which would actually be used if * astGrid was called with the current set of Plot attributes. This * includes calculating any dynamic defaults which would be used, and is * consequently rather slow. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astGetLabel"). The * string "Used" is added on to the front of the supplied value. * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_GET2(class,attr,type,bad_value,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type GetUsed##attr( Ast##class *, int *status ); \ static type GetUsed##attr( Ast##class *this, int *status ) { \ type result; /* Result to be returned */ \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad_value); \ \ /* If the attribute is set, use its normal accessor. */\ if( astTest##attr( this ) ) {\ result = astGet##attr( this );\ \ /* Otherwise, re-calculate dynamic defaults by going through the motions of \ drawing the grid. Nothing is actually drawn because we set the protected \ attribute Ink to zero first. The calculated values are stored in the \ Plot structure. */ \ } else { \ astSetInk( this, 0 ); \ astGrid( this ); \ astClearInk( this ); \ \ /* Assign the result value. */ \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } /* *+ * Name: * MAKE_SET2 * Purpose: * Implement a method to set an attribute value for a class. This * is identical to astMAKE_SET except that it does not create an * external interface function, and it does create a private function * prototype. * Type: * Protected macro. * Synopsis: * MAKE_SET2(class,attr,type,component,assign) * Class Membership: * Defined by the Plot class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void SetUsed( AstPlot *this, value ) * * which implements a method for setting a specified attribute value for a * class. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attr * The name of the attribute to be set, as it appears in the function * name (e.g. Label in "astSetLabel"). The string "Used" is added * to the front. * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_SET2(class,attr,type,component,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void SetUsed##attr( Ast##class *, type, int *status ); \ static void SetUsed##attr( Ast##class *this, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Store the new value in the structure component. */ \ this->component = (assign); \ } /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "channel.h" /* I/O channels */ #include "cmpmap.h" /* Compound mapping class */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "frame.h" /* Coordinate frame descriptions */ #include "frameset.h" /* Parent FrameSet class */ #include "grf.h" /* Low-level graphics interface */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "plot.h" /* Interface definition for this class */ #include "pointset.h" /* Class holding lists of positions */ #include "keymap.h" /* Hash maps */ #include "skyaxis.h" /* Sky coordinate axes */ #include "skyframe.h" /* Sky coordinate frames */ #include "winmap.h" /* Scale and shift mappings */ #include "mathmap.h" /* Algebraic mappings */ #include "wcsmap.h" /* FITS-WCS projectsions */ #include "unitmap.h" /* Unit mappings */ #include "permmap.h" /* Axis permutations */ #include "region.h" /* Frame regions */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Module Type Definitions */ /* ======================= */ typedef struct LabelList { double index; char *text; double x; double y; char *just; double upx; double upy; double val; int priority; const char *atext; int saved_prio; } LabelList; /* Structure to hold static data used internally within the Crv function. */ typedef struct CrvStatics { double *pdl2; /* Pointer to next squared segment length */ double *pdx; /* Pointer to next segment X increment */ double *pdy; /* Pointer to next segment Y increment */ double cosang; /* Cosine of angle between adjacent segments */ double d0; /* Distance to start of first sub-segment */ double delta; /* Distance between adjacent sub-segments */ double dl; /* Segment length in graphics coordinates */ double dll; /* Segment length for previous segment */ double last_x; /* Graphics X at the end of the previous segment */ double last_y; /* Graphics Y at the end of the previous segment */ double limit2; /* Shortest acceptable squared segment length */ double t1; /* Increment in X */ double t2; /* Increment in Y */ double t3; /* Squared segment length */ double vx; /* X component of unit vector for current segment */ double vxl; /* X component of unit vector for previous segment */ double vy; /* Y component of unit vector for current segment */ double vyl; /* Y component of unit vector for previous segment */ int *seg0; /* Pointer to current segment OK flag */ int *segm; /* Pointer to previous segment OK flag */ int *segp; /* Pointer to next segment OK flag */ int all_bad; /* Are all supplied positions bad or clipped? */ int el; /* Total sub-segment count */ int j; /* Sub-segment index */ int last_ok; /* Was the previous position defined? */ int nel; /* Total number of sub-segments */ int nlong; /* No.of segments longer than limit2 */ int nseg; /* Number of segments being sub-divided */ int nshort; /* No.of segments shorter than limit2 */ #ifdef CRV_TRACE int levels[100]; #endif } CrvStatics; /* Structure to hold static data used internally within the Crv function. */ typedef struct GetTicksStatics { AstFrame *frame; /* Pointer to the current Frame */ AstMapping *map; /* Pointer to Base->Current Mapping */ AstPointSet *pset; /* Pointer to a PointSet holding physical coords */ double **ptr; /* Pointer to physical coordinate values */ double defgaps[ 2 ]; /* Initial test gaps for each axis */ double typval[ 2 ]; /* Typical value on each axis */ double width[ 2 ]; /* Range of used axis values */ int maxticks; /* Max. number of ticks on each axis */ int mintick; /* Min. number of ticks on each axis */ int ngood[ 2 ]; /* No. of good physical values on each axis */ int bad; /* Were any bad pixels found? */ } GetTicksStatics; /* Structure to hold static data used internally within the EdgeCrossings function. */ typedef struct EdgeCrossingsStatics { AstFrame *frame; /* Pointer to current Frame in Plot */ AstPointSet *pset1; /* Graphics cooords at edge samples */ AstPointSet *pset2; /* Physical cooords at edge samples */ AstPointSet *pset4; /* Graphics cooords at offset edge samples */ double **ptr1; /* Pointer to graphics coord. data */ double **ptr2; /* Pointer to physical coord. data */ double **ptr4; /* Pointer to graphics coord. data */ double edgehi; /* High bound on varying graphics axis */ double edgelo; /* Low bound on varying graphics axis */ double edgeval; /* Constant graphics axis value along edge */ double limit; /* Three times the RMS step size */ int dim; /* Extended number of samples */ int edgeax; /* Graphics axis to which edgeval refers */ int paxis; /* Axis used in first invocation */ int pedge; /* Edge used in first invocation */ } EdgeCrossingsStatics; /* Structure to hold static data used internally within the Map1 function. */ typedef struct Map1Statics { AstPointSet *pset1; /* PointSet holding physical coords */ AstPointSet *pset2; /* PointSet holding graphics coords */ double **ptr1; /* Pointer to physical coord data */ double *pax; /* Pointer to start of axis data */ double *ptr2[ 2 ]; /* Pointers to graphics coord data */ double *work1; /* Pointer to work space */ double *work2; /* Pointer to work space */ double axorig; /* Distance offset */ double axscale; /* Distance scale */ int neg; /* Negate axis values? */ int nl; /* No. of points in pset1 and pset2 */ } Map1Statics; /* Structure to hold static data used internally within the Map2 function. */ typedef struct Map2Statics { AstPointSet *pset1; /* PointSet holding graphics coords */ AstPointSet *pset2; /* PointSet holding physical coords */ double **ptr2; /* Pointer to physical coord data */ double *ptr1[ 2 ]; /* Pointers to graphics coord data */ int nl; /* No. of points in pset1 and pset2 */ } Map2Statics; /* Structure to hold static data used internally within the Map3 function. */ typedef struct Map3Statics { AstPointSet *pset1; /* PointSet holding physical coords */ AstPointSet *pset2; /* PointSet holding graphics coords */ double **ptr1; /* Pointer to physical coord data */ double *ptr2[ 2 ]; /* Pointers to graphics coord data */ int nc; /* No. of physical axes */ int nl; /* No. of points in pset1 and pset2 */ double *pos; /* Pointer to memory for a single position */ } Map3Statics; /* Structure to hold static data used internally within the Map4 function. */ typedef struct Map4Statics { AstPointSet *pset1; /* PointSet holding distances */ AstPointSet *pset2; /* PointSet holding physical coords */ AstPointSet *pset3; /* PointSet holding graphics coords */ int nl; /* No. of points in pset1 and pset2 */ } Map4Statics; /* Structure to hold static data used internally within the Map5 function. */ typedef struct Map5Statics { AstPointSet *pset1; /* PointSet holding physical coords */ AstPointSet *pset2; /* PointSet holding graphics coords */ double **ptr1; /* Pointer to physical coord data */ double *ptr2[ 2 ]; /* Pointers to graphics coord data */ int nl; /* No. of points in pset1 and pset2 */ } Map5Statics; /* Structure to hold information about tick marks for a single axis. */ typedef struct TickInfo{ int nmajor; /* No. of major tick marks */ int nminor; /* No. of minor tick marks */ double *ticks; /* Pointer to array of major tick mark values */ double *minticks; /* Pointer to array of minor tick mark values */ char **labels; /* Pointer to array of major tick mark labels */ double *start; /* Start pos'n on other axis for each curve section */ double *length; /* Length on other axis of each curve section */ int nsect; /* No. of sections in curve */ char *fmt; /* Pointer to format string used to create labels */ double gap; /* The gap between major ticks */ } TickInfo; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static void (* parent_removeframe)( AstFrameSet *, int, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* Strings giving the label for the graphics items corresponding to AST__BORDER_ID, AST__GRIDLINE_ID, etc. */ static char *GrfLabels = "Border Curves Title Markers Strings Axis1 Axis2 Axis3 " "NumLab1 NumLab2 NumLab3 TextLab1 TextLab2 TextLab3 " "Ticks1 Ticks2 Ticks3 Grid1 Grid2 Grid3 Axes NumLab " "TextLab Grid Ticks"; /* Text values used to represent edges externally. */ static const char *xedge[4] = { "left", "top", "right", "bottom" }; /* Text values used to represent Labelling externally. */ static const char *xlbling[2] = { "exterior", "interior" }; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GrfAttrs_nesting_t = 0; \ globals->Crv_nent_t = 0; \ globals->Box_lbnd_t[ 0 ] = FLT_MAX; \ globals->Box_ubnd_t[ 0 ] = FLT_MIN; \ globals->Boxp_lbnd_t[ 0 ] = FLT_MAX; \ globals->Boxp_ubnd_t[ 0 ] = FLT_MIN; \ globals->Box_lbnd_t[ 1 ] = FLT_MAX; \ globals->Box_ubnd_t[ 1 ] = FLT_MIN; \ globals->Boxp_lbnd_t[ 1 ] = FLT_MAX; \ globals->Boxp_ubnd_t[ 1 ] = FLT_MIN; \ globals->Boxp_freeze_t = 0; \ globals->Map1_plot_t = NULL; \ globals->Map1_map_t = NULL; \ globals->Map1_frame_t = NULL; \ globals->Map1_origin_t = NULL; \ globals->Map1_statics_t = NULL; \ globals->Map2_plot_t = NULL; \ globals->Map2_map_t = NULL; \ globals->Map2_statics_t = NULL; \ globals->Map3_plot_t = NULL; \ globals->Map3_map_t = NULL; \ globals->Map3_frame_t = NULL; \ globals->Map3_origin_t = NULL; \ globals->Map3_end_t = NULL; \ globals->Map3_statics_t = NULL; \ globals->Map4_plot_t = NULL; \ globals->Map4_map_t = NULL; \ globals->Map4_umap_t = NULL; \ globals->Map4_statics_t = NULL; \ globals->Map5_plot_t = NULL; \ globals->Map5_region_t = NULL; \ globals->Map5_map_t = NULL; \ globals->Map5_statics_t = NULL; \ globals->Poly_n_t = 0; \ globals->Poly_x_t = NULL; \ globals->Poly_y_t = NULL; \ globals->Poly_npoly_t = 0; \ globals->Poly_np_t = NULL; \ globals->Poly_xp_t = NULL; \ globals->Poly_yp_t = NULL; \ globals->Curve_data_t.nbrk = -1; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->SplitValue_Buff[ 0 ] = 0; \ globals->StripEscapes_Buff[ 0 ] = 0; \ globals->Grf_chv_t = AST__BAD; \ globals->Grf_chh_t = AST__BAD; \ globals->Grf_alpha_t = 0.0; \ globals->Grf_beta_t = 0.0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Plot) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(Plot,Class_Init) #define class_vtab astGLOBAL(Plot,Class_Vtab) #define grfattrs_nesting astGLOBAL(Plot,GrfAttrs_nesting_t) #define grfattrs_attrs astGLOBAL(Plot,GrfAttrs_attrs_t) #define Crv_limit astGLOBAL(Plot,Crv_limit_t) #define Crv_scerr astGLOBAL(Plot,Crv_scerr_t) #define Crv_tol astGLOBAL(Plot,Crv_tol_t) #define Crv_ux0 astGLOBAL(Plot,Crv_ux0_t) #define Crv_uy0 astGLOBAL(Plot,Crv_uy0_t) #define Crv_vxl astGLOBAL(Plot,Crv_vxl_t) #define Crv_vyl astGLOBAL(Plot,Crv_vyl_t) #define Crv_xhi astGLOBAL(Plot,Crv_xhi_t) #define Crv_xl astGLOBAL(Plot,Crv_xl_t) #define Crv_xlo astGLOBAL(Plot,Crv_xlo_t) #define Crv_yhi astGLOBAL(Plot,Crv_yhi_t) #define Crv_yl astGLOBAL(Plot,Crv_yl_t) #define Crv_ylo astGLOBAL(Plot,Crv_ylo_t) #define Crv_vxbrk astGLOBAL(Plot,Crv_vxbrk_t) #define Crv_vybrk astGLOBAL(Plot,Crv_vybrk_t) #define Crv_xbrk astGLOBAL(Plot,Crv_xbrk_t) #define Crv_ybrk astGLOBAL(Plot,Crv_ybrk_t) #define Crv_len astGLOBAL(Plot,Crv_len_t) #define Crv_ink astGLOBAL(Plot,Crv_ink_t) #define Crv_nbrk astGLOBAL(Plot,Crv_nbrk_t) #define Crv_nent astGLOBAL(Plot,Crv_nent_t) #define Crv_out astGLOBAL(Plot,Crv_out_t) #define Crv_clip astGLOBAL(Plot,Crv_clip_t) #define Crv_map astGLOBAL(Plot,Crv_map_t) #define Box_lbnd astGLOBAL(Plot,Box_lbnd_t) #define Box_ubnd astGLOBAL(Plot,Box_ubnd_t) #define Boxp_lbnd astGLOBAL(Plot,Boxp_lbnd_t) #define Boxp_ubnd astGLOBAL(Plot,Boxp_ubnd_t) #define Boxp_freeze astGLOBAL(Plot,Boxp_freeze_t) #define Poly_x astGLOBAL(Plot,Poly_x_t) #define Poly_y astGLOBAL(Plot,Poly_y_t) #define Poly_n astGLOBAL(Plot,Poly_n_t) #define Poly_xp astGLOBAL(Plot,Poly_xp_t) #define Poly_yp astGLOBAL(Plot,Poly_yp_t) #define Poly_np astGLOBAL(Plot,Poly_np_t) #define Poly_npoly astGLOBAL(Plot,Poly_npoly_t) #define Map1_ncoord astGLOBAL(Plot,Map1_ncoord_t) #define Map1_plot astGLOBAL(Plot,Map1_plot_t) #define Map1_map astGLOBAL(Plot,Map1_map_t) #define Map1_frame astGLOBAL(Plot,Map1_frame_t) #define Map1_origin astGLOBAL(Plot,Map1_origin_t) #define Map1_length astGLOBAL(Plot,Map1_length_t) #define Map1_axis astGLOBAL(Plot,Map1_axis_t) #define Map1_statics astGLOBAL(Plot,Map1_statics_t) #define Map1_norm astGLOBAL(Plot,Map1_norm_t) #define Map1_log astGLOBAL(Plot,Map1_log_t) #define Map2_ncoord astGLOBAL(Plot,Map2_ncoord_t) #define Map2_plot astGLOBAL(Plot,Map2_plot_t) #define Map2_map astGLOBAL(Plot,Map2_map_t) #define Map2_x0 astGLOBAL(Plot,Map2_x0_t) #define Map2_y0 astGLOBAL(Plot,Map2_y0_t) #define Map2_deltax astGLOBAL(Plot,Map2_deltax_t) #define Map2_deltay astGLOBAL(Plot,Map2_deltay_t) #define Map2_statics astGLOBAL(Plot,Map1_statics_t) #define Map3_ncoord astGLOBAL(Plot,Map3_ncoord_t) #define Map3_plot astGLOBAL(Plot,Map3_plot_t) #define Map3_map astGLOBAL(Plot,Map3_map_t) #define Map3_frame astGLOBAL(Plot,Map3_frame_t) #define Map3_origin astGLOBAL(Plot,Map3_origin_t) #define Map3_end astGLOBAL(Plot,Map3_end_t) #define Map3_scale astGLOBAL(Plot,Map3_scale_t) #define Map3_statics astGLOBAL(Plot,Map3_statics_t) #define Map4_ncoord astGLOBAL(Plot,Map4_ncoord_t) #define Map4_plot astGLOBAL(Plot,Map4_plot_t) #define Map4_map astGLOBAL(Plot,Map4_map_t) #define Map4_umap astGLOBAL(Plot,Map4_umap_t) #define Map4_statics astGLOBAL(Plot,Map4_statics_t) #define Map5_plot astGLOBAL(Plot,Map5_plot_t) #define Map5_region astGLOBAL(Plot,Map5_region_t) #define Map5_map astGLOBAL(Plot,Map5_map_t) #define Map5_ncoord astGLOBAL(Plot,Map5_ncoord_t) #define Map5_statics astGLOBAL(Plot,Map5_statics_t) #define Curve_data astGLOBAL(Plot,Curve_data_t) #define getattrib_buff astGLOBAL(Plot,GetAttrib_Buff) #define splitvalue_buff astGLOBAL(Plot,SplitValue_Buff) #define stripescapes_buff astGLOBAL(Plot,StripEscapes_Buff) #define Grf_chv astGLOBAL(Plot,Grf_chv_t) #define Grf_chh astGLOBAL(Plot,Grf_chh_t) #define Grf_alpha astGLOBAL(Plot,Grf_alpha_t) #define Grf_beta astGLOBAL(Plot,Grf_beta_t) static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Variables used within astGrfAttrs_ */ static double grfattrs_attrs[ GRF__NATTR ]; /* Saved attribute values */ static int grfattrs_nesting = 0; /* Nesting level. */ /* Variables used to pass information to the curve drawing functions. See the prologues of functions Crv and CrvLine for details. */ static double Crv_limit; static double Crv_scerr; static double Crv_tol; static double Crv_ux0; static double Crv_uy0; static double Crv_vxl; static double Crv_vyl; static double Crv_xhi; static double Crv_xl; static double Crv_xlo; static double Crv_yhi; static double Crv_yl; static double Crv_ylo; static float *Crv_vxbrk; static float *Crv_vybrk; static float *Crv_xbrk; static float *Crv_ybrk; static float Crv_len; static int Crv_ink; static int Crv_nbrk; static int Crv_nent = 0; static int Crv_out; static int Crv_clip; static void (*Crv_map)( int, double *, double *, double *, const char *, const char *, int * ); /* A cache of information calculated by the grf module. */ static double Grf_chv = AST__BAD; static double Grf_chh = AST__BAD; static float Grf_alpha = 0.0; static float Grf_beta = 0.0; /* The lower and upper bounds of the graphics coordinates enclosing all lines and numerical labels drawn by astGrid. */ static float Box_lbnd[ 2 ] = {FLT_MAX, FLT_MAX }; static float Box_ubnd[ 2 ] = {FLT_MIN, FLT_MIN }; /* The lower and upper bounds of the graphics coordinates enclosing all drawn graphics primatives, maintained by functions GLine, GMark and DrawText. */ static float Boxp_lbnd[ 2 ] = {FLT_MAX, FLT_MAX }; static float Boxp_ubnd[ 2 ] = {FLT_MIN, FLT_MIN }; static int Boxp_freeze = 0; /* Variables used to stored buffered poly lines (see functions Opoly, Bpoly and Apoly). */ static float *Poly_x = NULL; static float *Poly_y = NULL; static int Poly_n = 0; static float **Poly_xp = NULL; static float **Poly_yp = NULL; static int *Poly_np = NULL; static int Poly_npoly = 0; /* Variables used by function Map1. See the prologue of Map1 for details. */ static int Map1_ncoord; static AstPlot *Map1_plot = NULL; static AstMapping *Map1_map = NULL; static AstFrame *Map1_frame = NULL; static const double *Map1_origin = NULL; static double Map1_length; static void *Map1_statics = NULL; static int Map1_axis; static int Map1_norm; static int Map1_log; /* Variables used by function Map2. See the prologue of Map2 for details. */ static int Map2_ncoord; static AstPlot *Map2_plot = NULL; static AstMapping *Map2_map = NULL; static double Map2_x0; static double Map2_y0; static double Map2_deltax; static double Map2_deltay; static void *Map2_statics = NULL; /* Variables used by function Map3. See the prologue of Map3 for details. */ static int Map3_ncoord; static AstPlot *Map3_plot = NULL; static AstMapping *Map3_map = NULL; static AstFrame *Map3_frame = NULL; static const double *Map3_origin = NULL; static const double *Map3_end = NULL; static double Map3_scale; static void *Map3_statics = NULL; /* Variables used by function Map4. See the prologue of Map4 for details. */ static int Map4_ncoord; static AstPlot *Map4_plot = NULL; static AstMapping *Map4_map = NULL; static AstMapping *Map4_umap = NULL; static void *Map4_statics = NULL; /* Variables used by function Map5. See the prologue of Map5 for details. */ static AstPlot *Map5_plot = NULL; static AstMapping *Map5_map = NULL; static AstRegion *Map5_region = NULL; static void *Map5_statics = NULL; static int Map5_ncoord; /* A structure which stores information about the breaks in the last curve drawn using the public methods "astGridLine" and "astCurve". */ static AstPlotCurveData Curve_data; /* Buffers for strings returned by various functions. */ static char splitvalue_buff[ 200 ]; static char stripescapes_buff[ AST__PLOT_STRIPESCAPES_BUFF_LEN + 1 ]; static char getattrib_buff[ 200 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstPlotVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #endif /* Macro to reset the cache of values caclulated by the grf module. */ #define RESET_GRF \ Grf_chh = AST__BAD; \ Grf_chv = AST__BAD; \ Grf_alpha = 0.0; \ Grf_beta = 0.0; /* Prototypes for Private Member Functions. */ /* ======================================== */ static double GetTol( AstPlot *, int * ); static int TestTol( AstPlot *, int * ); static void ClearTol( AstPlot *, int * ); static void SetTol( AstPlot *, double, int * ); static int GetGrid( AstPlot *, int * ); static int TestGrid( AstPlot *, int * ); static void ClearGrid( AstPlot *, int * ); static void SetGrid( AstPlot *, int, int * ); static int GetTickAll( AstPlot *, int * ); static int TestTickAll( AstPlot *, int * ); static void ClearTickAll( AstPlot *, int * ); static void SetTickAll( AstPlot *, int, int * ); static int GetForceExterior( AstPlot *, int * ); static int TestForceExterior( AstPlot *, int * ); static void ClearForceExterior( AstPlot *, int * ); static void SetForceExterior( AstPlot *, int, int * ); static int GetBorder( AstPlot *, int * ); static int TestBorder( AstPlot *, int * ); static void ClearBorder( AstPlot *, int * ); static void SetBorder( AstPlot *, int, int * ); static int GetInvisible( AstPlot *, int * ); static int TestInvisible( AstPlot *, int * ); static void ClearInvisible( AstPlot *, int * ); static void SetInvisible( AstPlot *, int, int * ); static int GetInk( AstPlot *, int * ); static int TestInk( AstPlot *, int * ); static void ClearInk( AstPlot *, int * ); static void SetInk( AstPlot *, int, int * ); static int GetClipOp( AstPlot *, int * ); static int TestClipOp( AstPlot *, int * ); static void ClearClipOp( AstPlot *, int * ); static void SetClipOp( AstPlot *, int, int * ); static int GetClip( AstPlot *, int * ); static int TestClip( AstPlot *, int * ); static void ClearClip( AstPlot *, int * ); static void SetClip( AstPlot *, int, int * ); static int GetGrf( AstPlot *, int * ); static int TestGrf( AstPlot *, int * ); static void ClearGrf( AstPlot *, int * ); static void SetGrf( AstPlot *, int, int * ); static int GetDrawTitle( AstPlot *, int * ); static int TestDrawTitle( AstPlot *, int * ); static void ClearDrawTitle( AstPlot *, int * ); static void SetDrawTitle( AstPlot *, int, int * ); static int GetDrawAxes( AstPlot *, int, int * ); static int TestDrawAxes( AstPlot *, int, int * ); static void ClearDrawAxes( AstPlot *, int, int * ); static void SetDrawAxes( AstPlot *, int, int, int * ); static int GetAbbrev( AstPlot *, int, int * ); static int TestAbbrev( AstPlot *, int, int * ); static void ClearAbbrev( AstPlot *, int, int * ); static void SetAbbrev( AstPlot *, int, int, int * ); static int GetEscape( AstPlot *, int * ); static int TestEscape( AstPlot *, int * ); static void ClearEscape( AstPlot *, int * ); static void SetEscape( AstPlot *, int, int * ); static double GetLabelAt( AstPlot *, int, int * ); static int TestLabelAt( AstPlot *, int, int * ); static void ClearLabelAt( AstPlot *, int, int * ); static void SetLabelAt( AstPlot *, int, double, int * ); static double GetNumLabGap( AstPlot *, int, int * ); static int TestNumLabGap( AstPlot *, int, int * ); static void ClearNumLabGap( AstPlot *, int, int * ); static void SetNumLabGap( AstPlot *, int, double, int * ); static double GetTextLabGap( AstPlot *, int, int * ); static int TestTextLabGap( AstPlot *, int, int * ); static void ClearTextLabGap( AstPlot *, int, int * ); static void SetTextLabGap( AstPlot *, int, double, int * ); static double GetCentre( AstPlot *, int, int * ); static int TestCentre( AstPlot *, int, int * ); static void ClearCentre( AstPlot *, int, int * ); static void SetCentre( AstPlot *, int, double, int * ); static double GetGap( AstPlot *, int, int * ); static int TestGap( AstPlot *, int, int * ); static void ClearGap( AstPlot *, int, int * ); static void SetGap( AstPlot *, int, double, int * ); static int GetLabelling( AstPlot *, int * ); static int TestLabelling( AstPlot *, int * ); static void ClearLabelling( AstPlot *, int * ); static void SetLabelling( AstPlot *, int, int * ); static double GetMajTickLen( AstPlot *, int, int * ); static int TestMajTickLen( AstPlot *, int, int * ); static void ClearMajTickLen( AstPlot *, int, int * ); static void SetMajTickLen( AstPlot *, int, double, int * ); static double GetLogGap( AstPlot *, int, int * ); static int TestLogGap( AstPlot *, int, int * ); static void ClearLogGap( AstPlot *, int, int * ); static void SetLogGap( AstPlot *, int, double, int * ); static double GetTitleGap( AstPlot *, int * ); static int TestTitleGap( AstPlot *, int * ); static void ClearTitleGap( AstPlot *, int * ); static void SetTitleGap( AstPlot *, double, int * ); static double GetMinTickLen( AstPlot *, int, int * ); static int TestMinTickLen( AstPlot *, int, int * ); static void ClearMinTickLen( AstPlot *, int, int * ); static void SetMinTickLen( AstPlot *, int, double, int * ); static int GetEdge( AstPlot *, int, int * ); static int TestEdge( AstPlot *, int, int * ); static void ClearEdge( AstPlot *, int, int * ); static void SetEdge( AstPlot *, int, int, int * ); static int GetLabelUp( AstPlot *, int, int * ); static int TestLabelUp( AstPlot *, int, int * ); static void ClearLabelUp( AstPlot *, int, int * ); static void SetLabelUp( AstPlot *, int, int, int * ); static int GetLogPlot( AstPlot *, int, int * ); static int TestLogPlot( AstPlot *, int, int * ); static void ClearLogPlot( AstPlot *, int, int * ); static void SetLogPlot( AstPlot *, int, int, int * ); static int GetLogTicks( AstPlot *, int, int * ); static int TestLogTicks( AstPlot *, int, int * ); static void ClearLogTicks( AstPlot *, int, int * ); static void SetLogTicks( AstPlot *, int, int, int * ); static int GetLogLabel( AstPlot *, int, int * ); static int TestLogLabel( AstPlot *, int, int * ); static void ClearLogLabel( AstPlot *, int, int * ); static void SetLogLabel( AstPlot *, int, int, int * ); static int GetNumLab( AstPlot *, int, int * ); static int TestNumLab( AstPlot *, int, int * ); static void ClearNumLab( AstPlot *, int, int * ); static void SetNumLab( AstPlot *, int, int, int * ); static int GetMinTick( AstPlot *, int, int * ); static int TestMinTick( AstPlot *, int, int * ); static void ClearMinTick( AstPlot *, int, int * ); static void SetMinTick( AstPlot *, int, int, int * ); static int GetTextLab( AstPlot *, int, int * ); static int TestTextLab( AstPlot *, int, int * ); static void ClearTextLab( AstPlot *, int, int * ); static void SetTextLab( AstPlot *, int, int, int * ); static int GetLabelUnits( AstPlot *, int, int * ); static int TestLabelUnits( AstPlot *, int, int * ); static void ClearLabelUnits( AstPlot *, int, int * ); static void SetLabelUnits( AstPlot *, int, int, int * ); static int GetStyle( AstPlot *, int, int * ); static int TestStyle( AstPlot *, int, int * ); static void ClearStyle( AstPlot *, int, int * ); static void SetStyle( AstPlot *, int, int, int * ); static int GetFont( AstPlot *, int, int * ); static int TestFont( AstPlot *, int, int * ); static void ClearFont( AstPlot *, int, int * ); static void SetFont( AstPlot *, int, int, int * ); static int GetColour( AstPlot *, int, int * ); static int TestColour( AstPlot *, int, int * ); static void ClearColour( AstPlot *, int, int * ); static void SetColour( AstPlot *, int, int, int * ); static double GetWidth( AstPlot *, int, int * ); static int TestWidth( AstPlot *, int, int * ); static void ClearWidth( AstPlot *, int, int * ); static void SetWidth( AstPlot *, int, double, int * ); static double GetSize( AstPlot *, int, int * ); static int TestSize( AstPlot *, int, int * ); static void ClearSize( AstPlot *, int, int * ); static void SetSize( AstPlot *, int, double, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static AstFrameSet *Fset2D( AstFrameSet *, int, int * ); static AstKeyMap *GetGrfContext( AstPlot *, int * ); static AstPlotCurveData **CleanCdata( AstPlotCurveData **, int * ); static AstPlotCurveData **DrawGrid( AstPlot *, TickInfo **, int, const char *, const char *, int * ); static AstPointSet *DefGap( AstPlot *, double *, int *, double *, int *, const char *, const char *, int * ); static AstPointSet *GetDrawnTicks( AstPlot *, int, int, int * ); static AstPointSet *Trans( AstPlot *, AstFrame *, AstMapping *, AstPointSet *, int, AstPointSet *, int, const char *, const char *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static TickInfo **CleanGrid( TickInfo **, int * ); static TickInfo **GridLines( AstPlot *, double *, double *, int *, const char *, const char *, int * ); static TickInfo *TickMarks( AstPlot *, int, double *, double *, int *, GetTicksStatics **, const char *, const char *, int * ); static char **CheckLabels2( AstPlot *, AstFrame *, int, double *, int, char **, double, int * ); static char *FindWord( char *, const char *, const char **, int * ); static char *GrfItem( int, const char *, int *, int * ); static const char *JustMB( AstPlot *, int, const char *, float *, float *, float, float, const char *, float, float, float, float, float *, float *, const char *, const char *, int * ); static const char *SplitValue( AstPlot *, const char *, int, int *, int * ); static double **MakeGrid( AstPlot *, AstFrame *, AstMapping *, int, int, double, double, double, double, int, AstPointSet **, AstPointSet**, int, const char *, const char *, int * ); static double GetTicks( AstPlot *, int, double *, double **, int *, double **, int *, int, int *, double *, GetTicksStatics **, const char *, const char *, int * ); static double GetUseSize( AstPlot *, int, int * ); static double GetUseWidth( AstPlot *, int, int * ); static double GoodGrid( AstPlot *, int *, AstPointSet **, AstPointSet **, const char *, const char *, int * ); static double Typical( int, double *, double, double, double *, int * ); static int Border( AstPlot *, int * ); static int Boundary( AstPlot *, const char *, const char *, int * ); static int BoxCheck( float *, float *, float *, float *, int * ); static int CGAttrWrapper( AstPlot *, int, double, double *, int, int * ); static int CGBBufWrapper( AstPlot *, int * ); static int CGCapWrapper( AstPlot *, int, int, int * ); static int CGEBufWrapper( AstPlot *, int * ); static int CGFlushWrapper( AstPlot *, int * ); static int CGLineWrapper( AstPlot *, int, const float *, const float *, int * ); static int CGMarkWrapper( AstPlot *, int, const float *, const float *, int, int * ); static int CGQchWrapper( AstPlot *, float *, float *, int * ); static int CGScalesWrapper( AstPlot *, float *, float *, int * ); static int CGTextWrapper( AstPlot *, const char *, float, float, const char *, float, float, int * ); static int CGTxExtWrapper( AstPlot *, const char *, float, float, const char *, float, float, float *, float *, int * ); static int CheckLabels( AstPlot *, AstFrame *, int, double *, int, int, char **, double, int * ); static int ChrLen( const char *, int * ); static int Compare_LL( const void *, const void * ); static int Compared( const void *, const void * ); static int CountGood( int, double *, int * ); static int Cross( float, float, float, float, float, float, float, float, int * ); static int CvBrk( AstPlot *, int, double *, double *, double *, int * ); static int EdgeCrossings( AstPlot *, int, int, double, double *, double **, EdgeCrossingsStatics **, const char *, const char *, int * ); static int EdgeLabels( AstPlot *, int, TickInfo **, AstPlotCurveData **, int, const char *, const char *, int * ); static int FindDPTZ( AstFrame *, int, const char *, const char *, int *, int *, int * ); static int FindMajTicks( AstMapping *, AstFrame *, int, double, double, double , double *, int, double *, double **, int * ); static int FindMajTicks2( int, double, double, int, double *, double **, int * ); static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * ); static int Fpoly_ecmp( const void *, const void * ); static int Fpoly_scmp( const void *, const void * ); static int FullForm( const char *, const char *, const char *, const char *, const char *, int * ); static int GCap( AstPlot *, int, int, int * ); static int GVec( AstPlot *, AstMapping *, double *, int, double, AstPointSet **, AstPointSet **, double *, double *, double *, double *, int *, const char *, const char *, int * ); static int GetUseColour( AstPlot *, int, int * ); static int GetUseFont( AstPlot *, int, int * ); static int GetUseStyle( AstPlot *, int, int * ); static int GraphGrid( int, int, double, double, double, double, double **, int * ); static int HasEscapes( const char *, int * ); static int IdFind( int, int, int *, int *, int *, int * ); static int Inside( int, float *, float *, float, float, int * ); static int IsASkyAxis( AstFrame *, int, int * ); static int IsASkyFrame( AstObject *, int * ); static int Labelat( AstPlot *, TickInfo **, AstPlotCurveData **, double *, const char *, const char *, int * ); static int Overlap( AstPlot *, int, int, const char *, float, float, const char *, float, float, float **, const char *, const char *, int * ); static int PopGat( AstPlot *, float *, const char *, const char *, int * ); static int RegionOutline( AstPlot *, AstFrame *, const char *, const char *, int * ); static int TestUseColour( AstPlot *, int, int * ); static int TestUseFont( AstPlot *, int, int * ); static int TestUseSize( AstPlot *, int, int * ); static int TestUseStyle( AstPlot *, int, int * ); static int TestUseWidth( AstPlot *, int, int * ); static int ToggleLogLin( AstPlot *, int, int, const char *, int * ); static int TraceBorder( AstPlot *, AstMapping *, double, double, double, double, int, double, int[ 4 ], const char *, const char *, int * ); static int Ustrcmp( const char *, const char *, int * ); static int Ustrncmp( const char *, const char *, size_t, int * ); static int swapEdges( AstPlot *, TickInfo **, AstPlotCurveData **, int * ); static void AddCdt( AstPlotCurveData *, AstPlotCurveData *, const char *, const char *, int * ); static void Apoly( AstPlot *, float, float, int * ); static void AxPlot( AstPlot *, int, const double *, double, int, AstPlotCurveData *, const char *, const char *, int * ); static void BBuf( AstPlot *, int * ); static void BoundingBox( AstPlot *, float[2], float[2], int * ); static void Bpoly( AstPlot *, float, float, int * ); static void Clip( AstPlot *, int, const double [], const double [], int * ); static void Copy( const AstObject *, AstObject *, int * ); static void CopyPlotDefaults( AstPlot *, int, AstPlot *, int, int * ); static void Crv( AstPlot *this, double *, double *, double *, int, double *, CrvStatics *, const char *, const char *, int * ); static void CrvLine( AstPlot *this, double, double, double, double, const char *, const char *, int * ); static void Curve( AstPlot *, const double [], const double [], int * ); static void CurvePlot( AstPlot *, const double *, const double *, int , AstPlotCurveData *, const char *, const char *, int * ); static void Delete( AstObject *, int * ); static void DrawAxis( AstPlot *, TickInfo **, double *, double *, const char *, const char *, int * ); static void DrawText( AstPlot *, int, int, const char *, float, float, const char *, float, float, float *, float *, float *, const char *, const char *, int * ); static void DrawTicks( AstPlot *, TickInfo **, int, double *, double *, const char *, const char *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void EBuf( AstPlot *, int * ); static void Fpoly( AstPlot *, const char *, const char *, int * ); static void GAttr( AstPlot *, int, double, double *, int, const char *, const char *, int * ); static void GBBuf( AstPlot *, const char *, const char *, int * )__attribute__((unused)); static void GEBuf( AstPlot *, const char *, const char *, int * )__attribute__((unused)); static void GFlush( AstPlot *, const char *, const char *, int * )__attribute__((unused)); static void GLine( AstPlot *, int, const float *, const float *, const char *, const char *, int * ); static void GMark( AstPlot *, int, const float *, const float *, int, const char *, const char *, int * ); static void GQch( AstPlot *, float *, float *, const char *, const char *, int * ); static void GScales( AstPlot *, float *, float *, const char *, const char *, int * ); static void GText( AstPlot *, const char *, float, float, const char *, float, float, const char *, const char *, int * ); static void GTxExt( AstPlot *, const char *, float , float, const char *, float, float, float *, float *, const char *, const char *, int * ); static void GenCurve( AstPlot *, AstMapping *, int * ); static void GrfPop( AstPlot *, int * ); static void GrfPush( AstPlot *, int * ); static void GrfSet( AstPlot *, const char *, AstGrfFun, int * ); static void GrfWrapper( AstPlot *, const char *, AstGrfWrap, int * ); static void Grid( AstPlot *, int * ); static void GridLine( AstPlot *, int, const double [], double, int * ); static void InterpEscape( AstPlot *, int, double, float *, float *, float, float, float, float, const char *, float *, double, double, double, double, double, const char *, const char *, int * ); static void Labels( AstPlot *, TickInfo **, AstPlotCurveData **, double *, double *, const char *, const char *, int * ); static void LinePlot( AstPlot *, double, double, double, double, int, AstPlotCurveData *, const char *, const char *, int * ); static void Map1( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); static void Map2( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); static void Map3( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); static void Map4( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); static void Map5( int, double *, double *, double *, const char *, const char *, int * GLOBALS_PROTO ); static void Mark( AstPlot *, int, int, int, const double *, int, int * ); static void Mirror( AstPlot *, int, int * ); static void Norm1( AstMapping *, int, int, double *, double, double, int * ); static void Opoly( AstPlot *, int * ); static void PlotLabels( AstPlot *, int, AstFrame *, int, LabelList *, char *, int, float **, const char *, const char *, int * ); static void PolyCurve( AstPlot *, int, int, int, const double *, int * ); static void PurgeCdata( AstPlotCurveData *, int * ); static void PushGat( AstPlot *, float, const char *, const char *, int * ); static void RemoveFrame( AstFrameSet *, int, int * ); static void RightVector( AstPlot *, float *, float *, float *, float *, const char *, const char *, int * ); static void SaveTick( AstPlot *, int, double, double, int, int * ); static void SetTickValues( AstPlot *, int, int, double *, int, double *, int * ); static void Text( AstPlot *, const char *, const double [], const float [], const char *, int * ); static void TextLabels( AstPlot *, int, int *, const char *, const char *, int * ); static void Ticker( AstPlot *, int, int, double, double *, double, int, int, EdgeCrossingsStatics **, const char *, const char *, int * ); static void UpdateConcat( float *, float *, float, float, float, float, float *, float *, float, float, float *, float *, float *, float *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Functions which access class attributes. */ /* ======================================= */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Tol. */ /* ---- */ /* *att++ * Name: * Tol * Purpose: * Plotting tolerance. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute specifies the plotting tolerance (or resolution) * to be used for the graphical output produced by a Plot. Smaller * values will result in smoother and more accurate curves being * drawn, but may slow down the plotting process. Conversely, * larger values may speed up the plotting process in cases where * high resolution is not required. * * The Tol value should be given as a fraction of the minimum * dimension of the plotting area, and should lie in the range c from 1.0e-7 to 1.0. By default, a value of 0.01 is used. f from 1.0E-7 to 1.0. By default, a value of 0.01 is used. * Applicability: * Plot * All Plots have this attribute. *att-- */ /* The plotting tolerance. Has a value of -1.0 when not set yielding a default value of 0.01. Usable values are in the range 1.0E-7 to 1.0. */ astMAKE_CLEAR(Plot,Tol,tol,-1.0) astMAKE_GET(Plot,Tol,double,0.01,(this->tol == -1.0 ? 0.01 : this->tol)) astMAKE_SET(Plot,Tol,double,tol,MIN(MAX(value,1.0E-7),1.0)) astMAKE_TEST(Plot,Tol,( this->tol != -1.0 )) /* Grid. */ /* ----- */ /* *att++ * Name: * Grid * Purpose: * Draw grid lines for a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether grid lines (a grid of curves marking the "major" values * on each axis) are drawn across the plotting area. * * If the Grid value of a Plot is non-zero, then grid lines will be * drawn. Otherwise, short tick marks on the axes are used to mark * the major axis values. The default behaviour is to use tick * marks if the entire plotting area is filled by valid physical * coordinates, but to draw grid lines otherwise. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The spacing between major axis values, which determines the * spacing of grid lines, may be set using the Gap(axis) attribute. *att-- */ /* If non-zero use lines instead of tick marks in a coordinate grid. Has a value of -1 when not set yielding a default value of 0. */ astMAKE_CLEAR(Plot,Grid,grid,-1) astMAKE_GET(Plot,Grid,int,0,(this->grid == -1 ? 0 : this->grid)) astMAKE_SET(Plot,Grid,int,grid,( value ? 1 : 0 )) astMAKE_TEST(Plot,Grid,( this->grid != -1 )) MAKE_GET2(Plot,Grid,int,0,this->ugrid) MAKE_SET2(Plot,Grid,int,ugrid,( value ? 1 : 0 )) /* Invisible. */ /* ---------- */ /* *att++ * Name: * Invisible * Purpose: * Draw graphics using invisible ink? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of all graphics produced by * Plot methods by determining whether graphics should be visible or * invisible. * * If the Invisible value of a Plot is non-zero, then all the Plot * methods which normally generate graphical output do not do so (you * can think of them drawing with "invisible ink"). Such methods do, * however, continue to do all the calculations which would be needed to * produce the graphics. In particular, the bounding box enclosing the * graphics is still calculated and can be retrieved as normal using c astBoundingBox. The default value is zero, resulting in all methods f AST_BOUNDINGBOX. The default value is zero, resulting in all methods * drawing graphics as normal, using visible ink. * Applicability: * Plot * All Plots have this attribute. *att-- */ /* If non-zero use invisible ink. Has a value of -1 when not set yielding a default value of 0. */ astMAKE_CLEAR(Plot,Invisible,invisible,-1) astMAKE_GET(Plot,Invisible,int,0,(this->invisible == -1 ? 0 : this->invisible)) astMAKE_SET(Plot,Invisible,int,invisible,( value ? 1 : 0 )) astMAKE_TEST(Plot,Invisible,( this->invisible != -1 )) /* TickAll */ /* ------- */ /* *att++ * Name: * TickAll * Purpose: * Draw tick marks on all edges of a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether tick marks should be drawn on all edges of a Plot. * * If the TickAll value of a Plot is non-zero (the default), then * tick marks will be drawn on all edges of the Plot. Otherwise, * they will be drawn only on those edges where the numerical and * descriptive axis labels are drawn (see the Edge(axis) * attribute). * Applicability: * Plot * All Plots have this attribute. * Notes: * - In some circumstances, numerical labels and tick marks are * drawn along grid lines inside the plotting area, rather than * around its edges (see the Labelling attribute). In this case, * the value of the TickAll attribute is ignored. *att-- */ /* If non-zero put tick marks on opposite edges. Has a value of -1 when not set yielding a default value of 1. */ astMAKE_CLEAR(Plot,TickAll,tickall,-1) astMAKE_GET(Plot,TickAll,int,1,(this->tickall == -1 ? 1 : this->tickall)) astMAKE_SET(Plot,TickAll,int,tickall,( value ? 1 : 0 )) astMAKE_TEST(Plot,TickAll,( this->tickall != -1 )) /* ForceExterior */ /* ------------- */ /* *att+ * Name: * ForceExterior * Purpose: * Force the use of exterior labelling? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by forcing f coordinate grid (drawn with the AST_GRID routine) by forcing * labels and tick marks to be drawn round the edges of the plot * (rather than across the middle of the plot), even if there appear * to be insufficient edge crossings to justify the use of exterior * labelling. * * The default value of zero results in the decision about whether to * use interior or exterior labelling being made purely on the basis * of the value of the Labelling attribute. If ForceExterior is set to * a non-zero value, then the Labelling attribute is ignored and exterior * labelling will always be attempted, even if there appear to be * insufficient edge labels to justify their use. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The value of this attribute is currently under investigation, and * so this attribute prologue is currently marked as protected rather * than public (in order to prevent it being included in the public * documentation). *att- */ astMAKE_CLEAR(Plot,ForceExterior,forceexterior,-1) astMAKE_GET(Plot,ForceExterior,int,0,(this->forceexterior == -1 ? 0 : this->forceexterior)) astMAKE_SET(Plot,ForceExterior,int,forceexterior,( value ? 1 : 0 )) astMAKE_TEST(Plot,ForceExterior,( this->forceexterior != -1 )) /* *att++ * Name: * Border * Purpose: * Draw a border around valid regions of a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether a border is drawn around regions corresponding to the c valid physical coordinates of a Plot (c.f. astBorder). f valid physical coordinates of a Plot (c.f. AST_BORDER). * * If the Border value of a Plot is non-zero, then this border will * be drawn as part of the grid. Otherwise, the border is not drawn * (although axis labels and tick marks will still appear, unless * other relevant Plot attributes indicate that they should * not). The default behaviour is to draw the border if tick marks * and numerical labels will be drawn around the edges of the * plotting area (see the Labelling attribute), but to omit it * otherwise. * Applicability: * Plot * All Plots have this attribute. *att-- */ /* If non-zero draw the border. Has a value of -1 when not set, yeilding a default of 1. */ astMAKE_CLEAR(Plot,Border,border,-1) astMAKE_SET(Plot,Border,int,border,( value ? 1 : 0 )) astMAKE_TEST(Plot,Border,( this->border != -1 )) astMAKE_GET(Plot,Border,int,1,(this->border == -1 ? 1 : this->border)) MAKE_SET2(Plot,Border,int,uborder,( value ? 1 : 0 )) MAKE_GET2(Plot,Border,int,1,this->uborder) /* Clip */ /* ---- */ /* *att++ * Name: * Clip * Purpose: * Clip lines and/or markers at the Plot boundary? * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute controls whether curves and markers are clipped at the * boundary of the graphics box specified when the Plot was created. A * value of 3 implies both markers and curves are clipped at the Plot * boundary. A value of 2 implies markers are clipped, but not curves. A * value of 1 implies curves are clipped, but not markers. A value of * zero implies neither curves nor markers are clipped. The default * value is 1. Note, this attributes controls only the clipping * performed internally within AST. The underlying graphics system may * also apply clipping. In such cases, removing clipping using this * attribute does not guarantee that no clipping will be visible in the * final plot. * c The astClip function f The AST_CLIP routine * can be used to establish generalised clipping within arbitrary * regions of the Plot. * Applicability: * Plot * All Plots have this attribute. *att-- */ astMAKE_CLEAR(Plot,Clip,clip,-1) astMAKE_GET(Plot,Clip,int,0,(this->clip == -1 ? 1 : this->clip)) astMAKE_TEST(Plot,Clip,( this->clip != -1 )) astMAKE_SET(Plot,Clip,int,clip,((value>=0&&value<=3)?value:(astError( AST__ATTIN, "astSetClip(Plot): Invalid value %d supplied for Clip attribute", status, value ), this->clip))) /* ClipOp */ /* ------ */ /* *att++ * Name: * ClipOp * Purpose: * Combine Plot clipping limits using a boolean OR? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls how the clipping limits specified for c each axis of a Plot (using the astClip function) are f each axis of a Plot (using the AST_CLIP routine) are * combined. This, in turn, determines which parts of the graphical * output will be visible. * * If the ClipOp attribute of a Plot is zero (the default), * graphical output is visible only if it satisfies the clipping * limits on all the axes of the clipping Frame (a boolean * AND). Otherwise, if ClipOp is non-zero, output is visible if it * satisfies the clipping limits on one or more axes (a boolean * OR). * * An important use of this attribute is to allow areas of a Plot * to be left clear (e.g. as a background for some text). To * achieve this, the lower and upper clipping bounds supplied to c astClip should be reversed, and the ClipOp attribute of the f AST_CLIP should be reversed, and the ClipOp attribute of the * Plot should be set to a non-zero value. * Applicability: * Plot * All Plots have this attribute. *att-- */ /* If non-zero only 1axis need be within the clipping bounds to avoid a point being clipped. Otherwise, all axes must be within bounds. */ astMAKE_CLEAR(Plot,ClipOp,clipop,-1) astMAKE_GET(Plot,ClipOp,int,0,(this->clipop == -1 ? 0 : this->clipop)) astMAKE_SET(Plot,ClipOp,int,clipop,( value ? 1 : 0 )) astMAKE_TEST(Plot,ClipOp,( this->clipop != -1 )) /* Grf. */ /* ---- */ /* *att++ * Name: * Grf * Purpose: c Use Grf functions registered through astGrfSet? f Use Grf routines registered through AST_GRFSET? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: c This attribute selects the functions which are used to draw graphics by c the Plot class. If it is zero, then the functions in the graphics c interface selected at link-time are used (see the ast_link script). c Otherwise, functions registered using astGrfSet are used. In this c case, if a function is needed which has not been registered, c then the function in the graphics interface selected at link-time is c used. f This attribute selects the routines which are used to draw graphics by f the Plot class. If it is zero, then the routines in the graphics f interface selected at link-time are used (see the ast_link script). f Otherwise, routines registered using AST_GRFSET are used. In this f case, if a routine is needed which has not been registered, f then the routine in the graphics interface selected at link-time is f used. * The default is to use the graphics interface * Applicability: * Plot * All Plots have this attribute. * Plot3D * The Plot3D class ignores this attributes, assuming a value of * zero. * Notes: * - The value of this attribute is not saved when the Plot is written * out through a Channel to an external data store. On re-loading such c a Plot using astRead, the attribute will be cleared, resulting in the f a Plot using AST_READ, the attribute will be cleared, resulting in the * graphics interface selected at link-time being used. *att-- */ /* Use Grf routines registered using astGrfSet? Has a value of -1 when not set yielding a default of 0. */ astMAKE_CLEAR(Plot,Grf,grf,-1) astMAKE_GET(Plot,Grf,int,0,(this->grf == -1 ? 0 : this->grf)) astMAKE_SET(Plot,Grf,int,grf,( value ? 1 : 0 )) astMAKE_TEST(Plot,Grf,( this->grf != -1 )) /* DrawTitle */ /* --------- */ /* *att++ * Name: * DrawTitle * Purpose: * Draw a title for a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether a title is drawn. * * If the DrawTitle value of a Plot is non-zero (the default), then * the title will be drawn, otherwise it will be omitted. * Applicability: * Plot * All Plots have this attribute. * Plot3D * The Plot3D class ignores this attributes, assuming a value of * zero. * Notes: * - The text used for the title is obtained from the Plot's Title * attribute. * - The vertical placement of the title can be controlled using * the TitleGap attribute. *att-- */ /* If non-zero add a title to the grid. Has a value of -1 when not set yielding a default value of 1. */ astMAKE_CLEAR(Plot,DrawTitle,drawtitle,-1) astMAKE_GET(Plot,DrawTitle,int,1,(this->drawtitle == -1 ? 1 : this->drawtitle)) astMAKE_SET(Plot,DrawTitle,int,drawtitle,( value ? 1 : 0 )) astMAKE_TEST(Plot,DrawTitle,( this->drawtitle != -1 )) /* LabelUp. */ /* ------- */ /* *att++ * Name: * LabelUp(axis) * Purpose: * Draw numerical Plot labels upright? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether the numerical labels for each axis of a Plot should be * drawn upright or not. It takes a separate value for each * physical axis of a Plot so that, for instance, the setting * "LabelUp(2)=1" specifies that numerical labels for the second * axis should be drawn upright. * * If the LabelUp value of a Plot axis is non-zero, it causes * numerical labels for that axis to be plotted upright (i.e. as * normal, horizontal text), otherwise labels are drawn parallel to * the axis to which they apply. * * The default is to produce upright labels if the labels are placed * around the edge of the plot, and to produce labels that follow the * axes if the labels are placed within the interior of the plot (see * attribute Labelling). * Applicability: * Plot * All Plots have this attribute. * Notes: * - In some circumstances, numerical labels and tick marks are * drawn around the edges of the plotting area (see the Labelling * attribute). In this case, the value of the LabelUp attribute is * ignored. * - If no axis is specified, (e.g. "LabelUp" instead of * "LabelUp(2)"), then a "set" or "clear" operation will affect the * attribute value of all the Plot axes, while a "get" or "test" * operation will use just the LabelUp(1) value. *att-- */ /* Are numerical labels to be displayed on each axis? Has a value of -1 when not set yielding a value of 0 (no) for both axes. */ MAKE_CLEAR(LabelUp,labelup,-1,0) MAKE_GET(LabelUp,int,0,( this->labelup[axis] == -1 ? 0 : this->labelup[axis] ),0) MAKE_TEST(LabelUp,( this->labelup[axis] != -1 ),0) MAKE_SET(LabelUp,int,labelup,( value ? 1 : 0 ),0) /* DrawAxes */ /* -------- */ /* *att++ * Name: * DrawAxes(axis) * Purpose: * Draw axes for a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether curves representing coordinate axes should be drawn. * It takes a separate value for each physical axis of a * Plot so that, for instance, the setting "DrawAxes(2)=0" * specifies that no axis should be drawn for the second axis. * * If drawn, these axis lines will pass through any tick marks * associated with numerical labels drawn to mark values on the * axes. The location of these tick marks and labels (and hence the * axis lines) is determined by the Plot's LabelAt(axis) attribute. * * If the DrawAxes value of a Plot is non-zero (the default), then * axis lines will be drawn, otherwise they will be omitted. * Applicability: * Plot * All Plots have this attribute. * Notes: * - Axis lines are drawn independently of any coordinate grid * lines (see the Grid attribute) so grid lines may be used to * substitute for axis lines if required. * - In some circumstances, numerical labels and tick marks are * drawn around the edges of the plotting area (see the Labelling * attribute). In this case, the value of the DrawAxes attribute * is ignored. * - If no axis is specified, (e.g. "DrawAxes" instead of * "DrawAxes(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the DrawAxes(1) value. *att-- */ /* If non-zero draw a curve through the tick marks. Has a value of -1 when not set yielding a default value of 1. */ MAKE_CLEAR(DrawAxes,drawaxes,-1,0) MAKE_GET(DrawAxes,int,1,( this->drawaxes[axis] == -1 ? 1 : this->drawaxes[axis] ),0) MAKE_TEST(DrawAxes,( this->drawaxes[axis] != -1 ),0) MAKE_SET(DrawAxes,int,drawaxes,( value ? 1 : 0 ),0) /* Abbrev */ /* -------- */ /* *att++ * Name: * Abbrev(axis) * Purpose: * Abbreviate leading fields within numerical axis labels? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether matching leading fields should be removed from adjacent * numerical axis labels. It takes a separate value for each physical * axis of a Plot so that, for instance, the setting "Abbrev(2)=0" * specifies that matching leading fields should not be removed on * the second axis. * * If the Abbrev value of a Plot is non-zero (the default), then * leading fields will be removed from adjacent axis labels if they * are equal. * Applicability: * Plot * All Plots have this attribute. * Notes: * - If no axis is specified, (e.g. "Abbrev" instead of * "Abbrev(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the Abbrev(1) value. *att-- */ MAKE_CLEAR(Abbrev,abbrev,-1,0) MAKE_GET(Abbrev,int,1,( this->abbrev[axis] == -1 ? 1 : this->abbrev[axis] ),0) MAKE_TEST(Abbrev,( this->abbrev[axis] != -1 ),0) MAKE_SET(Abbrev,int,abbrev,( value ? 1 : 0 ),0) /* Escape. */ /* ------- */ /* *att++ * Name: * Escape * Purpose: * Allow changes of character attributes within strings? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of text strings and numerical c labels drawn by the astGrid and (for the Plot class) astText functions, f labels drawn by the AST_GRID and (for the Plot class) AST_TEXT routines, * by determining if any escape sequences contained within the strings * should be used to control the appearance of the text, or should * be printed literally. Note, the Plot3D class only interprets escape * sequences within the c astGrid function. f AST_GRID routine. * * If the Escape value of a Plot is one (the default), then any * escape sequences in text strings produce the effects described * below when printed. Otherwise, they are printed literally. * c See also the astEscapes function. f See also the AST_ESCAPES function. * Escape Sequences: * Escape sequences are introduced into the text string by a percent * "%" character. Any unrecognised, illegal or incomplete escape sequences * are printed literally. The following escape sequences are * currently recognised ("..." represents a string of one or more * decimal digits): * * %% - Print a literal "%" character. * * %^...+ - 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. * %^+ - 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. * * %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. * * %<...+ - 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. * * %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; * * %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; * * %w+ - Reset the Size attribute to its "normal" value. * * %f...+ - Change the Font attribute for subsequent characters. The * digits "..." give the new Font value. * * %f+ - Reset the Font attribute to its "normal" value. * * %c...+ - Change the Colour attribute for subsequent characters. The * digits "..." give the new Colour value. * * %c+ - Reset the Colour attribute to its "normal" value. * * %t...+ - Change the Style attribute for subsequent characters. The * digits "..." give the new Style value. * * %t+ - Reset the Style attribute to its "normal" value. * * %h+ - Remember the current horizontal position (see "%g+") * * %g+ - Go to the horizontal position of the previous "%h+" (if any). * * %- - Push the current graphics attribute values onto the top of * the stack (see "%+"). * * %+ - Pop attributes values of the top the stack (see "%-"). If * the stack is empty, "normal" attribute values are restored. * Applicability: * Plot * All Plots have this attribute. *att-- */ /* Has a value of -1 when not set yeilding a default of 1. */ astMAKE_GET(Plot,Escape,int,1,(this->escape == -1 ? 1 : this->escape)) astMAKE_CLEAR(Plot,Escape,escape,-1) astMAKE_SET(Plot,Escape,int,escape,( value ? 1 : 0 )) astMAKE_TEST(Plot,Escape,( this->escape != -1 )) /* LabelAt(axis). */ /* -------------- */ /* *att++ * Name: * LabelAt(axis) * Purpose: * Where to place numerical labels for a Plot * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * where numerical axis labels and associated tick marks are * placed. It takes a separate value for each physical axis of a * Plot so that, for instance, the setting "LabelAt(2)=10.0" * specifies where the numerical labels and tick marks for the * second axis should be drawn. * * For each axis, the LabelAt value gives the value on the other * axis at which numerical labels and tick marks should be placed c (remember that Plots suitable for use with astGrid may only f (remember that Plots suitable for use with AST_GRID may only * have two axes). For example, in a celestial (RA,Dec) coordinate * system, LabelAt(1) gives a Dec value which defines a line (of * constant Dec) along which the numerical RA labels and their * associated tick marks will be drawn. Similarly, LabelAt(2) gives * the RA value at which the Dec labels and ticks will be drawn. * * The default bahaviour is for the Plot to generate its own * position for numerical labels and tick marks. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The LabelAt value should use the same units as are used * internally for storing coordinate values on the appropriate * axis. For example, with a celestial coordinate system, the * LabelAt value should be in radians, not hours or degrees. * - Normally, the LabelAt value also determines where the lines * representing coordinate axes will be drawn, so that the tick * marks will lie on these lines (but also see the DrawAxes * attribute). * - In some circumstances, numerical labels and tick marks are * drawn around the edges of the plotting area (see the Labelling * attribute). In this case, the value of the LabelAt attribute is * ignored. *att-- */ /* The constant value on the other axis at which to place labels for each axis. */ MAKE_CLEAR(LabelAt,labelat,AST__BAD,0) MAKE_GET(LabelAt,double,AST__BAD,this->labelat[axis],0) MAKE_SET(LabelAt,double,labelat,value,0) MAKE_TEST(LabelAt,( this->labelat[axis] != AST__BAD ),0) MAKE_GET3(LabelAt,double,AST__BAD,this->ulblat[axis],0) MAKE_SET3(LabelAt,double,ulblat,value,0) /* Centre(axis). */ /* ------------ */ /* A value at which to place a tick mark. Other ticks marks are spaced at regular distances from this one. AST__BAD is stored if no value is supplied, resulting in Plot choosing its own value. */ MAKE_CLEAR(Centre,centre,AST__BAD,0) MAKE_GET(Centre,double,AST__BAD,this->centre[axis],0) MAKE_SET(Centre,double,centre,value,0) MAKE_TEST(Centre,( this->centre[axis] != AST__BAD ),0) MAKE_GET3(Centre,double,AST__BAD,this->ucentre[axis],0) MAKE_SET3(Centre,double,ucentre,value,0) /* Ink */ /* --- */ /* A protected attribute indicating if astGrid should draw using visible ink. The unset value is -1, yeilding a default value of 1. */ astMAKE_CLEAR(Plot,Ink,ink,-1) astMAKE_GET(Plot,Ink,int,1,(this->ink == -1 ? 1 : this->ink)) astMAKE_SET(Plot,Ink,int,ink,( value ? 1 : 0 )) astMAKE_TEST(Plot,Ink,( this->ink != -1 )) /* Gap(axis). */ /* ---------- */ /* *att++ * Name: * Gap(axis) * Purpose: * Interval between linearly spaced major axis values of a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the linear interval between the "major" axis values of a Plot, at * which (for example) major tick marks are drawn. It takes a separate * value for each physical axis of the Plot so that, for instance, * the setting "Gap(2)=3.0" specifies the difference between adjacent major * values along the second axis. The Gap attribute is only used when * the LogTicks attribute indicates that the spacing between major axis * values is to be linear. If major axis values are logarithmically spaced * then the gap is specified using attribute LogGap. * * The Gap value supplied will usually be rounded to the nearest * "nice" value, suitable (e.g.) for generating axis labels, before * use. To avoid this "nicing" you should set an explicit format * for the axis using the Format(axis) or Digits/Digits(axis) * attribute. The default behaviour is for the Plot to generate its * own Gap value when required, based on the range of axis values * to be represented. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The Gap value should use the same units as are used internally * for storing coordinate values on the corresponding axis. For * example, with a celestial coordinate system, the Gap value * should be in radians, not hours or degrees. * - If no axis is specified, (e.g. "Gap" instead of "Gap(2)"), * then a "set" or "clear" operation will affect the attribute * value of all the Plot axes, while a "get" or "test" operation * will use just the Gap(1) value. *att-- */ /* The gap between tick marks on each axis. AST__BAD is stored if no value has been supplied, resulting in default values being found. */ MAKE_CLEAR(Gap,gap,AST__BAD,0) MAKE_SET(Gap,double,gap,value,0) MAKE_TEST(Gap,( this->gap[axis] != AST__BAD ),0) MAKE_GET(Gap,double,AST__BAD,this->gap[axis],0) MAKE_SET3(Gap,double,ugap,value,0) MAKE_GET3(Gap,double,AST__BAD,this->ugap[axis],0) /* LogGap(axis). */ /* ---------- */ /* *att++ * Name: * LogGap(axis) * Purpose: * Interval between major axis values of a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the logarithmic interval between the "major" axis values of a Plot, at * which (for example) major tick marks are drawn. It takes a separate * value for each physical axis of the Plot so that, for instance, * the setting "LogGap(2)=100.0" specifies the ratio between adjacent major * values along the second axis. The LogGap attribute is only used when * the LogTicks attribute indicates that the spacing between major axis * values is to be logarithmic. If major axis values are linearly spaced * then the gap is specified using attribute Gap. * * The LogGap value supplied will be rounded to the nearest power of 10. * The reciprocal of the supplied value may be used if this is necessary * to produce usable major axis values. If a zero or negative value is * supplied, an error will be reported when the grid is drawn. The default * behaviour is for the Plot to generate its own LogGap value when * required, based on the range of axis values to be represented. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The LogGap value is a ratio between axis values and is therefore * dimensionless. * - If no axis is specified, (e.g. "LogGap" instead of "LogGap(2)"), * then a "set" or "clear" operation will affect the attribute * value of all the Plot axes, while a "get" or "test" operation * will use just the LogGap(1) value. *att-- */ /* The logarithmic gap between tick marks on each axis. AST__BAD is stored if no value has been supplied, resulting in default values being found. */ MAKE_CLEAR(LogGap,loggap,AST__BAD,0) MAKE_SET(LogGap,double,loggap,value,0) MAKE_TEST(LogGap,( this->loggap[axis] != AST__BAD ),0) MAKE_GET(LogGap,double,AST__BAD,this->loggap[axis],0) MAKE_SET3(LogGap,double,uloggap,value,0) MAKE_GET3(LogGap,double,AST__BAD,this->uloggap[axis],0) /* LogPlot. */ /* ------- */ /* *att++ * Name: * LogPlot(axis) * Purpose: * Map the plot logarithmically onto the screen? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of all graphics produced by * the Plot, by determining whether the axes of the plotting surface * are mapped logarithmically or linearly onto the base Frame of the * FrameSet supplied when the Plot was constructed. It takes a separate * value for each axis of the graphics coordinate system (i.e. the * base Frame in the Plot) so that, for instance, the setting * "LogPlot(2)=1" specifies that the second axis of the graphics * coordinate system (usually the vertical axis) should be mapped * logarithmically onto the second axis of the base Frame of the * FrameSet supplied when the Plot was constructed. * * If the LogPlot value of a Plot axis is non-zero, it causes that * axis to be mapped logarithmically, otherwise (the default) the axis * is mapped linearly. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The setting of the LogPlot attribute provides the default value * for the related LogTicks attribute. By selecting suitable values for * LogPlot and LogTicks, it is possible to have tick marks which are evenly * spaced in value but which are mapped logarithmically onto the screen * (and vice-versa). * - An axis may only be mapped logarithmically if the visible part of * the axis does not include the value zero. The visible part of the * axis is that part which is mapped onto the plotting area, and is * measured within the base Frame of the FrameSet which was supplied when * the Plot was constructed. Any attempt to set LogPlot to a non-zero value * will be ignored (without error) if the visible part of the axis * includes the value zero * - If no axis is specified, (e.g. "LogPlot" instead of * "LogPlot(2)"), then a "set" or "clear" operation will affect the * attribute value of all the Plot axes, while a "get" or "test" * operation will use just the LogPlot(1) value. *att-- */ /* Are plot axes to be mapped logarithmically? Has a value of -1 when not set yielding a value of 0 (no) for both axes. */ MAKE_GET(LogPlot,int,0,( this->logplot[axis] == -1 ? 0 : this->logplot[axis] ),0) MAKE_TEST(LogPlot,( this->logplot[axis] != -1 ),0) /* LogTicks. */ /* ------- */ /* *att++ * Name: * LogTicks(axis) * Purpose: * Space the major tick marks logarithmically? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether the major tick marks should be spaced logarithmically or * linearly in axis value. It takes a separate value for each physical * axis of the Plot so that, for instance, the setting "LogTicks(2)=1" * specifies that the major tick marks on the second axis should be * spaced logarithmically. * * If the LogTicks value for a physical axis is non-zero, the major * tick marks on that axis will be spaced logarithmically (that is, * there will be a constant ratio between the axis values at adjacent * major tick marks). An error will be reported if the dynamic range of * the axis (the ratio of the largest to smallest displayed axis value) * is less than 10.0. If the LogTicks value is zero, the major tick marks * will be evenly spaced (that is, there will be a constant difference * between the axis values at adjacent major tick marks). The default is * to produce logarithmically spaced tick marks if the corresponding * LogPlot attribute is non-zero and the ratio of maximum axis value * to minimum axis value is 100 or more. If either of these conditions * is not met, the default is to produce linearly spaced tick marks. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The setting of the LogTicks attribute does not affect the mapping * of the plot onto the screen, which is controlled by attribute LogPlot. * By selecting suitable values for LogPlot and LogTicks, it is possible to * have tick marks which are evenly spaced in value but which are mapped * logarithmically onto the screen (and vica-versa). * - An error will be reported when drawing an annotated axis grid if * the visible part of the physical axis includes the value zero. * - If no axis is specified, (e.g. "LogTicks" instead of * "LogTicks(2)"), then a "set" or "clear" operation will affect the * attribute value of all the Plot axes, while a "get" or "test" * operation will use just the LogTicks(1) value. *att-- */ /* Are ticksto be spaced logarithmically? Has a value of -1 when not set, yeielding a default value equal to the corresponding LogPlot value. */ MAKE_CLEAR(LogTicks,logticks,-1,0) MAKE_GET(LogTicks,int,0,( this->logticks[axis] == -1 ? astGetLogPlot(this,axis) : this->logticks[axis] ),0) MAKE_TEST(LogTicks,( this->logticks[axis] != -1 ),0) MAKE_SET(LogTicks,int,logticks,( value ? 1 : 0 ),0) MAKE_SET3(LogTicks,int,ulgtk,value,0) MAKE_GET3(LogTicks,int,0,this->ulgtk[axis],0) /* LogLabel. */ /* -------- */ /* *att++ * Name: * LogLabel(axis) * Purpose: * Use exponential format for numerical axis labels? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether the numerical axis labels should be in normal decimal form * or should be represented as 10 raised to the appropriate power. * That is, an axis value of 1000.0 will be drawn as "1000.0" if * LogLabel is zero, but as "10^3" if LogLabel is non-zero. If * graphical escape sequences are supported (see attribute Escape), * the power in such exponential labels will be drawn as a small * superscript instead of using a "^" character to represent * exponentiation. * * The default is to produce exponential labels if the major tick * marks are logarithmically spaced (see the LogTicks attribute). * Applicability: * Plot * All Plots have this attribute. * Notes: * - If no axis is specified, (e.g. "LogLabel" instead of * "LogLabel(2)"), then a "set" or "clear" operation will affect the * attribute value of all the Plot axes, while a "get" or "test" * operation will use just the LogLabel(1) value. *att-- */ /* Are labels to be drawn as 10**x? Has a value of -1 when not set, yeielding a default value equal to the corresponding LogTicks value. */ MAKE_CLEAR(LogLabel,loglabel,-1,0) MAKE_GET(LogLabel,int,0,( this->loglabel[axis] == -1 ? astGetLogTicks(this,axis) : this->loglabel[axis] ),0) MAKE_TEST(LogLabel,( this->loglabel[axis] != -1 ),0) MAKE_SET(LogLabel,int,loglabel,( value ? 1 : 0 ),0) MAKE_SET3(LogLabel,int,ulglb,value,0) MAKE_GET3(LogLabel,int,0,this->ulglb[axis],0) /* MajTickLen. */ /* ----------- */ /* *att++ * Name: * MajTickLen(axis) * Purpose: * Length of major tick marks for a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the length of the major tick marks drawn on the axes of a Plot. * It takes a separate value for each physical axis of the Plot so * that, for instance, the setting "MajTickLen(2)=0" specifies the * length of the major tick marks drawn on the second axis. * * The MajTickLen value should be given as a fraction of the * minimum dimension of the plotting area. Negative values cause * major tick marks to be placed on the outside of the * corresponding grid line or axis (but subject to any clipping * imposed by the underlying graphics system), while positive * values cause them to be placed on the inside. * * The default behaviour depends on whether a coordinate grid is * drawn inside the plotting area (see the Grid attribute). If so, * the default MajTickLen value is zero (so that major ticks are * not drawn), otherwise the default is +0.015. * Applicability: * Plot * All Plots have this attribute. * Notes: * - If no axis is specified, (e.g. "MajTickLen" instead of * "MajTickLen(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or "test" * operation will use just the MajTickLen(1) value. *att-- */ /* Fractional length of major tick marks. Has a value of AST__BAD when not set yielding a default value of 0.015. */ MAKE_CLEAR(MajTickLen,majticklen,AST__BAD,0) MAKE_SET(MajTickLen,double,majticklen,value,0) MAKE_TEST(MajTickLen,( this->majticklen[axis] != AST__BAD ),0) MAKE_GET(MajTickLen,double,0.0,( this->majticklen[axis] == AST__BAD ? 0.015 : this->majticklen[axis]),0) MAKE_SET3(MajTickLen,double,umjtkln,value,0) MAKE_GET3(MajTickLen,double,0.0,this->umjtkln[axis],0) /* TitleGap. */ /* --------- */ /* *att++ * Name: * TitleGap * Purpose: * Vertical spacing for a Plot title. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * where the title of a Plot is drawn. * * Its value gives the spacing between the bottom edge of the title * and the top edge of a bounding box containing all the other parts * of the annotated grid. Positive values cause the title to be * drawn outside the box, while negative values cause it to be drawn * inside. * * The TitleGap value should be given as a fraction of the minimum * dimension of the plotting area, the default value being +0.05. * Applicability: * Plot * All Plots have this attribute. * Plot3D * The Plot3D class ignores this attributes since it does not draw * a Title. * Notes: * - The text used for the title is obtained from the Plot's Title * attribute. *att-- */ /* Fractional gap between titile and top edge. Has a value of AST__BAD when not set yielding a default value of 0.05. */ astMAKE_CLEAR(Plot,TitleGap,titlegap,AST__BAD) astMAKE_GET(Plot,TitleGap,double,0.0,( this->titlegap == AST__BAD ? 0.05 : this->titlegap)) astMAKE_SET(Plot,TitleGap,double,titlegap,value) astMAKE_TEST(Plot,TitleGap,( this->titlegap != AST__BAD )) /* MinTickLen. */ /* ----------- */ /* *att++ * Name: * MinTickLen(axis) * Purpose: * Length of minor tick marks for a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the length of the minor tick marks drawn on the axes of a Plot. * It takes a separate value for each physical axis of the Plot so * that, for instance, the setting "MinTickLen(2)=0" specifies the * length of the minor tick marks drawn on the second axis. * * The MinTickLen value should be given as a fraction of the * minimum dimension of the plotting area. Negative values cause * minor tick marks to be placed on the outside of the * corresponding grid line or axis (but subject to any clipping * imposed by the underlying graphics system), while positive * values cause them to be placed on the inside. * * The default value is +0.007. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The number of minor tick marks drawn is determined by the * Plot's MinTick(axis) attribute. * - If no axis is specified, (e.g. "MinTickLen" instead of * "MinTickLen(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or "test" * operation will use just the MinTickLen(1) value. *att-- */ /* Fractional length of minor tick marks. Has a value of AST__BAD when not set yielding a default value of 0.007. */ MAKE_CLEAR(MinTickLen,minticklen,AST__BAD,0) MAKE_SET(MinTickLen,double,minticklen,value,0) MAKE_TEST(MinTickLen,( this->minticklen[axis] != AST__BAD ),0) MAKE_GET(MinTickLen,double,0.0,( this->minticklen[axis] == AST__BAD ? 0.007 : this->minticklen[axis]),0) /* Labelling. */ /* ---------- */ /* *att++ * Name: * Labelling * Purpose: * Label and tick placement option for a Plot. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the strategy for placing numerical labels and tick marks for a Plot. * * If the Labelling value of a Plot is "exterior" (the default), then * numerical labels and their associated tick marks are placed * around the edges of the plotting area, if possible. If this is * not possible, or if the Labelling value is "interior", then they * are placed along grid lines inside the plotting area. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The LabelAt(axis) attribute may be used to determine the exact * placement of labels and tick marks that are drawn inside the * plotting area. *att-- */ astMAKE_CLEAR(Plot,Labelling,labelling,-9999) astMAKE_SET(Plot,Labelling,int,labelling,(value?1:0)) astMAKE_TEST(Plot,Labelling,( this->labelling != -9999 )) astMAKE_GET(Plot,Labelling,int,0,(this->labelling == -9999 ? 0 : this->labelling)) MAKE_SET2(Plot,Labelling,int,ulbling,(value?1:0)) MAKE_GET2(Plot,Labelling,int,0,this->ulbling) /* Edge. */ /* ----- */ /* *att++ * Name: * Edge(axis) * Purpose: * Which edges to label in a Plot * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * which edges of a Plot are used for displaying numerical and * descriptive axis labels. It takes a separate value for each * physical axis of the Plot so that, for instance, the setting * "Edge(2)=left" specifies which edge to use to display labels for * the second axis. * * The values "left", "top", "right" and "bottom" (or any * abbreviation) can be supplied for this attribute. The default is * usually "bottom" for the first axis and "left" for the second * axis. However, if exterior labelling was requested (see the * Labelling attribute) but cannot be produced using these default * Edge values, then the default values will be swapped if this * enables exterior labelling to be produced. * Applicability: * Plot * All Plots have this attribute. * Plot3D * The Plot3D class ignores this attributes. Instead it uses its * own RootCorner attribute to determine which edges of the 3D plot * to label. * Notes: * - In some circumstances, numerical labels will be drawn along * internal grid lines instead of at the edges of the plotting area * (see the Labelling attribute). In this case, the Edge attribute * only affects the placement of the descriptive labels (these are * drawn at the edges of the plotting area, rather than along the * axis lines). *att-- */ /* The edges of the plotting area on which to place numerical labels for axes 0 and 1. Has a value of -1 when not set yielding a value of 3 (the bottom edge) for axis 0 and 0 (the left-hand edge) for axis 1. */ MAKE_CLEAR(Edge,edge,-1,0) MAKE_GET(Edge,int,0,( this->edge[axis] == -1 ? (axis?LEFT:BOTTOM) : this->edge[axis] ),0) MAKE_SET(Edge,int,edge,(abs( value % 4 )),0) MAKE_TEST(Edge,( this->edge[axis] != -1 ),0) MAKE_GET3(Edge,int,0,this->uedge[axis],0) MAKE_SET3(Edge,int,uedge,(abs( value % 4 )),0) /* NumLab. */ /* -------- */ /* *att++ * Name: * NumLab(axis) * Purpose: * Draw numerical axis labels for a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether labels should be drawn to represent the numerical values * along each axis of a Plot. It takes a separate value for each * physical axis of a Plot so that, for instance, the setting * "NumLab(2)=1" specifies that numerical labels should be drawn * for the second axis. * * If the NumLab value of a Plot axis is non-zero (the default), * then numerical labels will be drawn for that axis, otherwise * they will be omitted. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The drawing of associated descriptive axis labels for a Plot * (describing the quantity being plotted along each axis) is * controlled by the TextLab(axis) attribute. * - If no axis is specified, (e.g. "NumLab" instead of * "NumLab(2)"), then a "set" or "clear" operation will affect the * attribute value of all the Plot axes, while a "get" or "test" * operation will use just the NumLab(1) value. *att-- */ /* Are numerical labels to be displayed on each axis? Has a value of -1 when not set yielding a value of 1 (yes) for both axes. */ MAKE_CLEAR(NumLab,numlab,-1,0) MAKE_GET(NumLab,int,1,( this->numlab[axis] == -1 ? 1 : this->numlab[axis] ),0) MAKE_TEST(NumLab,( this->numlab[axis] != -1 ),0) MAKE_SET(NumLab,int,numlab,( value ? 1 : 0 ),0) /* NumLabGap. */ /* --------- */ /* *att++ * Name: * NumLabGap(axis) * Purpose: * Spacing of numerical labels for a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * where numerical axis labels are placed relative to the axes they * describe. It takes a separate value for each physical axis of a * Plot so that, for instance, the setting "NumLabGap(2)=-0.01" * specifies where the numerical label for the second axis should * be drawn. * * For each axis, the NumLabGap value gives the spacing between the * axis line (or edge of the plotting area, if appropriate) and the * nearest edge of the corresponding numerical axis * labels. Positive values cause the descriptive label to be placed * on the opposite side of the line to the default tick marks, * while negative values cause it to be placed on the same side. * * The NumLabGap value should be given as a fraction of the minimum * dimension of the plotting area, the default value being +0.01. * Applicability: * Plot * All Plots have this attribute. * Notes: * - If no axis is specified, (e.g. "NumLabGap" instead of * "NumLabGap(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the NumLabGap(1) value. *att-- */ /* Fractional spacing between numeric labels and axes. Has a value of AST__BAD when not set yielding a default value of 0.01. */ MAKE_CLEAR(NumLabGap,numlabgap,AST__BAD,0) MAKE_GET(NumLabGap,double,0.0,( this->numlabgap[ axis ] == AST__BAD ? 0.01 : this->numlabgap[axis]),0) MAKE_SET(NumLabGap,double,numlabgap,value,0) MAKE_TEST(NumLabGap,( this->numlabgap[axis] != AST__BAD ),0) /* MinTick. */ /* -------- */ /* *att++ * Name: * MinTick(axis) * Purpose: * Density of minor tick marks for a Plot. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * the density of minor tick marks which appear between the major * axis values of a Plot. It takes a separate value for each * physical axis of a Plot so that, for instance, the setting * "MinTick(2)=2" specifies the density of minor tick marks along * the second axis. * * The value supplied should be the number of minor divisions * required between each pair of major axis values, this being one * more than the number of minor tick marks to be drawn. By * default, a value is chosen that depends on the gap between major * axis values and the nature of the axis. * Applicability: * Plot * All Plots have this attribute. * Notes: * - If no axis is specified, (e.g. "MinTick" instead of * "MinTick(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the MinTick(1) value. *att-- */ /* How many divisions are there between major tick marks? Has a value of -1 when not set yielding a value of 1 for both axes. */ MAKE_CLEAR(MinTick,mintick,-1,0) MAKE_GET(MinTick,int,1,( this->mintick[axis] == -1 ? 1 : this->mintick[axis] ),0) MAKE_TEST(MinTick,( this->mintick[axis] != -1 ),0) MAKE_SET(MinTick,int,mintick,( (value < 1)? 1 : value ),0) MAKE_GET3(MinTick,int,1,this->umintk[axis],0) MAKE_SET3(MinTick,int,umintk,( (value < 1)? 1 : value ),0) /* TextLab. */ /* --------- */ /* *att++ * Name: * TextLab(axis) * Purpose: * Draw descriptive axis labels for a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether textual labels should be drawn to describe the quantity * being represented on each axis of a Plot. It takes a separate * value for each physical axis of a Plot so that, for instance, * the setting "TextLab(2)=1" specifies that descriptive labels * should be drawn for the second axis. * * If the TextLab value of a Plot axis is non-zero, then * descriptive labels will be drawn for that axis, otherwise they * will be omitted. The default behaviour is to draw descriptive * labels if tick marks and numerical labels are being drawn around * the edges of the plotting area (see the Labelling attribute), * but to omit them otherwise. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The text used for the descriptive labels is derived from the * Plot's Label(axis) attribute, together with its Unit(axis) * attribute if appropriate (see the LabelUnits(axis) attribute). * - The drawing of numerical axis labels for a Plot (which * indicate values on the axis) is controlled by the NumLab(axis) * attribute. * - If no axis is specified, (e.g. "TextLab" instead of * "TextLab(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the TextLab(1) value. *att-- */ /* Are textual labels to be displayed on each axis? Has a value of -1 when not set yielding a value of 1 (yes) for both axes. */ MAKE_CLEAR(TextLab,textlab,-1,0) MAKE_GET(TextLab,int,1,( this->textlab[axis] == -1 ? 1 : this->textlab[axis] ),0) MAKE_TEST(TextLab,( this->textlab[axis] != -1 ),0) MAKE_SET(TextLab,int,textlab,( value ? 1 : 0 ),0) MAKE_GET3(TextLab,int,1,this->utxtlb[axis],0) MAKE_SET3(TextLab,int,utxtlb,( value ? 1 : 0 ),0) /* TextLabGap. */ /* ----------- */ /* *att++ * Name: * TextLabGap(axis) * Purpose: * Spacing of descriptive axis labels for a Plot. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * where descriptive axis labels are placed relative to the axes they * describe. It takes a separate value for each physical axis of a * Plot so that, for instance, the setting "TextLabGap(2)=0.01" * specifies where the descriptive label for the second axis should * be drawn. * * For each axis, the TextLabGap value gives the spacing between the * descriptive label and the edge of a box enclosing all other parts * of the annotated grid (excluding other descriptive labels). The gap * is measured to the nearest edge of the label (i.e. the top or the * bottom). Positive values cause the descriptive label to be placed * outside the bounding box, while negative values cause it to be placed * inside. * * The TextLabGap value should be given as a fraction of the minimum * dimension of the plotting area, the default value being +0.01. * Applicability: * Plot * All Plots have this attribute. * Notes: * - If drawn, descriptive labels are always placed at the edges of * the plotting area, even although the corresponding numerical * labels may be drawn along axis lines in the interior of the * plotting area (see the Labelling attribute). * - If no axis is specified, (e.g. "TextLabGap" instead of * "TextLabGap(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the TextLabGap(1) value. *att-- */ /* Fractional spacing between numeric labels and axes. Has a value of AST__BAD when not set yielding a default value of 0.01. */ MAKE_CLEAR(TextLabGap,textlabgap,AST__BAD,0) MAKE_GET(TextLabGap,double,0.0,( this->textlabgap[ axis ] == AST__BAD ? 0.01 : this->textlabgap[axis]),0) MAKE_SET(TextLabGap,double,textlabgap,value,0) MAKE_TEST(TextLabGap,( this->textlabgap[axis] != AST__BAD ),0) /* LabelUnits. */ /* ----------- */ /* *att++ * Name: * LabelUnits(axis) * Purpose: * Use axis unit descriptions in a Plot? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls the appearance of an annotated c coordinate grid (drawn with the astGrid function) by determining f coordinate grid (drawn with the AST_GRID routine) by determining * whether the descriptive labels drawn for each axis of a Plot * should include a description of the units being used on the * axis. It takes a separate value for each physical axis of a * Plot so that, for instance, the setting "LabelUnits(2)=1" * specifies that a unit description should be included in the * label for the second axis. * * If the LabelUnits value of a Plot axis is non-zero, a unit * description will be included in the descriptive label for that * axis, otherwise it will be omitted. The default behaviour is to * include a unit description unless the current Frame of the Plot * is a SkyFrame representing equatorial, ecliptic, galactic or * supergalactic coordinates, in which case it is omitted. * Applicability: * Plot * All Plots have this attribute. * Notes: * - The text used for the unit description is obtained from the * Plot's Unit(axis) attribute. * - If no axis is specified, (e.g. "LabelUnits" instead of * "LabelUnits(2)"), then a "set" or "clear" operation will affect * the attribute value of all the Plot axes, while a "get" or * "test" operation will use just the LabelUnits(1) value. * - If the current Frame of the Plot is not a SkyFrame, but includes * axes which were extracted from a SkyFrame, then the default behaviour * is to include a unit description only for those axes which were not * extracted from a SkyFrame. *att-- */ /* Are textual labels to include a string describing the axis units? Has a value of -1 when not set yielding a default of 1. */ MAKE_CLEAR(LabelUnits,labelunits,-1,0) MAKE_TEST(LabelUnits,( this->labelunits[axis] != -1 ),0) MAKE_SET(LabelUnits,int,labelunits,( value ? 1 : 0 ),0) MAKE_GET3(LabelUnits,int,1,this->ulbunit[axis],0) MAKE_SET3(LabelUnits,int,ulbunit,( value ? 1 : 0 ),0) /* Style. */ /* ------ */ /* *att++ * Name: * Style(element) * Purpose: * Line style for a Plot element. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute determines the line style used when drawing each * element of graphical output produced by a Plot. It takes a * separate value for each graphical element so that, for instance, * the setting "Style(border)=2" causes the Plot border to be drawn * using line style 2 (which might result in, say, a dashed line). * * The range of integer line styles available and their appearance * is determined by the underlying graphics system. The default * behaviour is for all graphical elements to be drawn using the * default line style supplied by this graphics system (normally, * this is likely to give a solid line). * Applicability: * Plot * All Plots have this attribute. * Notes: * - For a list of the graphical elements available, see the * description of the Plot class. * - If no graphical element is specified, (e.g. "Style" instead of * "Style(border)"), then a "set" or "clear" operation will affect * the attribute value of all graphical elements, while a "get" or * "test" operation will use just the Style(Border) value. *att-- */ /* Line styles. Has a value of -1 when not set yielding a default of 1. */ MAKE_CLEAR(Style,style,-1,AST__NPID) MAKE_GET(Style,int,1,( this->style[axis] == -1 ? 1 : this->style[axis] ),AST__NPID) MAKE_TEST(Style,( this->style[axis] != -1 ),AST__NPID) MAKE_SET(Style,int,style,value,AST__NPID) /* Font. */ /* ----- */ /* *att++ * Name: * Font(element) * Purpose: * Character font for a Plot element. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute determines the character font index used when * drawing each element of graphical output produced by a Plot. It * takes a separate value for each graphical element so that, for * instance, the setting "Font(title)=2" causes the Plot title to * be drawn using font number 2. * * The range of integer font indices available and the appearance * of the resulting text is determined by the underlying graphics * system. The default behaviour is for all graphical elements to * be drawn using the default font supplied by this graphics * system. * Applicability: * Plot * All Plots have this attribute. * Notes: * - For a list of the graphical elements available, see the * description of the Plot class. * - If no graphical element is specified, (e.g. "Font" instead * of "Font(title)"), then a "set" or "clear" operation will * affect the attribute value of all graphical elements, while a * "get" or "test" operation will use just the Font(TextLab) * value. *att-- */ /* Character fonts. Has a value of -1 when not set yielding a default of 1. */ MAKE_CLEAR(Font,font,-1,AST__NPID) MAKE_GET(Font,int,1,( this->font[axis] == -1 ? 1 : this->font[axis] ),AST__NPID) MAKE_TEST(Font,( this->font[axis] != -1 ),AST__NPID) MAKE_SET(Font,int,font,value,AST__NPID) /* Colour. */ /* ------- */ /* *att++ * Name: * Colour(element) * Purpose: * Colour index for a Plot element. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute determines the colour index used when drawing * each element of graphical output produced by a Plot. It takes a * separate value for each graphical element so that, for instance, * the setting "Colour(title)=2" causes the Plot title to be drawn * using colour index 2. The synonym "Color" may also be used. * * The range of integer colour indices available and their * appearance is determined by the underlying graphics system. The * default behaviour is for all graphical elements to be drawn * using the default colour index supplied by this graphics system * (normally, this is likely to result in white plotting on a black * background, or vice versa). d * Applicability: * Plot * All Plots have this attribute. * Notes: * - For a list of the graphical elements available, see the * description of the Plot class. * - If no graphical element is specified, (e.g. "Colour" instead * of "Colour(title)"), then a "set" or "clear" operation will * affect the attribute value of all graphical elements, while a * "get" or "test" operation will use just the Colour(TextLab) * value. *att-- */ /* Colours. Has a value of -1 when not set yielding a default of 1. */ MAKE_CLEAR(Colour,colour,-1,AST__NPID) MAKE_GET(Colour,int,1,( this->colour[axis] == -1 ? 1 : this->colour[axis] ),AST__NPID) MAKE_TEST(Colour,( this->colour[axis] != -1 ),AST__NPID) MAKE_SET(Colour,int,colour,value,AST__NPID) /* Width. */ /* ------ */ /* *att++ * Name: * Width(element) * Purpose: * Line width for a Plot element. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute determines the line width used when drawing each * element of graphical output produced by a Plot. It takes a * separate value for each graphical element so that, for instance, * the setting "Width(border)=2.0" causes the Plot border to be * drawn using a line width of 2.0. A value of 1.0 results in a * line thickness which is approximately 0.0005 times the length of * the diagonal of the entire display surface. * * The actual appearance of lines drawn with any particular width, * and the range of available widths, is determined by the * underlying graphics system. The default behaviour is for all * graphical elements to be drawn using the default line width * supplied by this graphics system. This will not necessarily * correspond to a Width value of 1.0. * Applicability: * Plot * All Plots have this attribute. * Notes: * - For a list of the graphical elements available, see the * description of the Plot class. * - If no graphical element is specified, (e.g. "Width" instead of * "Width(border)"), then a "set" or "clear" operation will affect * the attribute value of all graphical elements, while a "get" or * "test" operation will use just the Width(Border) value. *att-- */ /* Line widths. Has a value of AST__BAD when not set yielding a default of 1.0. */ MAKE_CLEAR(Width,width,AST__BAD,AST__NPID) MAKE_GET(Width,double,1.0,( this->width[axis] == AST__BAD ? 1.0 : this->width[axis] ),AST__NPID) MAKE_TEST(Width,( this->width[axis] != AST__BAD ),AST__NPID) MAKE_SET(Width,double,width,(value!=0.00)?value:(astError(AST__ATTIN,"astSetWidth(Plot):Invalid zero value supplied for Width(%s) attribute", status,GrfItem(axis,NULL,NULL, status )),this->width[axis]),AST__NPID) /* Size. */ /* ----- */ /* *att++ * Name: * Size(element) * Purpose: * Character size for a Plot element. * Type: * Public attribute. * Synopsis: * Floating Point. * Description: * This attribute determines the character size used when drawing * each element of graphical output produced by a Plot. It takes a * separate value for each graphical element so that, for instance, * the setting "Size(title)=2.0" causes the Plot title to be drawn * using twice the default character size. * * The range of character sizes available and the appearance of the * resulting text is determined by the underlying graphics system. * The default behaviour is for all graphical elements to be drawn * using the default character size supplied by this graphics * system. * Applicability: * Plot * All Plots have this attribute. * Notes: * - For a list of the graphical elements available, see the * description of the Plot class. * - If no graphical element is specified, (e.g. "Size" instead * of "Size(title)"), then a "set" or "clear" operation will * affect the attribute value of all graphical elements, while a * "get" or "test" operation will use just the Size(TextLab) * value. *att-- */ /* Character sizes. Has a value of AST__BAD when not set yielding a default of 1.0. */ MAKE_CLEAR(Size,size,AST__BAD,AST__NPID) MAKE_GET(Size,double,1.0,( this->size[axis] == AST__BAD ? 1.0 : this->size[axis] ),AST__NPID) MAKE_TEST(Size,( this->size[axis] != AST__BAD ),AST__NPID) MAKE_SET(Size,double,size,(value!=0.00)?value:(astError(AST__ATTIN,"astSetSize(Plot): Invalid zero value supplied for Size(%s) attribute", status,GrfItem(axis,NULL,NULL, status )),this->size[axis]),AST__NPID) /* Member functions. */ /* ================= */ static void AddCdt( AstPlotCurveData *cdt1, AstPlotCurveData *cdt2, const char *method, const char *class, int *status ){ /* * * Name: * AddCdt * Purpose: * Append one AstPlotCurveData structure to another. * Type: * Private function. * Synopsis: * #include "plot.h" * void AddCdt( AstPlotCurveData *cdt1, AstPlotCurveData *cdt2, const char *method, * const char *class, int *status ) * Class Membership: * Plot private function. * Description: * The contents of the structure pointed to by "cdt2" is appended * to the structure pointed to by "cdt1". * Parameters: * cdt1 * Pointer to the AstPlotCurveData structure to be modified. * cdt2 * Pointer to the AstPlotCurveData structure to be appended to cdt1. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - An error is reported if there is insufficient room in "cdt1" to * store the information in "cdt2". */ /* Local Variables: */ int nbrk, i, j; /* Check the global error status. */ if ( !astOK ) return; /* Get the total number of breaks described by both structures. */ nbrk = cdt1->nbrk + cdt2->nbrk; /* Report an error if this number of breaks cannot be stored in a AstPlotCurveData structure. */ if( nbrk > AST__MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__MXBRK ); /* Otherwise, append the information. */ } else { /* Store the index within "cdt1" of the next break to be added. */ j = cdt1->nbrk; /* Add each the position and direction information for each of the breaks in "cdt2". */ for( i = 0; i < cdt2->nbrk; i++ ){ cdt1->xbrk[ j ] = cdt2->xbrk[ i ]; cdt1->ybrk[ j ] = cdt2->ybrk[ i ]; cdt1->vxbrk[ j ] = cdt2->vxbrk[ i ]; cdt1->vybrk[ j ] = cdt2->vybrk[ i ]; /* Increment the index of the next break in "cdt1". */ j++; } /* Update the number of breaks in "cdt1". */ cdt1->nbrk = nbrk; /* Update the length of the curve described by "cdt1". */ cdt1->length += cdt2->length; /* Update the flag indicating if the entire curve is outside the plotting zone. */ if( !cdt2->out ) cdt1->out = 0; } /* Return. */ return; } static void Apoly( AstPlot *this, float x, float y, int *status ){ /* * Name: * Apoly * Purpose: * Append a another point to a poly line. * Type: * Private function. * Synopsis: * #include "plot.h" * void Apoly( AstPlot *this, float x, float y, int *status ) * Class Membership: * Plot member function. * Description: * This function appends the supplied point to the current poly line. * Parameters: * x * The graphics x coordinate. * y * The graphics y coordinate. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int ipoint; astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Extend the buffers, and add the supplied point to the end. */ ipoint = Poly_n++; Poly_x = astGrow( Poly_x, Poly_n, sizeof(*Poly_x) ); Poly_y = astGrow( Poly_y, Poly_n, sizeof(*Poly_y) ); if( astOK ) { Poly_x[ ipoint ] = x; Poly_y[ ipoint ] = y; } /* Update the box containing all plotted lines. */ Box_lbnd[ 0 ] = MIN( x, Box_lbnd[ 0 ] ); Box_ubnd[ 0 ] = MAX( x, Box_ubnd[ 0 ] ); Box_lbnd[ 1 ] = MIN( y, Box_lbnd[ 1 ] ); Box_ubnd[ 1 ] = MAX( y, Box_ubnd[ 1 ] ); } static void AxPlot( AstPlot *this, int axis, const double *start, double length, int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ){ /* * * Name: * AxPlot * Purpose: * Draw a curve with constant axis value. * Type: * Private function. * Synopsis: * #include "plot.h" * void AxPlot( AstPlot *this, int axis, const double *start, double length, * int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws a section of a curve of the specified length * with constant value on a specified axis in the current Frame of the * Plot, starting at the specified position. The algorithm used can handle * discontinuities in the Mapping between the current Frame and graphics * coordinates, and information describing any breaks in the curve * (including the start and end of the curve) are returned in the supplied * AstPlotCurveData structure. * Parameters: * this * Pointer to the Plot. * axis * The zero-based index of an axis within the current Frame of the Plot. * The curve has a varying value on this axis. * start * A pointer to a an array holding the coordinates of the start of the * curve within the current Frame of the Plot. * length * The length of the section of the curve to be drawn, given as an * increment along the axis specified by parameter "axis". * ink * If zero, the curve is not actually drawn, but information about * the breaks is still returned. If non-zero, the curve is also drawn. * cdata * A pointer to a structure in which to return information about the * breaks in the curve. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - No curve is draw if the "start" array contains any bad values * (i.e. values equal to AST__BAD), or if the "length" value is bad, * or if a NULL pointer is supplied for "cdata". No errors are reported * in these cases. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ double tol; /* Absolute tolerance value */ int i; /* Loop count */ int naxes; /* No. of axes in the base Frame */ int ok; /* Are all start coords good? */ int gridid; /* Identifier value for element being drawn */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); #ifdef CRV_TRACE printf("AXPLOT: axis %d, start (%.*g,%.*g), length %.*g\n", axis, DBL_DIG, start[0], DBL_DIG, start[1], DBL_DIG, length ); getchar(); #endif /* Initialise any supplied cdata structure to hold safe values. */ if( cdata ){ cdata->length = 0.0; cdata->out = 1; cdata->nbrk = 0; } /* Get the number of axes in the current Frame. */ naxes = astGetNout( this ); /* Check the "start" parameter for bad values. */ ok = 1; for( i = 0; i < naxes; i++ ) { if( start[ i ] == AST__BAD ){ ok = 0; break; } } /* Check the "length" parameter for bad values. */ if( length == AST__BAD ) ok = 0; /* Check that the "cdata" pointer can be used. */ if( !cdata ) ok = 0; /* Only proceed if the parameters are OK, and there has been no error. */ if( ok && astOK ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ if( axis == 0 ) { gridid = AST__GRIDLINE2_ID; } else { gridid = AST__GRIDLINE1_ID; } astGrfAttrs( this, gridid, 1, GRF__LINE, method, class ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Set up the externals used to communicate with the Map1 function... The number of axes in the physical coordinate system (i.e. the current Frame). */ Map1_ncoord = naxes; /* See if tick marks are logarithmically or linearly spaced. */ Map1_log = astGetLogTicks( this, axis ); /* A pointer to the Plot, the Current Frame and the Mapping. */ Map1_plot = this; Map1_frame = astGetFrame( this, AST__CURRENT ); Map1_map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Physical coords at the start of the curve (dist=0). */ Map1_origin = start; /* Length of the curve. */ Map1_length = length; /* The index of the axis which the curve follows. */ Map1_axis = axis; /* Decide whether to omit points not in their normal ranges. */ Map1_norm = !IsASkyAxis( Map1_frame, 0, status ) && !IsASkyAxis( Map1_frame, 1, status ); /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Now set up the external variables used by the Crv and CrvLine function. */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_ux0 = AST__BAD; Crv_tol = tol; Crv_limit = 0.5*tol*tol; Crv_map = Map1; Crv_ink = ink; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_out = 1; Crv_xbrk = cdata->xbrk; Crv_ybrk = cdata->ybrk; Crv_vxbrk = cdata->vxbrk; Crv_vybrk = cdata->vybrk; Crv_clip = astGetClip( this ) & 1; /* Set up a list of points spread evenly over the curve. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Map these points into graphics coordinates. */ Map1( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map1 to draw the curve. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* End the current poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map1. */ Map1( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* If no part of the curve could be drawn, set the number of breaks and the length of the drawn curve to zero. */ if( Crv_out ) { Crv_nbrk = 0; Crv_len = 0.0F; /* Otherwise, add an extra break to the returned structure at the position of the last point to be plotted. */ } else { Crv_nbrk++; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; } } /* Store extra information about the curve in the returned structure, and purge any zero length sections. */ if( cdata ){ cdata->length = Crv_len; cdata->out = Crv_out; cdata->nbrk = Crv_nbrk; PurgeCdata( cdata, status ); } /* Annul the Frame and Mapping. */ Map1_frame = astAnnul( Map1_frame ); Map1_map = astAnnul( Map1_map ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gridid, 0, GRF__LINE, method, class ); } /* Return. */ return; } static void BBuf( AstPlot *this, int *status ) { /* *++ * Name: c astBBuf f AST_BBUF * Purpose: * Begin a new graphical buffering context. * Type: * Public function. * Synopsis: c #include "plot.h" c void astBBuf( AstPlot *this ) f CALL AST_BBUF( THIS STATUS ) * Class Membership: * Plot member function. * Description: c This function f This routine * starts a new graphics buffering context. A matching call to the c function astEBuf f routine AST_EBUF * should be used to end the context. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - The nature of the buffering is determined by the underlying * graphics system (as defined by the current grf module). Each call c to this function f to this routine c to this function f to this routine * simply invokes the astGBBuf function in the grf module. *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the active GRF BBuf function. */ GBBuf( this, "astBBuf", astGetClass( this ), status ); } static int Boundary( AstPlot *this, const char *method, const char *class, int *status ){ /* * Name: * Boundary * Purpose: * Draw a boundary around regions containing valid physical positions. * Type: * Private function. * Synopsis: * #include "plot.h" * int Boundary( AstPlot *this, const char *method, const char *class, int *status ) * Class Membership: * Plot method. * Description: * This function draws a boundary around the regions of the plotting * area which contain valid, unclipped, physical coordinates, but does * not include the intersections with the edges of the plotting area. * * Broadly, the algorithm is as follows: An initial coarse grid is * created covering the entire plotting area. This grid consists of a * regular square matrix of points in graphics coordinates, and the * corresponding physical coordinates. An array of flags is created, * one for each grid cell, indicating if the boundary passes through the * cell. This is assumed to be the case if the cell has a mix of good and * bad corners (i.e corners which have good or bad physical coordinates). * This assumption does not locate all boundary cells though, since if * the boundary passes into and out of a cell throught the same edge, * the corners of the cell will be either all good or all bad. But for * the moment, we just concentrate on the ones found using this simple * assumption. For each such cell, a finer grid is then created covering * the cell, and the boundary is drawn through this fine grid using * TraceBorder. TraceBorder returns a set of four flags indicating which * edges of the cell were intersected by the boundary. A check is then * made on any of the four neighbouring cells into which the curve * passes. If any of these cells were not flagged as boundary cells using * the simple assumption described earlier, then they are flagged now * (with a different flag value). Once all the cells located using the * simple assumption have been processed, any further cells flagged * with the new flag value are also processed using TraceBorder in the * same way. This process is repeated until no extra boundary cells are * found. * Parameters: * this * Pointer to a Plot. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A flag indicating if any regions containing invalid physical * coordinates were found within the plotting area. * Notes: * - This function assumes the physical coordinate Frame is * 2-dimensional, and it should not be used if this is not the case. * - A value of zero is returned if an error has already occurred, or * if this function should fail for any reason. */ /* Local Variables: */ AstFrame *bfrm; /* Pointer to base Plot Frame */ AstFrame *cfrm; /* Pointer to current Plot Frame */ AstMapping *map; /* Pointer to Plot mapping (graphics -> physical) */ AstMapping *rmap; /* Pointer to Plot mapping (graphics -> physical) */ AstRegion *breg; /* Region mapped into base Plot Frame */ double blbnd[ 2 ]; /* Lower grid bounds in base frame */ double bubnd[ 2 ]; /* Upper grid bounds in base frame */ double dx; /* Plotting area width */ double dy; /* Plotting area height */ double power; /* Exponent in pow call */ double rat; /* Ratio by which to reduce DIM */ double tol; /* Fractional plotting tolerance */ int dim; /* No. of points along each edge of coarse grid */ int edges[ 4 ]; /* Flags indicating edges bisected by boundary */ int rate_disabled; /* Was the astRate method initially disabled? */ int ret; /* Any regions containing bad physical coords? */ /* Check global status. */ if( !astOK ) return 0; /* Initialise the answer to indicate that no regions containing invalid physical coordinates have been found. */ ret = 0; /* Get the current Frame from the Plot. */ cfrm = astGetFrame( this, AST__CURRENT ); /* If it is a region, we use a special method, if possible, to trace the Region boundary. Otherwise, we use a grid tracing method that makes no assumptions about the nature of the Mapping or Frame. */ if( !RegionOutline( this, cfrm, method, class, status ) ) { /* Each basic element of the boundary drawn by the following algorithm will be drawn at a multiple of 45 degrees to the horizontal. This can cause noticable aliasing. For instance, if the border is a straight line at 50 degrees to the horizontal, it will be drawn at 45 degrees for long sections, followed by a vertical leap to catch up with where it should be. Because of this we use a finer tolerance than for other drawing. */ tol = 0.25*astGetTol( this ); /* Set up the dimension of a coarse grid in graphics coordinates to cover the whole plotting area. This is chosen to give a finer grid for smaller plotting tolerances. Note, putting the power as a literal constant in the call to pow seems to cause a segmentation violation on some systems. */ power = -0.666666666; dim = (int) 4*pow( tol, power ) + 10; if( dim > 400 ) dim = 400; if( dim < 3 ) dim = 3; /* Store the required plotting tolerance as a distance in graphics coords. */ dx = fabs( this->xhi - this->xlo ); dy = fabs( this->xhi - this->xlo ); tol *= ( ( dx > dy ) ? dx : dy ); /* Extract the Mapping from the Plot. */ map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Select the area covered by the coarse grid. If the current Frame is a Region, we use the bounding box of Region after being mapped into graphics coords. */ if( astIsARegion( cfrm ) ) { bfrm = astGetFrame( this, AST__BASE ); /* Get the Mapping from the current to the base Frame in the Plot, and remove the effects of any Regions. */ astInvert( map ); rmap = astRemoveRegions( map ); astInvert( map ); /* Map the Region into the GRAPHICS frame. */ breg = astMapRegion( cfrm, rmap, bfrm ); astGetRegionBounds( breg, blbnd, bubnd ); rmap = astAnnul( rmap ); bfrm = astAnnul( bfrm ); breg = astAnnul( breg ); rat = ( ( bubnd[ 0 ] - blbnd[ 0 ] )*( bubnd[ 1 ] - blbnd[ 1 ] ) )/ ( ( this->xhi - this->xlo )*( this->yhi - this->ylo ) ); rat = sqrt( rat ); dim = (int) ( rat*dim ); if( dim < 3 ) dim = 3; /* If the current Frame is not a Region, use the whole plot. */ } else { blbnd[ 0 ] = this->xlo; blbnd[ 1 ] = this->ylo; bubnd[ 0 ] = this->xhi; bubnd[ 1 ] = this->yhi; } /* Disable the astRate method in order to improve the speed of evaluating the Mapping in cases where the Mapping includes an AstRateMap. Note the original value of the flag so that it can be re-instated at the end. */ rate_disabled = astRateState( 1 ); /* Draw the boundary. */ ret = TraceBorder( this, map, blbnd[ 0 ], bubnd[ 0 ], blbnd[ 1 ], bubnd[ 1 ], dim, tol, edges, method, class, status ); /* Re-instate the original setting of the "astRate disabled" flag. */ astRateState( rate_disabled ); /* Release the remaining resources. */ map = astAnnul( map ); } cfrm = astAnnul( cfrm ); /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static int Border( AstPlot *this_nd, int *status ){ /* *++ * Name: c astBorder f AST_BORDER * Purpose: * Draw a border around valid regions of a Plot. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c int astBorder( AstPlot *this ) f RESULT = AST_BORDER( THIS, STATUS ) * Class Membership: * Plot method. * Description: * This function draws a (line) border around regions of the * plotting area of a Plot which correspond to valid, unclipped * physical coordinates. For example, when plotting using an * all-sky map projection, this function could be used to draw the * boundary of the celestial sphere when it is projected on to the * plotting surface. * * If the entire plotting area contains valid, unclipped physical * coordinates, then the boundary will just be a rectangular box * around the edges of the plotting area. * * If the Plot is a Plot3D, this method is applied individually to * each of the three 2D Plots encapsulated within the Plot3D (each of * these Plots corresponds to a single 2D plane in the 3D graphics * system). In addition, if the entire plotting volume has valid * coordinates in the 3D current Frame of the Plot3D, then additional * lines are drawn along the edges of the 3D plotting volume so that * the entire plotting volume is enclosed within a cuboid grid. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astBorder() f AST_BORDER = LOGICAL c Zero is returned if the plotting space is completely filled by f .FALSE. is returned if the plotting space is completely filled by * valid, unclipped physical coordinates (so that only a c rectangular box was drawn around the edge). Otherwise, one is f rectangular box was drawn around the edge). Otherwise, .TRUE. is * returned. * Notes: c - A value of zero will be returned if this function is invoked f - A value of .FALSE. will be returned if this function is invoked c with the AST error status set, or if it should fail for any f with STATUS set to an error value, or if it should fail for any * reason. * - An error results if either the current Frame or the base Frame * of the Plot is not 2-dimensional or (for a Plot3D) 3-dimensional. * - An error also results if the transformation between the base * and current Frames of the Plot is not defined (i.e. the Plot's * TranForward attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPlot *this; /* Plot with no more than 2 current axes */ AstPlotCurveData cdata; /* Structure to receive break information */ const char *class; /* Object class */ const char *method; /* Current method */ int inval; /* Were any bad regions found? */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return 0; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_nd); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astBorder"; class = astGetClass( this_nd ); /* Initialise the bounding box for primitives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this_nd ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Get a Plot with a 2D (or 1D) current Frame. */ this = (AstPlot *) Fset2D( (AstFrameSet *) this_nd, AST__CURRENT, status ); /* Check the current Frame of the Plot is 2-D. */ naxes = astGetNout( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__BORDER_ID, 1, GRF__LINE, method, class ); /* We first draw the intersections of the regions containing valid physical coordinates with the edges of the plotting area. First do the bottom edge. */ LinePlot( this, this->xlo, this->ylo, this->xhi, this->ylo, 1, &cdata, method, class, status ); /* Now do the right-hand edge. */ LinePlot( this, this->xhi, this->ylo, this->xhi, this->yhi, 1, &cdata, method, class, status ); /* Now do the top edge. */ LinePlot( this, this->xhi, this->yhi, this->xlo, this->yhi, 1, &cdata, method, class, status ); /* Now do the left-hand edge. */ LinePlot( this, this->xlo, this->yhi, this->xlo, this->ylo, 1, &cdata, method, class, status ); /* Now draw a curve following the boundary through the interior of the plotting area. If the current Frame in the Plot is a Region, we use a shorter method if possible. If this is not possible, we use a longer method. */ inval = Boundary( this, method, class, status ); /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__BORDER_ID, 0, GRF__LINE, method, class ); /* Annul the 2d plot. */ this = astAnnul( this ); /* Return. */ return inval; } static void BoundingBox( AstPlot *this, float lbnd[2], float ubnd[2], int *status ){ /* *++ * Name: c astBoundingBox f AST_BOUNDINGBOX * Purpose: * Return a bounding box for previously drawn graphics. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astBoundingBox( AstPlot *this, float lbnd[2], float ubnd[2] ) f CALL AST_BOUNDINGBOX( THIS, LBND, UBND, STATUS ) * Class Membership: * Plot method. * Description: c This function returns the bounds of a box which just encompasess the f This routine returns the bounds of a box which just encompasess the * graphics produced by the previous call to any of the Plot methods * which produce graphical output. If no such previous call has yet * been made, or if the call failed for any reason, then the bounding box c returned by this function is undefined. f returned by this routine is undefined. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c lbnd f LBND( 2 ) = REAL (Returned) * A two element array in which is returned the lower limits of the * bounding box on each of the two axes of the graphics coordinate * system (the base Frame of the Plot). c ubnd f UBND( 2 ) = REAL (Returned) * A two element array in which is returned the upper limits of the * bounding box on each of the two axes of the graphics coordinate * system (the base Frame of the Plot). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - An error results if the base Frame of the Plot is not * 2-dimensional. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrameSet *fset; /* Pointer to the Plot's FrameSet */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Get a pointer to the FrameSet at the start of the Plot. */ fset = (AstFrameSet *) this; /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( fset ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "astBoundingBox(%s): Number of axes (%d) in the " "base Frame of the supplied %s is invalid - this number " "should be 2.", status, astGetClass( this ), naxes, astGetClass( this ) ); } /* Return the bounding box. */ lbnd[ 0 ] = Boxp_lbnd[ 0 ]; lbnd[ 1 ] = Boxp_lbnd[ 1 ]; ubnd[ 0 ] = Boxp_ubnd[ 0 ]; ubnd[ 1 ] = Boxp_ubnd[ 1 ]; /* Return. */ return; } static int BoxCheck( float *bx, float *by, float *cx, float *cy, int *status ) { /* * Name: * BoxCheck * Purpose: * See if two boxes overlap. * Type: * Private function. * Synopsis: * #include "plot.h" * int BoxCheck( float *bx, float *by, float *cx, float *cy, int *status ) * Class Membership: * Plot method. * Description: * This function returns a flag indicating if two trapezoidal boxes * (box "b" and box "c") overlap or not. * Parameters: * bx * Pointer to an array holding the X coordinates at the 4 corners * of box "b". * by * Pointer to an array holding the Y coordinates at the 4 corners * of box "b". * cx * Pointer to an array holding the X coordinates at the 4 corners * of box "c". * cy * Pointer to an array holding the Y coordinates at the 4 corners * of box "c". * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the boxes do not overlap or an error has * already occurred. Otherwise, 1 is returned. */ /* Local Variables: */ float x2; float y2; int i; int ip; int j; int jp; int ret; /* Assume the boxes do not overlap. */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Check each corner of box b to see if it is inside box c. */ for( j = 0; j < 4 && ret == 0; j++ ){ if( Inside( 4, cx, cy, bx[ j ], by[ j ], status ) ) ret = 1; } /* Now check each corner of box c to see if it is inside box b. */ for( j = 0; j < 4 && ret == 0; j++ ){ if( Inside( 4, bx, by, cx[ j ], cy[ j ], status ) ) ret = 1; } /* If no overlap has yet been found, we need to see if any of the edges of the boxes intersect. For instance, in the case of a cross formed by a vertical rectangle crossing a horizontal rectangle, the above checks on the corners would not have revealed any overlap. */ if( !ret ) { /* The following code assumes that the corners with indices 0, 1, 2, 3 are adjacent round the edge of the box. This is the case if the line joining corners 0 and 1 does not cross the line joining corners 2 and 3 AND the line joining corners 1 and 2 does not cross the line joining corners 3 and 0. If either of these conditions is not met swap the corners around to correct it. First do box b. */ if( Cross( bx[0], by[0], bx[1], by[1], bx[2], by[2], bx[3], by[3], status ) ) { x2 = bx[2]; y2 = by[2]; bx[2] = bx[1]; by[2] = by[1]; bx[1] = x2; by[1] = y2; } else if( Cross( bx[1], by[1], bx[2], by[2], bx[3], by[3], bx[0], by[0], status ) ) { x2 = bx[2]; y2 = by[2]; bx[2] = bx[3]; by[2] = by[3]; bx[3] = x2; by[3] = y2; } /* Now do box c. */ if( Cross( cx[0], cy[0], cx[1], cy[1], cx[2], cy[2], cx[3], cy[3], status ) ) { x2 = cx[2]; y2 = cy[2]; cx[2] = cx[1]; cy[2] = cy[1]; cx[1] = x2; cy[1] = y2; } else if( Cross( cx[1], cy[1], cx[2], cy[2], cx[3], cy[3], cx[0], cy[0], status ) ) { x2 = cx[2]; y2 = cy[2]; cx[2] = cx[3]; cy[2] = cy[3]; cx[3] = x2; cy[3] = y2; } /* We now check each edge of box b to see if it overlaps any edge of box c. */ for( j = 0; j < 4 && ret == 0; j++ ) { /* This edge of box b starts at the corner with index j. Get the index of the corner at which the edge ends. */ jp = j + 1; if( jp == 4 ) jp = 0; /* Check to see if this edge of box b crosses each edge of box c in turn. */ for( i = 0; i < 4 && ret == 0; i++ ) { ip = i + 1; if( ip == 4 ) ip = 0; ret = Cross( bx[j], by[j], bx[jp], by[jp], cx[i], cy[i], cx[ip], cy[ip], status ); } } } return ret; } static void Bpoly( AstPlot *this, float x, float y, int *status ){ /* * Name: * Bpoly * Purpose: * Begin a new poly line. * Type: * Private function. * Synopsis: * #include "plot.h" * void Bpoly( AstPlot *this, float x, float y, int *status ) * Class Membership: * Plot member function. * Description: * This function draws any current poly line, and then starts a new one * at the supplied position. * Parameters: * x * The graphics x coordinate. * y * The graphics y coordinate. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int ignore; /* Is the new point the end of the current polyline? */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* See if the new point is co-incident with the end of the current polyline. If so we assume the current polyline is to be re-started, rather than starting a new polyline. */ if( Poly_n > 0 ) { ignore = ( EQUAL( Poly_x[ Poly_n - 1 ], x ) && EQUAL( Poly_y[ Poly_n - 1 ], y ) ); } else { ignore = 0; } /* If the supplied point is not at the end of the current polyline, draw any existing poly line. This will empty the buffer. Then add the supplied point into the buffer. */ if( !ignore ) { Opoly( this, status ); Apoly( this, x, y, status ); } } static int CGCapWrapper( AstPlot *this, int cap, int value, int *status ) { /* * * Name: * CGCapWrapper * Purpose: * Call a C implementation of the GCap Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGCapWrapper( AstPlot *this, int cap, int value, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GCap * grf function to enquire or set a graphics attribute value. * Parameters: * this * The Plot. * cap * The capability to be inquired aboue. * value * The value ot assign to the capability. * status * Pointer to the inherited status value. * Returned Value: * Non-zero if the grf module is capabale of performing the action * requested by "cap". */ if( !astOK ) return 0; return ( (AstGCapFun) this->grffun[ AST__GCAP ] )( astGrfConID(this), cap, value ); } static int CGAttrWrapper( AstPlot *this, int attr, double value, double *old_value, int prim, int *status ) { /* * * Name: * CGAttrWrapper * Purpose: * Call a C implementation of the GAttr Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGAttrWrapper( AstPlot *this, int attr, double value, * double *old_value, int prim, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GAttr * grf function to enquire or set a graphics attribute value. * Parameters: * this * The Plot. * attr * An integer value identifying the required attribute. The * following symbolic values are defined in grf.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 * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGAttrFun) this->grffun[ AST__GATTR ] )( astGrfConID(this), attr, value, old_value, prim ); } static int CGBBufWrapper( AstPlot *this, int *status ) { /* * * Name: * CGBBufWrapper * Purpose: * Call a C implementation of the GBBuf Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGBBufWrapper( AstPlot *this ) { * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GBBuf * grf function to start a new graphics context. * Parameters: * this * The Plot. * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGBBufFun) this->grffun[ AST__GBBUF ])( astGrfConID(this) ); } static int CGEBufWrapper( AstPlot *this, int *status ) { /* * * Name: * CGEBufWrapper * Purpose: * Call a C implementation of the GEBuf Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGEBufWrapper( AstPlot *this ) { * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GEBuf * grf function to start a new graphics context. * Parameters: * this * The Plot. * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGEBufFun) this->grffun[ AST__GEBUF ])( astGrfConID(this) ); } static int CGFlushWrapper( AstPlot *this, int *status ) { /* * * Name: * CGFlushWrapper * Purpose: * Call a C implementation of the GFlush Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGFlushWrapper( AstPlot *this ) { * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GFlush * grf function to flush graphics. * Parameters: * this * The Plot. * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGFlushFun) this->grffun[ AST__GFLUSH ])( astGrfConID(this) ); } static int CGLineWrapper( AstPlot *this, int n, const float *x, const float *y, int *status ) { /* * * Name: * CGLineWrapper * Purpose: * Call a C implementation of the GLine Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGLineWrapper( AstPlot *this, int n, const float *x, * const float *y, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GLine * grf function to draw a polyline. * Parameters: * this * The Plot. * 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. * status * Pointer to the inherited status variable. */ if( !astOK ) return 0; return ( (AstGLineFun) this->grffun[ AST__GLINE ])( astGrfConID(this), n, x, y ); } static int CGMarkWrapper( AstPlot *this, int n, const float *x, const float *y, int type, int *status ) { /* * * Name: * CGMarkWrapper * Purpose: * Call a C implementation of the GMark Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGMarkWrapper( AstPlot *this, int n, const float *x, * const float *y, int type, int *status ) { * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GMark grf * function to draw markers. * Parameters: * this * The Plot. * 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. * type * An integer which can be used to indicate the type of marker symbol * required. * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGMarkFun) this->grffun[ AST__GMARK ])( astGrfConID(this), n, x, y, type ); } static int CGTextWrapper( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy, int *status ) { /* * * Name: * CGTextWrapper * Purpose: * Call a C implementation of the GText Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGTextWrapper( AstPlot *this, const char *text, float x, float y, * const char *just, float upx, float upy, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GText grf * function to draw a text string. * Parameters: * this * The Plot. * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGTextFun) this->grffun[ AST__GTEXT ])( astGrfConID(this), text, x, y, just, upx, upy ); } static int CGTxExtWrapper( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy, float *xb, float *yb, int *status ) { /* * * Name: * CGTxExtWrapper * Purpose: * Call a C implementation of the GTxExt Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGTxExtWrapper( AstPlot *this, const char *text, float x, float y, * const char *just, float upx, float upy, float *xb, * float *yb, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GTxExt * grf function to find the extent of a text string. * Parameters: * this * The Plot. * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * 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. * status * Pointer to the inherited status variable. */ if( !astOK ) return 0; return ( (AstGTxExtFun) this->grffun[ AST__GTXEXT ])( astGrfConID(this), text, x, y, just, upx, upy, xb, yb ); } static int CGQchWrapper( AstPlot *this, float *chv, float *chh, int *status ) { /* * * Name: * CGQchWrapper * Purpose: * Call a C implementation of the GQch Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGQchWrapper( AstPlot *this, float *chv, float *chh, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GQch * grf function to find the extent of a text string. * Parameters: * this * The Plot. * chv * A pointer to the double which is to receive the height of * characters drawn vertically. This will be an increment in the X * axis * chh * A pointer to the double which is to receive the height of * characters drawn vertically. This will be an increment in the Y * axis * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGQchFun) this->grffun[ AST__GQCH ])( astGrfConID(this), chv, chh ); } static int CGScalesWrapper( AstPlot *this, float *alpha, float *beta, int *status ) { /* * * Name: * CGScalesWrapper * Purpose: * Call a C implementation of the GScales Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int CGScalesWrapper( AstPlot *this, float *alpha, float *beta, int *status ) * Class Membership: * Plot private function. * Description: * This function is a wrapper for a C implementation of the GScales * grf function to find the extent of a text string. * Parameters: * this * The Plot. * alpha * A pointer to the location at which to return the scale for the * X axis (i.e. Xnorm = alpha*Xworld). * beta * A pointer to the location at which to return the scale for the * Y axis (i.e. Ynorm = beta*Yworld). * status * Pointer to the inherited status value. */ if( !astOK ) return 0; return ( (AstGScalesFun) this->grffun[ AST__GSCALES ])( astGrfConID(this), alpha, beta ); } static int CheckLabels( AstPlot *this, AstFrame *frame, int axis, double *ticks, int nticks, int force, char **list, double refval, int *status ){ /* * Name: * CheckLabels * Purpose: * Create tick mark labels and check that adjacent labels are different. * Type: * Private function. * Synopsis: * #include "plot.h" * int CheckLabels( AstPlot *this, AstFrame *frame, int axis, double *ticks, * int nticks, int force, char **list, double refval, int *status ) * Class Membership: * Plot member function. * Description: * This function formats the supplied ticks mark values using the * astFormat method for the supplied Frame. Unless force is non-zero, it * then checks all pairs of adjacent labels. If a pair is found which are * identical then the memory holding the labels is released, and a value * of zero is returned. Otherwise, a value of one is returned, indicating * that adjacent labels are all different and the labels are returned. * Parameters: * this * Pointer to the Plot. * frame * Pointer to the Frame. * axis * The zero-based index of the axis to which the tick marks refer. * ticks * Pointer to an array holding the tick mark values. * nticks * The number of tick marks supplied by parameter "ticks". * force * If non-zero, then no check for identical adjacent labels is * performed, and the labels are always considered to be OK. * list * Pointer to the start of an array of pointers. Each of the * elements in this array receives a pointer to a string holding a * formatted label. Each of these strings should be freed using * astFree when no longer needed. * refval * A value to use for the other axis when normalizing. * status * Pointer to the inherited status variable. * Returned Value: * Zero if any pairs of identical adjacent labels were found. One * otherwise. * Notes: * - No error is reported if a pair of identical adjacent labels is * found. * - If an error has already occurred, or if this function should * fail for any reason, a value of zero is returned, and the array of * pointers identified by "list" is filled with NULL pointers. */ /* Local Variables: */ const char *label; /* Pointer to formatted tick value */ double val[ 2 ]; /* Workspace for normalizing */ int i; /* Tick index */ int len; /* Number of characters in curent label */ int ok; /* The returned flag */ /* Fill the supplied label list with NULL pointers. */ if( list ) { for( i = 0; i < nticks; i++ ) list[ i ] = NULL; } /* Check the global status. */ if( !astOK ) return 0; /* Initialise the returned flag to indicate that all adjacent labels are different. */ ok = 1; /* Normalize and format the first tick mark value. */ val[ axis ] = ticks[ 0 ]; val[ 1 - axis ] = refval; astNorm( frame, val ); label = astFormat( frame, axis, val[ axis ] ); /* Allocate memory holding a copy of the formatted value, and store a pointer to this copy in the list of labels. */ if( label ){ len = strlen( label ) + 1; list[ 0 ] = (char *) astStore( NULL, (void *) label, len ); } else { ok = 0; } /* Normalize and format each of the tick mark values in this batch. */ for( i = 1; i < nticks && astOK && ok; i++ ){ val[ axis ] = ticks[ i ]; val[ 1 - axis ] = refval; astNorm( frame, val ); label = astFormat( frame, axis, val[ axis ] ); if( label ){ /* Unless checks have been supressed, compare this label with the previous label. If they are identical clear the returned flag. */ if( !force && !strcmp( label, list[ i - 1 ] ) ) { ok = 0; /* Allocate memory holding a copy of the label, and store a pointer to this copy in the list of labels. */ } else { list[ i ] = (char *) astStore( NULL, (void *) label, strlen( label ) + 1 ); } } else { ok = 0; } } /* If two adjacent labels were identical, or an error occurred, release the memory used to store the labels. */ if( !ok || !astOK ){ for( i = 0; i < nticks; i++ ){ if( list[ i ] ) list[ i ] = (char *) astFree( (void *) list[ i ] ); } } /* Ensure a value of zero is returned if an error has occurred. */ if( !astOK ) ok = 0; /* Return the answer. */ return ok; } static char **CheckLabels2( AstPlot *this, AstFrame *frame, int axis, double *ticks, int nticks, char **old_list, double refval, int *status ){ /* * Name: * CheckLabels2 * Purpose: * Check that labels cannot be shortened. * Type: * Private function. * Synopsis: * #include "plot.h" * char **CheckLabels2( AstPlot *this, AstFrame *frame, int axis, * double *ticks, int nticks, char **old_list, * double refval, int *status ) * Class Membership: * Plot member function. * Description: * This function formats the supplied ticks mark values using the * astFormat method for the supplied Frame. It then compares the labels * with the corresponding labels supplied in "old_list". If all of the * new labels are shorter than, or equal in length to, the old labels, * then memory is allocated to hold the new (shorter) labels, and a * pointer to this memory is returned. If any new label is longer than * the corresponding old label, then a NULL pointer is returned. * * No check is performed on whether or not there are any identical * adjacent labels. * Parameters: * this * Pointer to the Plot. * frame * Pointer to the Frame. * axis * The zero-based index of the axis to which the tick marks refer. * ticks * Pointer to an array holding the tick mark values. * nticks * The number of tick marks supplied by parameter "ticks". * old_list * Pointer to the start of an array of pointers. Each of the * elements in this array should hold a pointer to a string holding a * formatted label. * refval * A value to use for the other axis when normalizing. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to an array of pointers. Each of these pointers points to * a text string holding a shortened label. If a complete set of * shortened labels could not be found (or if an error occurs), a NULL * pointer is returned. * Notes: * - The memory holding the returned shortened labels should be * freed by cthe caller, together with the memory holding the pointers to * the labels. * - No error is reported if a pair of identical adjacent labels is * found. * - If an error has already occurred, or if this function should * fail for any reason, a value of NULL is returned. */ /* Local Variables: */ char **list; /* The returned pointer */ const char *label; /* Pointer to formatted tick value */ double val[ 2 ]; /* Workspace for normalizing */ int i; /* Tick index */ int llen; /* Number of characters in curent label */ int ok; /* Are the old labels OK to be used? */ /* Check the global status. */ if( !astOK ) return NULL; /* Allocate memory to hold the pointers to the new labels. */ list = (char **) astMalloc( sizeof( char * )*(size_t) nticks ); if( list ) { /* Fill this array with NULLs for safety. */ for( i = 0; i < nticks; i++ ) list[ i ] = NULL; /* Initialise a flag to indicate that all the new labels are shorter than the old labels. */ ok = 0; /* Normalize and format each of the tick mark values in this batch. */ for( i = 0; i < nticks && astOK; i++ ){ val[ axis ] = ticks[ i ]; val[ 1 - axis ] = refval; astNorm( frame, val ); label = astFormat( frame, axis, val[ axis ] ); if( label ){ /* Get the length of the new label. */ llen = strlen( label ); /* Compare this label with the corresponding old label. If the new one is longer than the old one, set the flag and leave the loop. */ if( llen > strlen( old_list[ i ] ) ) { ok = 1; break; } /* Store the new label. */ list[ i ] = (char *) astStore( NULL, (void *) label, (size_t) (llen + 1) ); } } /* If the old labels are to be used, or an error occurred, release the memory used to store the new labels. */ if( ok || !astOK ){ for( i = 0; i < nticks; i++ ){ if( list[ i ] ) list[ i ] = (char *) astFree( (void *) list[ i ] ); } list = (char **) astFree( (void *) list ); } } /* Return the answer. */ return list; } static int ChrLen( const char *string, int *status ){ /* * Name: * ChrLen * Purpose: * Return the length of a string excluding any trailing white space. * Type: * Private function. * Synopsis: * int ChrLen( const char *string, int *status ) * Class Membership: * Plot * Description: * This function returns the length of a string excluding any trailing * white space. * Parameters: * string * Pointer to the string. * status * Pointer to the inherited status variable. * Returned Value: * The length of a string excluding any trailing white space. * Notes: * - A value of zero is returned if a NULL pointer is supplied, or if an * error has already occurred. */ /* Local Variables: */ const char *c; /* Pointer to the next character to check */ int ret; /* The returned string length */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise the returned string length. */ ret = 0; /* Check a string has been supplied. */ if( string ){ /* Check each character in turn, starting with the last one. */ ret = strlen( string ); c = string + ret - 1; while( ret ){ if( !isspace( (int) *c ) ) break; c--; ret--; } } /* Return the answer. */ return ret; } static AstPlotCurveData **CleanCdata( AstPlotCurveData **cdata, int *status ){ /* * Name: * CleanCdata * Purpose: * Release the structures holding curve break information. * Type: * Private function. * Synopsis: * #include "plot.h" * AstPlotCurveData **CleanCdata( AstPlotCurveData **cdata, int *status ) * Class Membership: * Plot member function. * Description: * This function releases the memory used to hold the curve break * information returned by function DrawGrid, and returns a NULL pointer. * Parameters: * cdata * Pointer to the information to be freed. * status * Pointer to the inherited status variable. * Returned Value: * A NULL pointer. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Return if a NULL pointer has been supplied. */ if( !cdata ) return NULL; /* Release each of the two structures in turn (if they exist). */ (void) astFree( (void *) cdata[ 0 ] ); (void) astFree( (void *) cdata[ 1 ] ); /* Release the memory used to hold the two AstPlotCurveData pointers. */ (void) astFree( (void *) cdata ); /* Return. */ return NULL; } static TickInfo **CleanGrid( TickInfo **grid, int *status ){ /* * Name: * CleanGrid * Purpose: * Release the structures holding grid information. * Type: * Private function. * Synopsis: * #include "plot.h" * TickInfo **CleanGrid( TickInfo **grid ) * Class Membership: * Plot member function. * Description: * This function releases the memory used to hold the grid information * returned by function GridLines, and returns a NULL pointer. * Parameters: * grid * Pointer to the information to be freed. * Returned Value: * A NULL pointer. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ TickInfo *info; /* Pointer to TickInfo structure being freed */ int i; /* Axis index */ int j; /* Tick mark index */ /* Return if a NULL pointer has been supplied. */ if( !grid ) return NULL; /* Release each of the TickInfo structures in turn (if they exist). */ for( i = 0; i < 2; i++ ){ if( ( info = grid[ i ] ) ){ /* Release the memory holding major tick mark values. */ (void) astFree( (void *) info->ticks ); /* Release the memory holding minor tick mark values. */ (void) astFree( (void *) info->minticks ); /* Release the memory holding curve section starting positions. */ (void) astFree( (void *) info->start ); /* Release the memory holding curve section lengths. */ (void) astFree( (void *) info->length ); /* If there are any tick mark labels in the structure... */ if( info->labels ){ /* Release the memory holding each tick mark label. */ for( j = 0; j < info->nmajor; j++ ){ (void) astFree( (void *) info->labels[ j ] ); } /* Release the memory holding the pointers to the tick mark labels. */ (void) astFree( (void *) info->labels ); /* Release the memory holding the format specification string. */ (void) astFree( (void *) info->fmt ); } /* Release the TickInfo structure. */ (void) astFree( (void *) info ); } } /* Release the memory used to hold the two TickInfo pointers. */ (void) astFree( (void *) grid ); /* Return. */ return NULL; } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a Plot. * Type: * Private function. * Synopsis: * #include "plot.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Plot member function (over-rides the astClearAttrib protected * method inherited from the FrameSet class). * Description: * This function clears the value of a specified attribute for a * Plot, so that the default value will subsequently be used. * Parameters: * this * Pointer to the Plot. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPlot *this; /* Pointer to the Plot structure */ char label[21]; /* Graphics item label */ const char *class; /* Pointer to class string */ int axis; /* Axis number */ int id1; /* Plot object id */ int id2; /* Plot object id */ int id; /* Plot object id */ int len; /* Length of attrib string */ int nax; /* Number of base Frame axes */ int nc; /* No. characters read by astSscanf */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_object; /* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ nax = astGetNin( this ); /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* Edge(axis). */ /* ------------ */ if ( nc = 0, ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearEdge( this, axis - 1 ); /* Grid. */ /* ----- */ } else if ( !strcmp( attrib, "grid" ) ) { astClearGrid( this ); /* LabelUp */ /* ------- */ } else if ( !strcmp( attrib, "labelup" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLabelUp( this, axis ); /* LabelUp(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLabelUp( this, axis - 1 ); /* LogPlot */ /* ------- */ } else if ( !strcmp( attrib, "logplot" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLogPlot( this, axis ); /* LogPlot(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLogPlot( this, axis - 1 ); /* LogTicks */ /* ------- */ } else if ( !strcmp( attrib, "logticks" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLogTicks( this, axis ); /* LogTicks(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLogTicks( this, axis - 1 ); /* LogLabel */ /* ------- */ } else if ( !strcmp( attrib, "loglabel" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLogLabel( this, axis ); /* LogLabel(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLogLabel( this, axis - 1 ); /* NumLab. */ /* ---------- */ } else if ( !strcmp( attrib, "numlab" ) ) { for( axis = 0; axis < nax; axis++ ) astClearNumLab( this, axis ); /* NumLab(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearNumLab( this, axis - 1 ); /* MinTick. */ /* ---------- */ } else if ( !strcmp( attrib, "mintick" ) ) { for( axis = 0; axis < nax; axis++ ) astClearMinTick( this, axis ); /* MinTick(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearMinTick( this, axis - 1 ); /* TextLab. */ /* ---------- */ } else if ( !strcmp( attrib, "textlab" ) ) { for( axis = 0; axis < nax; axis++ ) astClearTextLab( this, axis ); /* TextLab(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearTextLab( this, axis - 1 ); /* LabelUnits. */ /* --------- */ } else if ( !strcmp( attrib, "labelunits" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLabelUnits( this, axis ); /* LabelUnits(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLabelUnits( this, axis - 1 ); /* Style. */ /* ------ */ } else if ( !strcmp( attrib, "style" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearStyle( this, id ); /* Style(label). */ /* --------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearStyle( this, id1 ); if( nid > 1 ) astClearStyle( this, id2 ); if( nid > 2 ) astClearStyle( this, id3 ); /* Font. */ /* ----- */ } else if ( !strcmp( attrib, "font" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearFont( this, id ); /* Font(label). */ /* -------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearFont( this, id1 ); if( nid > 1 ) astClearFont( this, id2 ); if( nid > 2 ) astClearFont( this, id3 ); /* Colour. */ /* ------- */ } else if ( !strcmp( attrib, "colour" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearColour( this, id ); /* Colour(label). */ /* ---------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearColour( this, id1 ); if( nid > 1 ) astClearColour( this, id2 ); if( nid > 2 ) astClearColour( this, id3 ); /* Color. */ /* ------ */ } else if ( !strcmp( attrib, "color" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearColour( this, id ); /* Color(label). */ /* --------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearColour( this, id1 ); if( nid > 1 ) astClearColour( this, id2 ); if( nid > 2 ) astClearColour( this, id3 ); /* Width. */ /* ------ */ } else if ( !strcmp( attrib, "width" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearWidth( this, id ); /* Width(label). */ /* --------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearWidth( this, id1 ); if( nid > 1 ) astClearWidth( this, id2 ); if( nid > 2 ) astClearWidth( this, id3 ); /* Size. */ /* ----- */ } else if ( !strcmp( attrib, "size" ) ) { for( id = 0; id < AST__NPID; id++ ) astClearSize( this, id ); /* Size(label). */ /* -------------*/ } else if ( nc = 0, ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, attrib, "astClear", class, status ), nax, &id1, &id2, &id3, status ); astClearSize( this, id1 ); if( nid > 1 ) astClearSize( this, id2 ); if( nid > 2 ) astClearSize( this, id3 ); /* LabelAt(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLabelAt( this, axis - 1 ); /* Centre(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "centre(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearCentre( this, axis - 1 ); /* Gap. */ /* ---- */ } else if ( !strcmp( attrib, "gap" ) ) { for( axis = 0; axis < nax; axis++ ) astClearGap( this, axis ); /* Gap(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearGap( this, axis - 1 ); /* LogGap. */ /* ----------- */ } else if ( !strcmp( attrib, "loggap" ) ) { for( axis = 0; axis < nax; axis++ ) astClearLogGap( this, axis ); /* LogGap(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLogGap( this, axis - 1 ); /* NumLabGap. */ /* ---------- */ } else if ( !strcmp( attrib, "numlabgap" ) ) { for( axis = 0; axis < nax; axis++ ) astClearNumLabGap( this, axis ); /* NumLabGap(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearNumLabGap( this, axis - 1 ); /* TextLabGap. */ /* ----------- */ } else if ( !strcmp( attrib, "textlabgap" ) ) { for( axis = 0; axis < nax; axis++ ) astClearTextLabGap( this, axis ); /* TextLabGap(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearTextLabGap( this, axis - 1 ); /* TitleGap. */ /* --------- */ } else if ( !strcmp( attrib, "titlegap" ) ) { astClearTitleGap( this ); /* MajTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "majticklen" ) ) { for( axis = 0; axis < nax; axis++ ) astClearMajTickLen( this, axis ); /* MajTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearMajTickLen( this, axis - 1 ); /* MinTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "minticklen" ) ) { for( axis = 0; axis < nax; axis++ ) astClearMinTickLen( this, axis ); /* MinTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearMinTickLen( this, axis - 1 ); /* Labelling. */ /* -------- */ } else if ( !strcmp( attrib, "labelling" ) ) { astClearLabelling( this ); /* TickAll. */ /* -------- */ } else if ( !strcmp( attrib, "tickall" ) ) { astClearTickAll( this ); /* ForceExterior */ /* ------------- */ } else if ( !strcmp( attrib, "forceexterior" ) ) { astClearForceExterior( this ); /* Invisible. */ /* ---------- */ } else if ( !strcmp( attrib, "invisible" ) ) { astClearInvisible( this ); /* Border. */ /* ------- */ } else if ( !strcmp( attrib, "border" ) ) { astClearBorder( this ); /* ClipOp. */ /* ------- */ } else if ( !strcmp( attrib, "clipop" ) ) { astClearClipOp( this ); /* Clip. */ /* ----- */ } else if ( !strcmp( attrib, "clip" ) ) { astClearClip( this ); /* Grf. */ /* ---- */ } else if ( !strcmp( attrib, "grf" ) ) { astClearGrf( this ); /* DrawTitle. */ /* ---------- */ } else if ( !strcmp( attrib, "drawtitle" ) ) { astClearDrawTitle( this ); /* DrawAxes. */ /* --------- */ } else if ( !strcmp( attrib, "drawaxes" ) ) { for( axis = 0; axis < nax; axis++ ) astClearDrawAxes( this, axis ); /* Abbrev */ /* ------ */ } else if ( !strcmp( attrib, "abbrev" ) ) { for( axis = 0; axis < nax; axis++ ) astClearAbbrev( this, axis ); /* DrawAxes(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearDrawAxes( this, axis - 1 ); /* Abbrev(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearAbbrev( this, axis - 1 ); /* Escape. */ /* ------- */ } else if ( !strcmp( attrib, "escape" ) ) { astClearEscape( this ); /* Tol. */ /* ---- */ } else if ( !strcmp( attrib, "tol" ) ) { astClearTol( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static void ClearLogPlot( AstPlot *this, int axis, int *status ){ /* * * Name: * ClearLogPlot * Purpose: * Clear the value for a LogPlot attribute * Type: * Private function. * Synopsis: * #include "plot.h" * void ClearLogPlot( AstPlot *this, int axis, int *status ) * Class Membership: * Plot member function * Description: * Assigns the default value to the LogPlot attribute of the specified * axis, and also re-maps the base Frame of the Plot if necessary. * Parameters: * this * The Plot. * axis * Zero based axis index. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int oldval; /* Original value of the attribute */ int newval; /* Cleared (default) value of the attribute */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the axis index. */ if( axis < 0 || axis >= 2 ){ astError( AST__AXIIN, "astClearLogPlot(%s): Index (%d) is invalid for " "attribute LogPlot - it should be in the range 1 to 2.", status, astGetClass( this ), axis + 1 ); /* Do nothing if the attribute is not currently set. */ } else if( astTestLogPlot( this, axis ) ){ /* Get the original value of the attribute. clear the value, and then get the new (default) value. */ oldval = this->logplot[ axis ]; this->logplot[ axis ] = -1; newval = astGetLogPlot( this, axis ); /* If the effective value has changed, attempt to remap the axis. If this fails, re-instate the original value. */ if( ( oldval != 0 ) != ( newval != 0 ) ) { if( !ToggleLogLin( this, axis, oldval, "astClearLogPlot", status ) ) { this->logplot[ axis ] = oldval; } } } } static void Clip( AstPlot *this, int iframe, const double lbnd[], const double ubnd[], int *status ){ /* *++ * Name: c astClip f AST_CLIP * Purpose: * Set up or remove clipping for a Plot. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astClip( AstPlot *this, int iframe, const double lbnd[], c const double ubnd[] ) f CALL AST_CLIP( THIS, IFRAME, LBND, UBND, STATUS ) * Class Membership: * Plot method. * Description: c This function defines regions of a Plot which are to be clipped. f This routine defines regions of a Plot which are to be clipped. * Any subsequent graphical output created using the Plot will then * be visible only within the unclipped regions of the plotting * area. See also the Clip attribute. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c iframe f IFRAME = INTEGER (Given) * The index of the Frame within the Plot to which the clipping c limits supplied in "lbnd" and "ubnd" (below) refer. Clipping f limits supplied in LBND and UBND (below) refer. Clipping * may be applied to any of the coordinate systems associated * with a Plot (as defined by the Frames it contains), so this * index may take any value from 1 to the number of Frames in * the Plot (Nframe attribute). In addition, the values * AST__BASE and AST__CURRENT may be used to specify the base * and current Frames respectively. * * For example, a value of AST__CURRENT causes clipping to be * performed in physical coordinates, while a value of AST__BASE * would clip in graphical coordinates. Clipping may also be * removed completely by giving a value of AST__NOFRAME. In this * case any clipping bounds supplied (below) are ignored. c lbnd f LBND( * ) = DOUBLE PRECISION (Given) * An array with one element for each axis of the clipping Frame c (identified by the index "iframe"). This should contain the f (identified by the index IFRAME). This should contain the * lower bound, on each axis, of the region which is to remain * visible (unclipped). c ubnd f UBND( * ) = DOUBLE PRECISION (Given) * An array with one element for each axis of the clipping Frame c (identified by the index "iframe"). This should contain the f (identified by the index IFRAME). This should contain the * upper bound, on each axis, of the region which is to remain * visible (unclipped). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - Only one clipping Frame may be active at a time. This function f - Only one clipping Frame may be active at a time. This routine * will deactivate any previously-established clipping Frame before * setting up new clipping limits. c - The clipping produced by this function is in addition to that f - The clipping produced by this routine is in addition to that * specified by the Clip attribute which occurs at the edges of the * plotting area c established when the Plot is created (see astPlot). The f established when the Plot is created (see AST_PLOT). The * underlying graphics system may also impose further clipping. * - When testing a graphical position for clipping, it is first * transformed into the clipping Frame. The resulting coordinate on * each axis is then checked against the clipping limits (given by c "lbnd" and "ubnd"). By default, a position is clipped if any f LBND and UBND). By default, a position is clipped if any * coordinate lies outside these limits. However, if a non-zero * value is assigned to the Plot's ClipOp attribute, then a * position is only clipped if the coordinates on all axes lie * outside their clipping limits. * - If the lower clipping limit exceeds the upper limit for any * axis, then the sense of clipping for that axis is reversed (so * that coordinate values lying between the limits are clipped * instead of those lying outside the limits). To produce a "hole" * in a coordinate space (that is, an internal region where nothing * is plotted), you should supply all the bounds in reversed order, * and set the ClipOp attribute for the Plot to a non-zero value. * - Either clipping limit may be set to the value AST__BAD, which * is equivalent to setting it to infinity (or minus infinity for a * lower bound) so that it is not used. * - If a graphical position results in any bad coordinate values * (AST__BAD) when transformed into the clipping Frame, then it is * treated (for the purposes of producing graphical output) as if * it were clipped. * - When a Plot is used as a Mapping to transform points c (e.g. using astTran2), any clipped output points are assigned f (e.g. using AST_TRAN2), any clipped output points are assigned * coordinate values of AST__BAD. * - An error results if the base Frame of the Plot is not * 2-dimensional. *-- */ /* Local Variables: */ AstFrame *fr; /* Pointer to the clipping Frame */ AstFrameSet *fset; /* Pointer to the Plot's FrameSet */ int i; /* Axis index */ int ifrm; /* The validated frame index */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ ifrm = 0; /* Get a pointer to the FrameSet at the start of the Plot. */ fset = (AstFrameSet *) this; /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( fset ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "astClip(%s): Number of axes (%d) in the " "base Frame of the supplied %s is invalid - this number " "should be 2.", status, astGetClass( this ), naxes, astGetClass( this ) ); } /* If clipping is to be switched on, check the supplied frame index and bounds. */ if( iframe != AST__NOFRAME && astOK ) { /* Report an error if either of the bounds pointers is NULL.*/ if( !lbnd ){ astError( AST__CLPAX, "astClip(%s): A NULL pointer was " "supplied for the array holding the lower bounds of " "the clipping volume.", status, astGetClass( this ) ); } else if( !ubnd ){ astError( AST__CLPAX, "astClip(%s): A NULL pointer was " "supplied for the array holding the upper bounds of " "the clipping volume.", status, astGetClass( this ) ); } /* Validate the clipping frame index. */ ifrm = astValidateFrameIndex( fset, iframe, "astClip" ); /* Get the number of axes in the clipping frame. */ fr = astGetFrame( this, ifrm ); naxes = astGetNaxes( fr ); fr = astAnnul( fr ); } /* Leave the current clipping information unchanged if an error has occurred. */ if( astOK ){ /* Remove all clipping information from the Plot. */ this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); this->clip_frame = AST__NOFRAME; this->clip_axes = 0; /* If bounds have been supplied, set up new clipping information. */ if( iframe != AST__NOFRAME ){ /* Store the information. */ this->clip_frame = ifrm; this->clip_lbnd = astStore( NULL, lbnd, sizeof(double)*(size_t)naxes ); this->clip_ubnd = astStore( NULL, ubnd, sizeof(double)*(size_t)naxes ); this->clip_axes = naxes; /* If an error has occurred, remove all clipping information. */ if( !astOK ){ this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); this->clip_frame = AST__NOFRAME; this->clip_axes = 0; /* Otherwise, replace any bounds of AST__BAD with suitable default values. */ } else { for( i = 0; i < naxes; i++ ){ if( this->clip_lbnd[ i ] == AST__BAD ) this->clip_lbnd[ i ] = -DBL_MAX; if( this->clip_ubnd[ i ] == AST__BAD ) this->clip_ubnd[ i ] = DBL_MAX; } } } } /* Return. */ return; } static int Compared( const void *elem1, const void *elem2 ){ /* * Name: * Compared * Purpose: * Compare two "double" values. * Type: * Private function. * Synopsis: * #include "plot.h" * int Compared( const void *elem1, const void *elem2 ) * Class Membership: * Plot method. * Description: * This function compares the two "double" values to which pointers * are supplied, and returns an integer indicating which is larger, * checking for AST__BAD values. It is intended for use with the C * Run-Time-Library sorting function "qsort". * Parameters: * elem1 * Pointer to the first "double". * elem2 * Pointer to the second "double". * Returned Value: * Zero is returned if the values are equal. If the first is larger * than the second then +1 is returned. Otherwise, -1 is returned. * Notes: * - Values of AST__BAD are considered to be larger than any other * value (other than another value of AST__BAD). * - If both values are AST__BAD, then zero is returned. * - This function executes even if an error has occurred. */ /* Local Variables: */ double *delem1; /* Pointer to the first "double" value */ double *delem2; /* Pointer to the second "double" value */ int ret; /* The returned value */ /* Get pointers to the two "double" values. */ delem1 = (double *) elem1; delem2 = (double *) elem2; /* Check the values for equality (including both values being AST__BAD). */ if( *delem1 == *delem2 ){ ret = 0; /* If the first is bad, then it is considered to be larger than the second. */ } else if( *delem1 == AST__BAD ){ ret = 1; /* If the second is bad, then it is considered to be larger than the first. */ } else if( *delem2 == AST__BAD ){ ret = -1; /* If the first is larger than the second, return 1. */ } else if( *delem1 > *delem2 ){ ret = 1; /* If the first is smaller than the second, return -1. */ } else { ret = -1; } /* Return the answer. */ return ret; } static int Compare_LL( const void *elem1, const void *elem2 ){ /* * Name: * Compare_LL * Purpose: * Compare two LabelList structures as used by function PlotLabels. * Type: * Private function. * Synopsis: * #include "plot.h" * int Compare_LL( const void *elem1, const void *elem2 ) * Class Membership: * Plot method. * Description: * This function compares two "LabelList" structures as used by function * PlotLabels, and returns an integer indicating which has a larger * "index" value. This function is intended to be used with the C * Run-Time-Library sorting function "qsort". * Parameters: * elem1 * Pointer to the first LabelList. * elem2 * Pointer to the second LabelList. * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the values are equal. If the first is larger * than the second then +1 is returned. Otherwise, -1 is returned. * Notes: * - This function executes even if an error has occurred. */ /* Local Variables: */ LabelList *ll1; /* Pointer to the first LabelList */ LabelList *ll2; /* Pointer to the second LabelList */ int ret; /* The returned value */ /* Get pointers to the two LabelList structures. */ ll1 = (LabelList *) elem1; ll2 = (LabelList *) elem2; /* Compare the indices for the two label's. */ if( ll1->index < ll2->index ){ ret = -1; } else if( ll1->index > ll2->index ){ ret = 1; } else { ret = 0; } /* Return the answer. */ return ret; } static void CopyPlotDefaults( AstPlot *this, int axis, AstPlot *dplot, int daxis, int *status ){ /* *+ * Name: * astCopyPlotDefaults * Purpose: * Copy used attribute defaults from one Plot to another. * Type: * Protected virtual function. * Synopsis: * #include "plot.h" * void astCopyPlotDefaults( AstPlot *this, int axis, AstPlot *dplot, * int daxis ) * Class Membership: * Plot method. * Description: * Some of the attributes used by the Plot class have dynamic default * values that are determined during the process of drawing an annotated * grid using astGrid. The dynamic default values are stored in a * separate set of components within the Plot structure. This function * copies these components from one Plot to another. * Parameters: * this * Pointer to a Plot containing the values ot be copied. * axis * The zero-based index of the axis within "this" for which the * used defaults are to be copied. * dplot * A pointer to another Plot into which the default attribute * values are to be copied. * daxis * The zero based index of the axis within "dplot" which is to * receive the new values. *- */ /* Check the global status. */ if( !astOK ) return; dplot->ulglb[ daxis ] = this->ulglb[ axis ]; dplot->ulgtk[ daxis ] = this->ulgtk[ axis ]; dplot->uloggap[ daxis ] = this->uloggap[ axis ]; dplot->ugap[ daxis ] = this->ugap[ axis ]; dplot->ucentre[ daxis ] = this->ucentre[ axis ]; dplot->uedge[ daxis ] = this->uedge[ axis ]; dplot->ulblat[ daxis ] = this->ulblat[ axis ]; dplot->ulbunit[ daxis ] = this->ulbunit[ axis ]; dplot->umintk[ daxis ] = this->umintk[ axis ]; dplot->utxtlb[ daxis ] = this->utxtlb[ axis ]; dplot->umjtkln[ daxis ] = this->umjtkln[ axis ]; dplot->ugrid = this->ugrid; dplot->ulbling = this->ulbling; dplot->uborder = this->uborder; } static int CountGood( int n, double *data, int *status ){ /* * Name: * CountGood * Purpose: * Coount the number of non-bad values in an array. * Type: * Private function. * Synopsis: * #include "plot.h" * int CountGood( int n, double *data, int *status ) * Class Membership: * Plot method. * Description: * This function returns the number of elements in the supplied array * which do not have the value AST__BAD. * Parameters: * n * The total number of elements in the array. * data * Pointer to the start of the array. * status * Pointer to the inherited status variable. * Returned Value: * The number of good points in the array. * Notes: * - A value of zero is returned if an error has already occurred. */ /* Local Variables: */ int i; int ngood; double *value; /* Check global status. */ if( !astOK ) return 0; /* Initialise a pointer to the next array element, and the number of good elements found so far. */ value = data; ngood = 0; /* Check each element. */ for( i = 0; i < n; i++ ){ if( *(value++) != AST__BAD ) ngood++; } /* Return the answer. */ return ngood; } static int Cross( float ax, float ay, float bx, float by, float cx, float cy, float dx, float dy, int *status ){ /* * Name: * Cross * Purpose: * See if two line segments intersect. * Type: * Private function. * Synopsis: * #include "plot.h" * int Cross( float ax, float ay, float bx, float by, * float cx, float cy, float dx, float dy, int *status ) * Class Membership: * Plot method. * Description: * This function sees if the line segment (A,B) intersects the line * segment (C,D). * Parameters: * ax, ay * The coordinates of A. * bx, by * The coordinates of B. * cx, cy * The coordinates of C. * dx, dy * The coordinates of D. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the line segments do not cross or if an error has already * occurred, and 1 if they do. */ /* Local Variables: */ int ret; float m1, m2, denom, num, t1, t2; /* Check the inherited status. */ if( !astOK ) return 0; /* Get the fraction of the distance from A to B at which the line AB intersects the line CD. */ m1 = dx - cx; m2 = dy - cy; denom = (bx - ax)*m2 - (by-ay)*m1; num = (ay - cy)*m1 - (ax - cx)*m2; if( denom != 0.0 ) { t1 = num / denom; /* If the the intersection occurs within the segment of the line between A and B... */ if( t1 >= 0.0 && t1 <= 1.0 ){ /* ... then get the fraction of the distance from C to D at which the line CD intersects the line AB. */ m1 = bx - ax; m2 = by - ay; denom = (dx - cx)*m2 - (dy-cy)*m1; num = (cy - ay)*m1 - (cx - ax)*m2; if( denom != 0.0 ) { t2 = num / denom; /* If the the intersection occurs within the segment of the line between C and D then the line segments intersect. */ if( t2 >= 0.0 && t2 <= 1.0 ){ ret = 1; } else { ret = 0; } /* If the two lines are parallel, then they do not intersect. */ } else { ret = 0; } } else { ret = 0; } } else { ret = 0; } return ret; } static void Crv( AstPlot *this, double *d, double *x, double *y, int skipbad, double *box, CrvStatics *pstatics, const char *method, const char *class, int *status ){ /* * Name: * Crv * Purpose: * Draw a curve. * Type: * Private function. * Synopsis: * #include "plot.h" * void Crv( AstPlot *this, double *d, double *x, double *y, int skipbad, * double *box, CrvStatics *pstatics, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws a curve parameterised by the distance from some * starting point. The function pointed to by the external variable * Crv_map is used to transform distances along the curve into graphics * coordinates (X,Y). The supplied function parameters defined the * section of the curve to be drawn. * * The algorithm used needs no knowledge about the nature of the mapping * performed by Crv_map, and can handle discontinuities in the curve. It * first of all determines if any of the segments of the curve can be * adequately represented by simply drawing a straight line through the * supplied end points. This decision is based on several requirements such * as keeping the angle between adjacent sections low and both ends being * defined (i.e. X and Y not equal to AST__BAD). Any segments of the curve * which satisfy the requirements are draw as straight lines. If any of * the supplied curve segments cannot be drawn in this way, then they are * split up into a set of evenly-spaced sub-segments and the graphics * coordinates at the ends of these sub-segments are found using Crv_map. * This function is then called recursively to draw the sub-segments. This * recursion is limited in depth by the requirement that all the * sub-segments must be longer than a specified lower limit. If this is not * the case, then the curve is assumed to be dis-continuous and and the * sub-segments are ignored. * Parameters: * d * Pointer to an array of CRV_NPNT values giving the distance along * the curve from the starting point to each of CRV_NPNT points. They * should increase monotonically, and should be in whatever units are * used by the function pointed to by Crv_map. The curve is drawn from * d[0] to d[CRV_NPNT]. * x * Pointer to an array of CRV_NPNT values giving the graphics X * coordinate for the positions supplied in the array pointed to by * parameter "d". * y * Pointer to an array of CRV_NPNT values giving the graphics Y * coordinate for the positions supplied in the array pointed to by * parameter "d". * skipbad * Controls what happens if all the supplied points are bad or * outside the plotting area. If skipbad is non-zero, then it is * assumed that the supplied points represent an entirely bad (or * out of bounds) section of the curve, and this function will * return without attempt to sub-divide any of the supplied points. * If skipbad is zero, then it is assumed that we may be able to find * some good points between the supplied bad points, and therefore * this function will attempt to sub-divide the supplied points. * Should be supplied as zero on the initial invocation. * box * Pointer to an array of 4 doubles houlding a bounding box within * which the current segment must reside if it is to be sub-divided. * Supplied in the order xlo, xhi, ylo, yhi. May be NULL in which * case, no check is made on the bounding box. * pstatics * Pointer to a structure holding values for variables which were * statically defined within this function prior to the thread-safe * version of AST. If a NULL pointer is supplied, a new structure * is created in dynamic memory and initialised. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * External Variables: * Crv_nent = int (Read/Write) * The number of recursive entries which have been made into * this function. This should be set to zero before entering * this function for the first time. * Crv_ux0 = double (Read/Write) * The X component in graphics coordinates of the unit vector * along the previous segment of the curve. This should be set * to AST__BAD initially to indicate that the previous section * is not defined. * Crv_uy0 = double (Read/Write) * The Y component of the unit vector along the previous segment. * Crv_limit = double (Read) * The square of the maximum acceptable residual between the * drawn curve and the true curve, in graphics coordinates. * Crv_scerr = double (Read) * If the ratio of the lengths of adjacent sub-segments is larger * than Crv_scerr,then the seub-segments will be sub-divided. Note, * if either axis is mapped logarithmically onto the screen, then * there will naturally be large changes in scale. Crv_scerr should * always be larger than 1.0. * Crv_map = void (*)( int n, double *dd, double *xx, double *yy, * const char *method, const char *class ) (Read) * A pointer to a function which can be called to map "n" distances * along the curve (supplied in "dd") into graphics coordinates * (stored in "xx" and "yy"). See function "Map1" as an example. * Crv_clip = int (Read) * Should lines be clipped at the edge of the plotting area? * Notes: * - The CRV_TRACE conditional compilation blocks in this function * provide code which displays the recursive entries made to this * function (and also pauses on initial entry until return is pressed). * It is useful for investigating the details of the drawing of a * curve. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ CrvStatics *statics; /* Pointer to structure holding static values */ double *dd; /* Pointer to array holding sub-segment distances */ double *pd; /* Pointer to next sub-segment distance */ double *px; /* Pointer to next sub-segment x coord. */ double *py; /* Pointer to next sub-segment y coord. */ double *xx; /* Pointer to array holding sub-segment x coord.s */ double *yy; /* Pointer to array holding sub-segment x coord.s */ double bbox[4]; /* Bounding box for this segment */ double dl2[ CRV_NSEG ];/* Squred segment lengths */ double dx[ CRV_NSEG ]; /* X increment along each segment */ double dy[ CRV_NSEG ]; /* Y increment along each segment */ int i; /* Segment index */ int seg_ok[ CRV_NSEG ];/* Flags indicating which segments can be drawn */ int subdivide; /* Flag indicating if segments can be subdivided */ /* Check inherited status */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* If required, allocate memory for a structure to hold the static variables need by this function. */ if( ! pstatics ) { statics = astMalloc( sizeof( CrvStatics ) ); } else { statics = pstatics; } /* If this is the first entry, set up the minimum length for a sub-segment in graphics coordinates. If any segment is less than this minimum length, then recursion will stop and the curve will be assumed to be dis-continuous. */ if( !Crv_nent ) { statics->limit2 = 20.0*Crv_limit/(CRV_NSEG*CRV_NSEG); #ifdef CRV_TRACE statics->levels[ 0 ] = 0; #endif } /* Increment the number of entries into this function. */ Crv_nent++; #ifdef CRV_TRACE for( i = 0; i < Crv_nent; i++ ) { printf("%d ",statics->levels[ i ] ); } printf("\n"); if( getchar() == 'm' ) { float ffx,ffy; for( i = 0; i < CRV_NPNT; i++ ) { ffx = x[i]; ffy = y[i]; GMark( this, 1, &ffx, &ffy, 2, method, class, status ); GFlush( this, method, class, status ); } } #endif /* ====================================================================== The first section of this function sets up some arrays holding information which will be used later on. It looks at each of the segments joing adjacent tabulated points, and finds and stores the increments in X and Y along each segment, and the square of the segment length. It also checks to see if the tabulated points are all bad, or if they are all good. It also finds the lowest squared segment length. ======================================================================*/ /* Look at the first tabulated point. If it is good, set a flag to indicate that it can be used, store it as "the previous position" (i.e. the start of the current segment). Also set a flag ("all_bad") to indicate if all points looked at so far have been bad, or outside the plotting area. */ if( *x != AST__BAD && *y != AST__BAD ){ statics->last_ok = 1; statics->last_x = *x; statics->last_y = *y; statics->all_bad = ( *x < Crv_xlo || *x > Crv_xhi || *y < Crv_ylo || *y > Crv_yhi ) && Crv_clip; } else { statics->last_ok = 0; statics->all_bad = 1; } /* Initialise the bouding box for the this segment. */ bbox[ 0 ] = DBL_MAX; bbox[ 1 ] = -DBL_MAX; bbox[ 2 ] = DBL_MAX; bbox[ 3 ] = -DBL_MAX; /* Store pointers to the X and Y values for the "current position". This is the position at the end of the current segment. This is initially the second tabulated point. */ px = x + 1; py = y + 1; /* Store pointers to the increments and squared length for the current segment. */ statics->pdx = dx; statics->pdy = dy; statics->pdl2 = dl2; /* Initialise the number of long and short segments. */ statics->nlong = 0; statics->nshort = 0; /* Loop round each segment. */ for( i = 0; i < CRV_NSEG; i++ ){ /* If the tabulated point marking the end of the segment is good... */ if( *px != AST__BAD && *py != AST__BAD ){ /* Update the bounding box. */ if( *px < bbox[ 0 ] ) bbox[ 0 ] = *px; if( *px > bbox[ 1 ] ) bbox[ 1 ] = *px; if( *py < bbox[ 2 ] ) bbox[ 2 ] = *py; if( *py > bbox[ 3 ] ) bbox[ 3 ] = *py; /* If the point is within the plotting area, set the "statics->all_bad" flag to indicate that at least 1 point is within the plotting area. */ if( !Crv_clip || ( *px >= Crv_xlo && *px <= Crv_xhi && *py >= Crv_ylo && *py <= Crv_yhi ) ) statics->all_bad = 0; /* If the point marking the start of the segment was also good, find and store the increments and squared length for the segment, incrementing the pointers ready for the next segment. */ if( statics->last_ok ){ statics->t1 = *px - statics->last_x; statics->t2 = *py - statics->last_y; statics->t3 = statics->t1*statics->t1 + statics->t2*statics->t2; *(statics->pdx++) = statics->t1; *(statics->pdy++) = statics->t2; *(statics->pdl2++) = statics->t3; /* Count the number of segments which are, and are not, shorter than the minimum significant length. */ if( statics->t3 > statics->limit2 ) { statics->nlong++; } else { statics->nshort++; } /* If the start was bad, the length of the segment is not defined so store bad values. */ } else { *(statics->pdx++) = AST__BAD; *(statics->pdy++) = AST__BAD; *(statics->pdl2++) = AST__BAD; } /* The point at the end of the current segment becomes the point at the start of the next segment. */ statics->last_ok = 1; statics->last_x = *(px++); statics->last_y = *(py++); /* If the tabulated point marking the end of the current segment is bad, the segment length is undefined so store bad values. */ } else { *(statics->pdx++) = AST__BAD; *(statics->pdy++) = AST__BAD; *(statics->pdl2++) = AST__BAD; /* The point at the end of the current segment becomes the point at the start of the next segment. */ statics->last_ok = 0; px++; py++; } } /* ====================================================================== The next section of this function checks to see lines can be drawn directly through any of the tabulated points. The flags in "seg_ok" indicates if this is the case for each segment. ======================================================================*/ /* The unit vector along the previous segment is supplied in external variables Crv_ux0 and Crv_uy0. These will be AST__BAD if the direction of the previous segment is undefined. */ statics->vxl = Crv_ux0; statics->vyl = Crv_uy0; /* The length of the previous segment is initially bad. */ statics->dll = AST__BAD; /* Set up some pointers used to walk through the arrays holding the lengths of each segment. */ statics->pdl2 = dl2; statics->pdx = dx; statics->pdy = dy; /* Check each segment in turn to see if it can be drawn as a single straight line. */ for( i = 0; i < CRV_NSEG; i++ ){ /* A segment can only be drawn as a single line if both ends are good and the distance between them is not zero. */ if( *statics->pdl2 != AST__BAD && *statics->pdl2 > 0.0 ){ /* Get a unit vector in the direction of the current segment. */ statics->dl = sqrt( *statics->pdl2 ); statics->vx = *statics->pdx/statics->dl; statics->vy = *statics->pdy/statics->dl; /* If a unit vector in the direction of the previous segment is available, we check that the angle between the previous segment and the current segment is not too high. */ if( statics->vxl != AST__BAD ){ statics->cosang = statics->vxl*statics->vx + statics->vyl*statics->vy; /* If the angle is too high, set a flag to indicate that the segment cannot be drawn as a single line. Also, set the flag for the previous segment as well. */ if( statics->cosang < 0.8 || ( *statics->pdl2 )*( 1.0 - statics->cosang*statics->cosang ) > Crv_limit ) { seg_ok[ i ] = 0; if( i > 0 ) seg_ok[ i - 1 ] = 0; /* If the angle between this segment and the previous segment is not too high, check that the scale has not changed too much. */ } else { /* If the scale (=vector length) has changed a lot, set a flag to indicate that the segment cannot be drawn as a single line. Also, set the flag for the previous segment as well. */ if( statics->dll != AST__BAD && ( statics->dl < statics->dll/Crv_scerr || statics->dl > statics->dll*Crv_scerr ) ) { seg_ok[ i ] = 0; if( i > 0 ) seg_ok[ i - 1 ] = 0; /* If the orientation and scale of this segment has not changed much from the previous segment, the segment can be drawn as a straight line. */ } else { seg_ok[ i ] = 1; } } /* If no unit vector is available for the previous segment, then assume we are re-starting the curve after a discontinuity. In this case, we can draw it as a straight line. */ } else { seg_ok[ i ] = 1; } /* Save the unit vector along the current segment for use next time. */ statics->vxl = statics->vx; statics->vyl = statics->vy; /* Save the length if the current segment for use next time. */ statics->dll = statics->dl; /* If the length of the current segment is undefined, or zero, we cannot draw it as a single line. Also, there is no direction vector to pass on to the next time, so set them bad. */ } else { seg_ok[ i ] = 0; statics->vxl = AST__BAD; statics->vyl = AST__BAD; statics->dll = AST__BAD; } /* Point to the next segment. */ statics->pdl2++; statics->pdx++; statics->pdy++; } /* Do not allow isolated segments to be OK. If a segment is flagged as being OK, but both its neighbours are not OK, set the segment not OK as well. */ statics->seg0 = seg_ok + 1; statics->segm = seg_ok; statics->segp = seg_ok + 2; if( !(*statics->seg0) ) *statics->segm = 0; for( i = 1; i < CRV_NSEG - 1; i++ ){ if( !(*statics->segm) && !(*statics->segp) ) *statics->seg0 = 0; statics->seg0++; statics->segm++; statics->segp++; } if( !(*statics->segm) ) *statics->seg0 = 0; /* ====================================================================== The next section of this function draws the curve. Each segment is drawn as a straight line if the corresponding flag in "seg_ok" is set. Segments for which the flag is not set are drawn by calling this function recursivly. ======================================================================*/ /* Get the parametric length (i.e. the increment in "d") of the sub-segments within each subdivided segment. */ statics->delta = ( d[ CRV_NSEG ] - d[ 0 ] )/(double)( CRV_NSEG*CRV_NSEG ); /* If we have made the maximum number of recursive entries into this function, or if every supplied point was bad or outside the plotting area, or if most of the segments were very short in graphics space, we will not be attempting to subdivide any segments which cannot be drawn directly as a straight line. If "skipbad" was supplied as zero, we ignore the restriction which says that we must have some good points (since we may find some good poits by a further sub-division). */ subdivide = ( Crv_nent < CRV_MXENT && ( !statics->all_bad || !skipbad ) && statics->nlong > statics->nshort ); /* We do not sub-divide if the bounding box of the supplied points is not at least 10% smaller than the supplied bouding box on either axis. */ if( box && bbox[ 0 ] != DBL_MAX ) { if( bbox[ 1 ] - bbox[ 0 ] > 0.9*( box[ 1 ] - box[ 0 ] ) && bbox[ 3 ] - bbox[ 2 ] > 0.9*( box[ 3 ] - box[ 2 ] ) ) { subdivide = 0; } } /* Initialise some pointers to the data defineding the subsegments. */ dd = NULL; xx = NULL; yy = NULL; /* If we may be subdividing any segments, find which segments they are and set up the offset to each sub-segment. */ if( subdivide ){ /* Initialise the number of segments being subdivided. */ statics->nseg = 0; /* Loop round each segment. */ for( i = 0; i < CRV_NSEG; i++ ){ /* If the segment cannot be drawn directly as a straight line, we will subdivide it. */ if( !seg_ok[ i ] ){ /* Increment the number of segments being subdivided, and let the array of subsegment offsets grow to accomodate it. */ statics->nseg++; dd = (double *) astGrow( dd, statics->nseg, sizeof(double)*( CRV_NSEG + 1 ) ); if( !astOK ) break; /* Append the offset to each new subsegment to the "dd" array. */ statics->el = ( statics->nseg - 1 )*( CRV_NSEG + 1 ); statics->d0 = d[ i ]; for( statics->j = 0; statics->j <= CRV_NSEG; statics->j++ ){ dd[ statics->el++ ] = statics->d0; statics->d0 += statics->delta; } } } /* If any segments needed subdividing, get room to store the graphics coordinates at each point, and then fill these arrays by calling Crv_map to map the offsets in "dd" into graphics coordinates. */ if( statics->nseg > 0 ){ statics->nel = statics->nseg*( CRV_NSEG + 1 ); xx = (double *) astMalloc( sizeof(double)*(size_t)statics->nel ); yy = (double *) astMalloc( sizeof(double)*(size_t)statics->nel ); Crv_map( statics->nel, dd, xx, yy, method, class, status GLOBALS_NAME ); } } /* If all has gone OK, we will draw each segment. Initialise pointers used to walk through the "xx", "yy" and "dd" arrays. */ if( astOK ){ px = xx; py = yy; pd = dd; /* Draw each segment in turn. */ for( i = 0; i < CRV_NSEG; i++ ){ /* If possible, draw it as a single straight line, and then store the unit vector along the line in the appropriate external variables for use by the next invocation of this function. */ if( seg_ok[ i ] ){ CrvLine( this, x[ i ], y[ i ], x[ i + 1 ], y[ i + 1 ], method, class, status ); statics->dl = sqrt( dl2[ i ] ); Crv_ux0 = dx[ i ]/statics->dl; Crv_uy0 = dy[ i ]/statics->dl; /* Otherwise, if we are subdividing, and if the current segment is not very short, we call this function recursively to draw the segment. Increment pointers into the "xx", "yy" and "dd" arrays so that they point to the start of the subsegment information for the next segment to be subdivided. If all the graphics positions at this level were bad or outside the plot, tell the next invocation of Crv to do no further sub-divisions if it too finds all graphics positions to be bad or outside the plot. */ } else if( subdivide ) { #ifdef CRV_TRACE statics->levels[ Crv_nent ] = i; #endif Crv( this, pd, px, py, statics->all_bad, bbox, statics, method, class, status ); pd += CRV_NSEG + 1; px += CRV_NSEG + 1; py += CRV_NSEG + 1; /* Otherwise, we assume we have hit a discontinuity in the curve. Store bad values for the unit vector along the previous sgment, and do not draw anything. */ } else { Crv_ux0 = AST__BAD; Crv_uy0 = AST__BAD; } } } /* Free any memory used to store subsegment information. */ if( dd ) dd = (double *) astFree( (void *) dd ); if( xx ) xx = (double *) astFree( (void *) xx ); if( yy ) yy = (double *) astFree( (void *) yy ); /* Decrement the number of recursive entries into this function. */ Crv_nent--; /* Free the memory holding the static data values if we are leaving the final entry. */ if( ! pstatics ) statics = astFree( statics ); /* Return. */ return; } static int CvBrk( AstPlot *this, int ibrk, double *brk, double *vbrk, double *len, int *status ){ /* *+ * Name: * astCvBrk * Purpose: * Return information about breaks in the last curve drawn by astGridLine, * astCurve or astGenCurve. * Type: * Protected virtual function. * Synopsis: * #include "plot.h" * int CvBrk( AstPlot *this, int ibrk, double *brk, double *vbrk, * double *len ) * Class Membership: * Plot method. * Description: * Curves drawn by astGridLine, astCurve or astGenCurve may contain breaks * for several reasons (for instance, it may go outside the plotting area, * or the mapping between physical and graphics coordinates may be * discontinuous). This function returns information about such breaks. * Parameters: * this * Pointer to a Plot. * ibrk * The index of the break for which information is required. The first * break has index 1. An error is reported if no break with the * required index exists. The exception to this is that zero can be * supplied, in which case the "brk" and "vbrk" parameters * are ignored, but all other information is returned. * brk * A pointer to an array of 2 elements * in which to return the X and Y graphics coordinates of the break. * vbrk * A pointer to an array of 2 elements * in which to return the X and Y components of a unit vector in the * graphics coordinate system. The vector is tangential to the curve * at the requested break, and points back along the drawn section of * the curve. * len * A pointer to a "double" in which to return the * length of the drawn curve, in the graphics coordinate system. * Returned Value: * astCvBrk() * The number of breaks which occurred in the curve. * Notes: * - Currently, this function may not be used to return information * about curves drawn using astPolyCurve. * - All curves contain at least two breaks; one at the start and one * at the end. This is true even if the start and end of the curve are * coincident. However, if the entire curve was outside the plotting area * (i.e. if the length of the drawn curve is zero), then it will have no * breaks. * - If no curve has yet been drawn by astGridLine or astCurve, then -1 is * returned for the function value, and the function parameter values are * left unchanged. * - The returned information refers to the most recent curve drawn by * astGridLine or astCurve, even if that curve was drawn by a Plot other than * the one supplied to this function. * - NULL pointers may be supplied for "brk", "vbrk" or "len", in which * case the corresponding values are not returned. * - Zero is returned by this function if an error has already occurred, * or if this function should fail for any reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int ret; /* The number of breaks in the curve. */ /* Check the global status. */ if( !astOK ) return 0; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Information about the most recent curve drawn by astGridLine or astCurve is stored in the external structure "Curve_data". Get the number of breaks in the last curve. This is initialised to -1 in astInitPlot when the virtual function table for this class is initialised. */ ret = Curve_data.nbrk; /* If a curve has been drawn, store the length of the drawn curve if required. */ if( ret != -1 ){ if( len ) *len = (double) Curve_data.length; /* If a legal break index has been supplied, return the position and direction at the requested break (if required). */ if( ibrk > 0 && ibrk <= ret ){ if( brk ){ brk[ 0 ] = (double) Curve_data.xbrk[ ibrk - 1 ]; brk[ 1 ] = (double) Curve_data.ybrk[ ibrk - 1 ]; } if( vbrk ){ vbrk[ 0 ] = (double) Curve_data.vxbrk[ ibrk - 1 ]; vbrk[ 1 ] = (double) Curve_data.vybrk[ ibrk - 1 ]; } /* If an illegal break index has been supplied (other than zero), report an error, and set the number of breaks to zero. */ } else if( ibrk ){ if( ret > 0 ){ astError( AST__BDBRK, "astCvBrk(%s): The supplied break index " "(%d) should be in the range [1,%d].", status, astGetClass(this), ibrk, ret ); ret = 0; } else { astError( AST__BDBRK, "astCvBrk(%s): The most recent curve " "plotted by method astGridLine or astCurve had no breaks.", status, astGetClass(this) ); } } } /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the result. */ return ret; } static void CrvLine( AstPlot *this, double xa, double ya, double xb, double yb, const char *method, const char *class, int *status ){ /* * Name: * CrvLine * Purpose: * Draw a straight line between two points, with clipping. * Type: * Private function. * Synopsis: * #include "plot.h" * void CrvLine( AstPlot *this, double xa, double ya, double xb, double yb, * const char *method, const char *class ) * Class Membership: * Plot member function. * Description: * This functions draws a straight line from (xa,ya) to (xb,yb), breaking * the line at the edges of the plotting area defined by Crv_xlo, Crv_xhi, * Crv_ylo and Crv_yhi if Crv_clip is non-zero. If the line does not start * at the end of the previous line plotted by this function, then * information describing the break in the curve is stored in external * arrays. * Parameters: * xa * The graphics X coordinate at the start of the line. * ya * The graphics Y coordinate at the start of the line. * xb * The graphics X coordinate at the end of the line. * yb * The graphics Y coordinate at the end of the line. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * External Variables: * Crv_ink = int (Read) * If zero then no line is drawn even if the line intersects the * plotting space, but break information (etc) is still returned. * Crv_clip = double (Read) * Clip lines at boundary of plotting space? * Crv_xlo = double (Read) * Lower x limit of the plotting space. * Crv_xhi = double (Read) * Upper x limit of the plotting space. * Crv_ylo = double (Read) * Lower y limit of the plotting space. * Crv_yhi = double (Read) * Upper y limit of the plotting space. * Crv_tol = double (Read) * The tolerance for determining if 2 points are coincident. * Crv_out = int (Read/Write) * Returned as zero if the line intersects the plotting space. * Unchanged otherwise. * Crv_xbrk = float * (Read/Write) * Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK * values containing the graphics X coordinates at which each break * in the plotted curve occurred. A break is recorded if the starting * point of the current line is not the same as the end point of * the previous line. * Crv_ybrk = float * (Read/Write) * Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK * values containing the graphics Y coordinates at which each break * in the plotted curve occurred. * Crv_vxbrk = float * (Read/Write) * Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK * values containing the X component of the unit vector (within the * graphics coordinate system) parallel to the tangent to the curve * at each break. The sense is such that the vector always points back * along the plotted section of the curve. * Crv_vybrk = float * (Read/Write) * Pointer to the next available element in an array of AST__PLOT_CRV_MXBRK * values containing the Y component of the unit vector parallel to * the tangent to the curve at each break. * Crv_nbrk = int (Write) * The number of breaks for which information is returned in Crv_xbrk, * etc. * Crv_len = float (Write) * The length of the section of the curve which has been drawn so far. * Crv_xl = double (Write) * The graphics X coordinate at the end of the last line drawn. * Crv_yl = double (Write) * The graphics Y coordinate at the end of the last line drawn. * Crv_vxl = double (Write) * The X component of the unit vector along the last line drawn. * Crv_vyl = double (Write) * The Y component of the unit vector along the last line drawn. * Grf_alpha = float (Read) * The factor for scaling graphics X axis values into equal scaled * X axis values. * Grf_beta = float (Read) * The factor for scaling graphics Y axis values into equal scaled * Y axis values. */ /* local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double a1; /* Distance from B to the lower x boundary */ double a2; /* Distance from B to the upper x boundary */ double a3; /* Distance from B to the lower y boundary */ double a4; /* Distance from B to the upper y boundary */ double aamax; /* Distance from supplied point B to the plotable point A */ double aamin; /* Distance from supplied point B to the plotable point B */ double dl; /* Length of plotted line segment */ double dx; /* Difference in x between supplied points */ double dy; /* Difference in y between supplied points */ double t; /* Temporary storage */ double xam; /* Modified xa position */ double xbm; /* Modified xb position */ double yam; /* Modified ya position */ double ybm; /* Modified yb position */ int plot; /* True if a line can be plotted */ /* Check inherited global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ dl = 0.0; xam = 0.0; xbm = 0.0; yam = 0.0; ybm = 0.0; /* Store the shifts in x and y. */ dx = xb - xa; dy = yb - ya; /* Do nothing if the line is of zero length. */ if( dx == 0.0 && dy == 0.0 ) return; /* If either end is outside the zone, replace the given coordinates with the end coordinates of the section of the line which lies within the zone. */ if( Crv_clip && ( xa < Crv_xlo || xa > Crv_xhi || xb < Crv_xlo || xb > Crv_xhi || ya < Crv_ylo || ya > Crv_yhi || yb < Crv_ylo || yb > Crv_yhi ) ){ /* Find the distance from point B towards point A at which the line cuts the two x bounds of the zone (distance at point B is 0.0, and at point A is 1.0). */ if( dx != 0.0 ){ a1 = ( xb - Crv_xlo )/dx; a2 = ( xb - Crv_xhi )/dx; /* Ensure that a1 represents the highest plottable offset, and a2 the lowest. */ if( a1 < a2 ){ t = a1; a1 = a2; a2 = t; } /* If the line joining A and B is vertical... */ } else { /* If the line is within the plottable x range, indicate that all offsets are plottable (as far as the x range is concerned at least). */ if( ( xa > Crv_xlo || EQUAL( xa, Crv_xlo ) ) && ( xa < Crv_xhi || EQUAL( xa, Crv_xhi ) ) ){ a1 = DBL_MAX; a2 = -DBL_MAX; /* If the line is ouside the plottable x range, indicate that no offsets are plottable. */ } else { a1 = 0.0; a2 = 0.0; } } /* Find the fractional distance from point A to point B at which the line cuts the two y bounds of the zone. */ if( dy != 0.0 ){ a3 = ( yb - Crv_ylo )/dy; a4 = ( yb - Crv_yhi )/dy; /* Ensure that a3 represents the highest plottable offset, and a4 the lowest. */ if( a3 < a4 ){ t = a3; a3 = a4; a4 = t; } /* If the line joining A and B is horizontal... */ } else { /* If the line is within the plottable y range, indicate that all offsets are plottable (as far as the y range is concerned at least). */ if( ( ya > Crv_ylo || EQUAL( ya, Crv_ylo ) ) && ( ya < Crv_yhi || EQUAL( ya, Crv_yhi ) ) ){ a3 = DBL_MAX; a4 = -DBL_MAX; /* If the line is ouside the plottable y range, indicate that no offsets are plottable. */ } else { a3 = 0.0; a4 = 0.0; } } /* Find the fractional distances from point A to point B at the ends of the plotable line. */ aamin = MIN( 1.0, MAX( 0.0, MAX( a2, a4 ) ) ); aamax = MAX( 0.0, MIN( 1.0, MIN( a1, a3 ) ) ); /* Store the end coordinates of the line joining the plotable points. */ if( aamax > aamin ){ xam = xb - aamax*dx; yam = yb - aamax*dy; xbm = xb - aamin*dx; ybm = yb - aamin*dy; plot = 1; /* Get the unit vector along the line and the length of the plotted section. */ dx *= Grf_alpha; dy *= Grf_beta; dl = sqrt( dx*dx + dy*dy ); dx /= dl; dy /= dl; dl *= MAX( 0.0, aamax - aamin ); /* Clear the "plot" flag if the line does not intersect the plotting area. */ } else { plot = 0; } /* If both ends of the line are within the plotting zone, draw the whole line between the supplied end points. */ } else { xam = xa; yam = ya; xbm = xb; ybm = yb; plot = 1; /* Get the length of the line and the unit vector along the line. */ dx *= Grf_alpha; dy *= Grf_beta; dl = sqrt( dx*dx + dy*dy ); dx /= dl; dy /= dl; } /* If a line is to be plotted... */ if( plot ){ /* If this is the first line to be plotted in the current curve, save the start of the line as a break, and indicate that some of the curve falls within the plotting zone. */ if( Crv_out ){ Crv_nbrk = 1; *(Crv_xbrk++) = (float) xam; *(Crv_ybrk++) = (float) yam; *(Crv_vxbrk++) = (float) dx; *(Crv_vybrk++) = (float) dy; Crv_out = 0; /* Set the length of the curve plotted so far to the length of this first segment. */ Crv_len = (float) dl; /* Start a poly line. */ if( Crv_ink ) Bpoly( this, (float) xam, (float) yam, status ); /* If this is not the first line to be plotted... */ } else { /* ... increment the length of the curve plotted so far. */ Crv_len += (float) dl; /* If the start of this line is not coincident with the end of the previous line, save the previous and current positions as breaks in the curve. Note, the previous vector is reversed so that it points back towards the drawn section of the curve. Report an error if the arrays are full. */ if( fabs( xam - Crv_xl ) > Crv_tol || fabs( yam - Crv_yl ) > Crv_tol ){ Crv_nbrk += 2; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in plotted " "curve exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; *(Crv_xbrk++) = (float) xam; *(Crv_ybrk++) = (float) yam; *(Crv_vxbrk++) = (float) dx; *(Crv_vybrk++) = (float) dy; } /* Start a poly line. */ if( Crv_ink ) Bpoly( this, (float) xam, (float) yam, status ); } } /* Append a section to the current poly line. */ if( Crv_ink ) Apoly( this, (float) xbm, (float) ybm, status ); /* Save the position and vector at the end of the current line. */ Crv_xl = xbm; Crv_yl = ybm; Crv_vxl = dx; Crv_vyl = dy; } /* Return. */ return; } static void Curve( AstPlot *this, const double start[], const double finish[], int *status ){ /* *++ * Name: c astCurve f AST_CURVE * Purpose: * Draw a geodesic curve. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astCurve( AstPlot *this, const double start[], c const double finish[] ) f CALL AST_CURVE( THIS, START, FINISH, STATUS ) * Class Membership: * Plot method. * Description: c This function draws a geodesic curve between two points in the f This routine draws a geodesic curve between two points in the * physical coordinate system of a Plot. The curve drawn is the * path of shortest distance joining the two points (as defined by c the astDistance function for the current Frame of the Plot). f the AST_DISTANCE function for the current Frame of the Plot). * For example, if the current Frame is a basic Frame, then the * curve joining the two points will be a straight line in physical * coordinate space. If the current Frame is more specialised and * describes, for instance, a sky coordinate system, then the * geodesic curve would be a great circle in physical coordinate * space passing through the two sky positions given. * * Note that the geodesic curve is transformed into graphical * coordinate space for plotting, so that a straight line in * physical coordinates may result in a curved line being drawn if * the Mapping involved is non-linear. Any discontinuities in the * Mapping between physical and graphical coordinates are c catered for, as is any clipping established using astClip. f catered for, as is any clipping established using AST_CLIP. * c If you need to draw many geodesic curves end-to-end, then the c astPolyCurve function is equivalent to repeatedly using c astCurve, but will usually be more efficient. f If you need to draw many geodesic curves end-to-end, then the f AST_POLYCURVE routine is equivalent to repeatedly calling f AST_CURVE, but will usually be more efficient. * c If you need to draw curves which are not geodesics, see astGenCurve c or astGridLine. f If you need to draw curves which are not geodesics, see AST_GENCURVE f or AST_GRIDLINE. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c start f START( * ) = DOUBLE PRECISION (Given) * An array, with one element for each axis of the Plot, giving * the physical coordinates of the first point on the geodesic * curve. c finish f FINISH( * ) = DOUBLE PRECISION (Given) * An array, with one element for each axis of the Plot, giving * the physical coordinates of the second point on the geodesic * curve. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - No curve is drawn if either of the "start" or "finish" arrays c contains any coordinates with the value AST__BAD. f - No curve is drawn if either of the START or FINISH arrays f contains any coordinates with the value AST__BAD. * - An error results if the base Frame of the Plot is not 2-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ const char *class; /* Object class */ const char *method; /* Current method */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astCurve"; class = astGetClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Initialise the bounding box for primitives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Draw the curve. The break information is stored in an external structure where it can be accessed by public methods which return information about the most recently drawn curve. */ CurvePlot( this, start, finish, 1, &Curve_data, method, class, status ); /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); /* Return. */ return; } static void CurvePlot( AstPlot *this, const double *start, const double *finish, int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ){ /* * * Name: * CurvePlot * Purpose: * Draw a geodesic curve. * Type: * Private function. * Synopsis: * #include "plot.h" * void CurvePlot( AstPlot *this, const double *start, const double *finish, * int ink, AstPlotCurveData *cdata, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws a geodesic curve between the supplied starting and * finishing positions. The algorithm used can handle discontinuities in the * Mapping between the current Frame and graphics coordinates, and * information describing any breaks in the curve (including the start and * end of the curve) are returned in the supplied AstPlotCurveData structure. * Parameters: * this * Pointer to the Plot. * start * A pointer to a an array holding the coordinates of the start of the * curve within the current Frame of the Plot. * finish * A pointer to a an array holding the coordinates of the finish of the * curve within the current Frame of the Plot. * ink * If zero, the curve is not actually drawn, but information about * the breaks is still returned. If non-zero, the curve is also drawn. * cdata * A pointer to a structure in which to return information about the * breaks in the curve. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - No curve is draw if the "start" or "finish" arrays contains any bad * values, or if a NULL pointer is supplied for "cdata". No errors are * reported in these cases. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ double tol; /* Absolute tolerance value */ int i; /* Loop count */ int naxes; /* No. of axes in the base Frame */ int ok; /* Are all start coords good? */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Get the number of axes in the current Frame. */ naxes = astGetNout( this ); /* Check the "start" and "finish" parameter for bad values. */ ok = 1; for( i = 0; i < naxes; i++ ) { if( start[ i ] == AST__BAD || finish[ i ] == AST__BAD ){ ok = 0; break; } } /* Check that the "cdata" pointer can be used. */ if( !cdata ) ok = 0; /* Only proceed if the parameters are OK, and there has been no error. */ if( ok && astOK ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Set up the externals used to communicate with the Map3 function... The number of axes in the physical coordinate system (i.e. the current Frame). */ Map3_ncoord = naxes; /* A pointer to the Plot, the Curretn Frame, and and Mapping. */ Map3_plot = this; Map3_frame = astGetFrame( this, AST__CURRENT ); Map3_map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* The physical coordinates at the start of the curve. */ Map3_origin = start; /* The physical coordinates at the end of the curve. */ Map3_end = finish; /* The scale factor to convert "dist" values into physical offset values. */ Map3_scale = astDistance( Map3_frame, start, finish ); /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Now set up the external variables used by the Crv and CrvLine function. */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_ux0 = AST__BAD; Crv_tol = tol; Crv_limit = 0.5*tol*tol; Crv_map = Map3; Crv_ink = ink; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_out = 1; Crv_xbrk = cdata->xbrk; Crv_ybrk = cdata->ybrk; Crv_vxbrk = cdata->vxbrk; Crv_vybrk = cdata->vybrk; Crv_clip = astGetClip( this ) & 1; /* Set up a list of points spread evenly over the curve. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Map these points into graphics coordinates. */ Map3( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map3 to draw the curve. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* End the current poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map3. */ Map3( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* If no part of the curve could be drawn, set the number of breaks and the length of the drawn curve to zero. */ if( Crv_out ) { Crv_nbrk = 0; Crv_len = 0.0F; /* Otherwise, add an extra break to the returned structure at the position of the last point to be plotted. */ } else { Crv_nbrk++; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; } } /* Store extra information about the curve in the returned structure, and purge any zero length sections. */ if( cdata ){ cdata->length = Crv_len; cdata->out = Crv_out; cdata->nbrk = Crv_nbrk; PurgeCdata( cdata, status ); } /* Annul the Frame and Mapping. */ Map3_frame = astAnnul( Map3_frame ); Map3_map = astAnnul( Map3_map ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); } /* Return. */ return; } static AstPointSet *DefGap( AstPlot *this, double *gaps, int *ngood, double *frac, int *inval, const char *method, const char *class, int *status ){ /* * Name: * DefGap * Purpose: * Find default gap sizes for the tick marks on the axes of a 2-D * physical coordinate system. * Type: * Private function. * Synopsis: * #include "plot.h" * AstPointSet *DefGap( AstPlot *this, double *gaps, int *ngood, * double *frac, int *inval, const char *method, * const char *class, int *status ) * Class Membership: * Plot method. * Description: * This function returns default gap sizes for each axis in a 2-D Frame. * The values are found by first obtaining a grid of points spread over * the region containing good physical coordinates. The physical * coordinate values (non-normalized) for each axis are sorted into * increasing order. * * For linearly spaced tick marks, a set of quantile axis values is then * found, and the median of the gaps between these quantiles is returned * as the default gap for the axis. * * For logarithmically spaced tick marks, the returned gap size is the * ratio between adjacent tick mark values, chosen to give an optimal * number of ticks between the maximum and minimum axis values found in * the grid. * Parameters: * this * Pointer to a Plot. * gaps * Pointer to an array in which to return the default gap value for * each axis. * ngood * Pointer to an array in which toi return the number of good * values in the returned PointSet for each axis. * frac * Pointer to a double in which to return the fraction of the * plotting area containing good physical coordinates. * inval * Pointer to a location at which to return a flag indicating if * any bad physical coordinates were encountered. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a PointSet holding the physical coordinate values at a * set of points spread across the plotting area. The values on each * axis are sorted into increasing order. The values will not have * been normalized. * Notes: * - The returned PointSet should be annulled when no longer needed. * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - Gap sizes of 1.0, zero good points, and a NULL pointer are returned * if an error has already occurred, or if this function should fail for * any reason. */ /* Local Variables: */ AstPointSet *pset1; /* Pointer to PointSet holding graphics coords */ AstPointSet *pset2; /* Pointer to PointSet holding physical coords */ double **ptr1; /* Pointer to graphics axis values */ double **ptr2; /* Pointer to physical axis values */ double dran; /* Dynamic range */ double maxv; /* Maximum axis value */ double minv; /* Minimum axis value */ double qgap[ MAJTICKS_OPT ];/* Gaps between physical coordinate quantiles */ int dim; /* Dimension of grid */ int dk; /* The number of points between quantiles */ int i; /* The quantile index */ int j; /* Axis index */ int k; /* Index into the sorted array of axis values */ int logticks; /* Logarithmically spaced tick marks? */ int n; /* Target number fo ticks */ int psize; /* Total number of axis value */ /* Initialise the returned values. */ gaps[ 0 ] = 1.0; gaps[ 1 ] = 1.0; ngood[ 0 ] = 0; ngood[ 1 ] = 0; *frac = 0.0; *inval = 0; /* Check global status. */ if( !astOK ) return NULL; /* Get two PointSets, one holding a grid of 2D graphics coordinates, and one holding the corresponding (non-normalized) physical coordinates. */ dim = 0; *frac = GoodGrid( this, &dim, &pset1, &pset2, method, class, status ); /* Get pointers to the data values in each PointSet. */ ptr1 = astGetPoints( pset1 ); ptr2 = astGetPoints( pset2 ); /* Store the number of elements in each PointSet. */ psize = astGetNpoint( pset1 ); /* For each axis... */ for( j = 0; j < 2 && astOK; j++ ){ /* Sort the axis values into increasing order. Any bad values are stored at the end of the array on return. */ qsort( (void *) ptr2[ j ], (size_t) psize, sizeof(double), Compared ); /* Count the number of non-bad values returned. */ ngood[ j ] = CountGood( psize, ptr2[ j ], status ); /* Set the returned flag to indicate if any bad values were found. */ if( ngood[ j ] < psize ) *inval = 1; /* Report an error if there are too few good points. */ if( ngood[ j ] < MAJTICKS_OPT ){ astError( AST__VSMAL, "%s(%s): The range of coordinate values " "covered by axis %d is too small to plot.", status, method, class, j + 1 ); break; } /* Get the maximum and minimum axis value */ minv = ptr2[ j ][ 0 ]; maxv = ptr2[ j ][ ngood[ j ] - 1 ]; /* See if ticks on this axis are spaced linearly or logarithmically. If a value has been set for LogTicks used it, otherwise find a default value. The default is 0 unless LogPlot is non-zero, the axis range does not encompass zero and and the dynamic range is 90 or more. Set this default value explicitly so that later functions will pick it up (it will be cleared at the end of the astGrid function). */ if( astTestLogTicks( this, j ) ) { logticks = astGetLogTicks( this, j ); } else { logticks = 0; if( astGetLogPlot( this, j ) && minv*maxv > 0.0 ) { dran = maxv/minv; if( dran >= 90.0 || dran <= 1.0/90.0 ) logticks = 1; } astSetLogTicks( this, j, logticks ); } /* If no value has been supplied for LogLabel use the value of LogTicks as the default. */ if( !astTestLogLabel( this, j ) ) astSetLogLabel( this, j, logticks ); /* For linear gaps, find the gaps between adjacent evenly spaced quantiles. The number of quantiles used equals the optimal number of major tick marks. */ if( !logticks ) { dk = (int)( (double)ngood[ j ]/MAJTICKS_OPT ); i = 0; for( k = dk; k < ngood[ j ] && i < MAJTICKS_OPT; k += dk ){ qgap[ i++ ] = ptr2[ j ][ k ] - ptr2[ j ][ k - dk ]; } /* Find the median of the gaps between adjacent quantiles. */ qsort( (void *) qgap, (size_t) i, sizeof(double), Compared ); gaps[ j ] = qgap[ i/2 ]; /* If the test gap size is zero, use a fraction of the total range. Report an error if the total range is zero. */ if( gaps[ j ] <= 0.0 ){ gaps[ j ] = ( ptr2[ j ][ ngood[ j ] - 1 ] - ptr2[ j ][ 0 ] )/MAJTICKS_OPT;; if( gaps[ j ] <= 0.0 ){ astError( AST__VSMAL, "%s(%s): The range of coordinate values " "covered by axis %d is too small to plot.", status, method, class, j + 1 ); } } /* For logarithmic gaps, use the Nth root of the ratio of the maximum and minimum data value found. */ } else if( astOK ) { /* Report an error if the max and min values are of opposite signs or zero or equal. */ if( maxv*minv <= 0.0 ) { astError( AST__ZERAX, "%s(%s): The range of coordinate values " "covered by axis %d includes the origin and so " "logarithmic ticks cannot be produced.", status, method, class, j + 1 ); } else if( maxv == minv ) { astError( AST__VSMAL, "%s(%s): The range of coordinate values " "covered by axis %d is too small to plot.", status, method, class, j + 1 ); /* Otherwise find the gap to use. */ } else { /* Store the maximum and minimum number of major tick marks along each axis. These numbers are reduced if only a small part of the plotting area contains valid coordinates, so that the tick marks do not end up to close together. */ n = (int) ( 0.5 + MAJTICKS_OPT*sqrt( *frac ) ); if( n < 5 ) n = 5; /* Choose a gap size which makes this many gaps. */ gaps[ j ] = pow( maxv/minv, 1.0/( n - 1.0 ) ); } } } /* Annul the PointSet holding Graphics coordinates. */ pset1 = astAnnul( pset1 ); /* If an error has occurred, annul the PointSet holding physical coordinates, and return gaps of 1.0. */ if( !astOK ) { pset2 = astAnnul( pset2 ); gaps[ 0 ] = 1.0; gaps[ 1 ] = 1.0; ngood[ 0 ] = 0; ngood[ 1 ] = 0; *frac = 0.0; *inval = 0; } /* Return the physical PointSet. */ return pset2; } static void DrawAxis( AstPlot *this, TickInfo **grid, double *labelat, double *gap, const char *method, const char *class, int *status ){ /* * * Name: * DrawAxis * Purpose: * Draw a curve joining the major tick marks. * Type: * Private function. * Synopsis: * #include "plot.h" * void DrawAxis( AstPlot *this, TickInfo **grid, double *labelat, * double *gap, const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws a curve through interior tick marks on both axes. * The curve is drawn even if it has already been drawn as part of a * grid of curves, because it may have been assigned different graphics * attributes to the grid curves. * Parameters: * this * A pointer to the Plot. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick marks on the axis. See function GridLines. * labelat * A pointer to a 2 element array giving the constant axis values at * which tick marks are put. Element 0 should give the axis 1 value at * which tick marks for axis 0 are placed. Element 1 should give the * axis 0 value at which tick marks for axis 1 are placed. * gap * Pointer to array of two values holding the gap between major * tick marks on the two axes. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This function assumes the current Frame of the Plot is 2 * dimensional, and it should not be called if this is not the case. */ /* Local Variables: */ AstFrame *frm; /* Pointer to current Frame */ AstPlotCurveData cdata;/* Somewhere to put the unneeded curve information */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ double *value; /* Current tick value */ double bot; /* Lowest axis value to be displayed */ double diff; /* Difference between adjacent tick marks */ double udiff; /* Used section length */ double start[ 2 ]; /* The start of the curve in physical coordinates */ double tmp; /* Temporary storage */ double top; /* Highest axis value to be displayed */ int axis; /* Current axis index */ int axisid; /* ID value for current axis plotting attributes */ int logticks; /* Are major ticks spaced logarithmically? */ int tick; /* Current tick index */ /* Check the global status. */ if( !astOK ) return; /* Not the id value for the first axis. */ axisid = AST__AXIS1_ID; /* Get a pointer to the current Frame. */ frm = astGetFrame( this, AST__CURRENT ); /* Consider drawing a curve parallel to each axis in turn. */ for( axis = 0; axis < 2; axis++ ){ /* Establish the correct graphical attributes for this axis as defined by attributes with the supplied Plot. */ astGrfAttrs( this, axisid, 1, GRF__LINE, method, class ); /* Check the axis is required. */ if( astGetDrawAxes( this, axis ) ){ /* If the tick marks have been placed round the edges of the plotting area, we do not need to draw the curves. */ if( labelat[ axis ] != AST__BAD ){ /* Get the max and min values allowed on this axis. */ bot = astGetBottom( frm, axis ); top = astGetTop( frm, axis ); if( bot > top ) { tmp = top; top = bot; bot = tmp; } /* Get a pointer to the structure containing information describing the positions of the major tick marks along the current axis. */ info = grid[ axis ]; /* Get a pointer to the axis value at the first major tick mark. */ value = info->ticks; /* See if the major tick marks are logarithmically spaced on this axis. */ logticks = astGetLogTicks( this, axis ); /* Initialise the difference between major tick marks. */ diff = logticks ? 0.0 : gap[ axis ]; /* Loop round all ticks. */ for( tick = 0; tick < info->nmajor; tick++, value++ ){ /* Update the difference between major tick marks if we are producing logarithmically spaced ticks (in which "gap" is a ratio, not a difference). */ if( logticks ) diff = (*value)*( gap[ axis ] - 1.0 ); /* Note the starting point for this section. */ start[ axis ] = *value; start[ 1 - axis ] = labelat[ axis ]; /* If this is the first tick, draw an axis section going "backwards" in case the first tick isn't at the lower visible bound. Limit the length of this backwards section so that it does not extend beyond the minimum axis value. */ if( tick == 0 ) { udiff = *value - bot; if( udiff > diff ) udiff = diff; if( udiff > 0.0 ) { AxPlot( this, axis, start, -udiff, 1, &cdata, method, class, status ); } } /* Limit the length of the section so that it does not extend beyond the maximum axis value. */ udiff = ( *value + diff > top ) ? top - *value : diff; /* Do not draw zero length sections. */ if( udiff > 0.0 ) { /* Draw a curve parallel to the current axis, starting at the tick mark, with length equal to the gap between tick marks. Do not draw sections of the curve which are outside the primary domains of the physical axes. */ AxPlot( this, axis, start, udiff, 1, &cdata, method, class, status ); } } /* Once the last section has been drawn, draw another axis section in case the last tick isn't at the upper visible bound. Limit the length of this section so that it does not extend beyond the maximum axis value. */ udiff = top - start[ axis ]; if( udiff > diff ) udiff = diff; if( udiff > 0.0 ) { AxPlot( this, axis, start, udiff, 1, &cdata, method, class, status ); } } } /* Re-establish the original graphical attributes. */ astGrfAttrs( this, axisid, 0, GRF__LINE, method, class ); /* Set up the id value for the next axis. */ axisid = AST__AXIS2_ID; } /* Free the pointer to the current Frame. */ frm = astAnnul( frm ); } static AstPlotCurveData **DrawGrid( AstPlot *this, TickInfo **grid, int drawgrid, const char *method, const char *class, int *status ){ /* * Name: * DrawGrid * Purpose: * Draw a grid of lines at the major tick mark positions on both axes. * Type: * Private function. * Synopsis: * #include "plot.h" * AstPlotCurveData **DrawGrid( AstPlot *this, TickInfo **grid, int drawgrid, * const char *method, const char *class ) * Class Membership: * Plot method. * Description: * This function draw a grid of curves at the major tick mark * positions on both axes, and returns information describing the * breaks in the curves. If short tick marks are required rather * than long curves (as specified by the Grid attribute of the supplied * Plot), then the curves are not drawn but the break information is * still returned. * Parameters: * this * Pointer to a Plot. * grid * A pointer to an array of two pointers (one for each axis), each * pointing to a TickInfo structure. These describe the positions * of the tick marks and should have been produced by function * GridLines. * drawgrid * If non-zero, draw a grid of curves marking the major axis * values. Otherwise, tick marks will be drawn at these values later. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * Returned Value: * A pointer to an array of two AstPlotCurveData pointers (one for each axis), * each pointing to an array of AstPlotCurveData structures (one for each tick * value). * Notes: * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned. */ /* Local Variables: */ AstPlotCurveData **cdata;/* The returned pointer */ AstPlotCurveData *cdt; /* Pointer to break info. for current tick mark */ AstPlotCurveData tcdt; /* Pointer to break info. for current curve section */ TickInfo *info; /* Tick mark information for a single axis */ double start[ 2 ]; /* Strting position for current curve section */ double total_length; /* Total curve length for all axis ticks */ int i; /* Axis index */ int j; /* Tick mark index */ int k; /* Curve section index */ /* Check the global status. */ if( !astOK ) return NULL; /* Allocate memory to hold two pointers, each pointing to an array of AstPlotCurveData structure. */ cdata = (AstPlotCurveData **) astMalloc( 2*sizeof( AstPlotCurveData *) ); /* If succesful, initialise the pointers. */ if( astOK ){ cdata[ 0 ] = NULL; cdata[ 1 ] = NULL; /* Draw the curves marking the major tick values on each axis. If no grid is required, we still do this in order to get information about the breaks in the curves which will be used later to decide where to put the labels, but we use "invisible ink". */ for( i = 0; i < 2; i++ ){ /* Get a pointer to the TickInfo structure for this axis holding information about where to put tick marks on this axis. */ info = grid[ i ]; /* Allocate memory to hold information describing the breaks in each tick mark curve. This takes the form of an array of AstPlotCurveData structures, one for each tick mark. */ cdata[ i ] = (AstPlotCurveData *) astMalloc( sizeof(AstPlotCurveData)* (size_t) info->nmajor ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise a pointer to the first AstPlotCurveData structure for this axis. */ cdt = cdata[ i ]; total_length = 0.0; /* Do each tick mark. */ for( j = 0; j < info->nmajor; j++ ){ /* Store the starting point of the first section of the curve. */ start[ i ] = (info->ticks)[ j ]; start[ 1 - i ] = (info->start)[ 0 ]; /* Draw the first section of the curve parallel to the other axis, starting at the values in "start", and extending for a length given in the TickInfo structure. We use invisible ink if short tick marks are required instead of a grid of curves. */ AxPlot( this, 1 - i, start, (info->length)[ 0 ], drawgrid, cdt, method, class, status ); /* Now draw any other sections in the curve. */ for( k = 1; k < info->nsect; k++ ){ /* Modify the starting value on the other axis. The starting value on the current axis remains set to the tick mark value. */ start[ 1 - i ] = (info->start)[ k ]; /* Draw the curve, the information describing the breaks goes into temporary storage in the local structure "tcdt". */ AxPlot( this, 1 - i, start, (info->length)[ k ], drawgrid, &tcdt, method, class, status ); /* Concatenate the break information for this section with the break information describing the previous sections. */ AddCdt( cdt, &tcdt, method, class, status ); } /* Increment the total length of curves drawn for all ticks on this axis. */ total_length += cdt->length; /* Point to the AstPlotCurveData structure for the next tick mark. */ cdt++; } /* Report an error if the total length of all curves on this axis is zero. This can be caused for instance by bugs in the algorithm for finding major tick values (which may cause AST__BAD tick mark values). */ if( total_length == 0.0 && astOK ) { astError( AST__INTER, "%s(%s): No grid curves can be drawn for " "axis %d.", status, method, class, i + 1 ); } } } } /* If an error has occurred, clean up the returned structures. */ if( !astOK ) cdata = CleanCdata( cdata, status ); /* Return. */ return cdata; } static void DrawText( AstPlot *this, int ink, int esc, const char *text, float x, float y, const char *just, float upx, float upy, float *xbn, float *ybn, float *drop, const char *method, const char *class, int *status ){ /* * Name: * DrawText * Purpose: * Draw a character string, potentially including superscripts and * subscripts. * Synopsis: * #include "plot.h" * void DrawText( AstPlot *this, int ink, int esc, const char *text, * float x, float y, const char *just, float upx, * float upy, float *xbn, float *ybn, float *drop, * const char *method, const char *class, int *status ) * Description: * This function displays a character string at a given position * using a specified up-vector, optionally interpreting any Plot escape * sequences contained within the text. It also returns its bounding * box. * Parameters: * this * The plot. * ink * If zero, nothing is drawn but the bounding box is still returned. * esc * Should escape sequences be interpreted? They will be printed * literally otherwise. * text * Pointer to a null-terminated character string to be displayed. * x * The graphics X coordinate of the label's reference point. * y * The graphics Y coordinate of the label's reference point. * just * Pointer to a null-terminated character string identifying the * reference point for the text being drawn. The first character in * this string identifies the reference position in the "up" direction * and may be "M", "B", "C" or "T" (for bottom, baseline, centre or * top). The second character identifies the side-to-side reference * position and may be "L", "C" or "R" (for left, centre or right). The * string is case-insensitive, and only the first two characters are * significant. * upx * The x component of the up-vector for the text. Positive values * always refer to displacements from left to right on the screen, * even if the graphics x axis increases in the opposite sense. * upy * The y component of the up-vector for the text. Positive values * always refer to displacements from left to right on the screen, * even if the graphics y axis increases in the opposite sense. * xbn * An array in which is returned the x coordinates at the corners * of the bounding box. The order is: bottom left, top left, top * right, bottom right. * ybn * An array in which is returned the Y coordinates at the corners * of the bounding box (see xbn). * drop * Address of a float in which to return the distance between the * bottom of the bounding box and the baseline of normal text. May * be NULL. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - The "B" option for the justification in the "up" direction refers * to the base-line on which the text is written. Some characters * ("y", "p", "g", etc) descend below this line. In addition, if the * supplied text string includes any escape sequences which produce * sub-scripts, then these will also descend below the base-line. To * justify the bottom of the entire string (instead of just the * base-line), specify "M" instead of "B" in the justification string. * - See function astFindEscape for details of the supported escape * sequences. */ /* Local Variables: */ astDECLARE_GLOBALS char *a; char *lt; char cc; const char *lj; double ncol; double nfont; double nsize; double nstyle; double nwidth; float alpha_hi; float alpha_lo; float beta_lo; float beta_hi; float cy; float cx; float dy; float dx; float height; float hmx; float hmy; float ly; float lx; float rx; float rlen; float rise; float rxu; float ryu; float ry; float tdrop; float tybn[ 4 ]; float txbn[ 4 ]; float ulen; float uyu; float uxu; float uy; float ux; float width; float x0; float y0; int estype; int esval; int got_esc; int grfcap; int i; int nc; /* Check the global error status, and that we have something to plot, and the reference position is good, and that the up vector is not zero. */ if ( !astOK || !text || !text[ 0 ] || x == AST__BAD || y == AST__BAD || ( upx == 0.0 && upy == 0.0 ) ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Initialise variables to avoid compiler warnings. */ rx = 0.0f; ry = 0.0f; x0 = 0.0f; y0 = 0.0f; /* Get an up vector which refers to the graphics coordinates in their correct senses (the supplied values are reversed if the corresponding axis is reversed). */ ux = ( this->xrev ) ? -upx : upx; uy = ( this->yrev ) ? -upy : upy; /* Find a vector which points from left to right along the text baseline, taking account of any difference in the scales of the x and y axes (is possible). This also scales the up vector so that it has a length equal to the height of normal text, and scales the right vector to have the same length (on the screen) as the up vector. */ RightVector( this, &ux, &uy, &rx, &ry, method, class, status ); /* Create a unit right vector. */ rlen = sqrt( rx*rx + ry*ry ); rxu = rx/rlen; ryu = ry/rlen; /* Create a unit up vector. */ ulen = sqrt( ux*ux + uy*uy ); uxu = ux/ulen; uyu = uy/ulen; /* Some older GRF modules cannot plot strings with vertical justification of "M". Check the capabilities of the grf module, and, if necessary, modify the justification and the coords of the reference point to use "B" instead of "M". This call also returns us the coords at the left end of the baseline of normal text. */ lx = x; ly = y; lj = JustMB( this, esc, text, &lx, &ly, upx, upy, just, uxu, uyu, rxu, ryu, &x0, &y0, method, class, status ); /* Initialise the horizontal and verical limits of the total bounding box. */ alpha_lo = FLT_MAX; alpha_hi = -FLT_MAX; beta_lo = FLT_MAX; beta_hi = -FLT_MAX; /* Tell the grf module whether or not to interpret escape sequences,and also note if the grf module is capable of interpreting escape sequences. */ grfcap = GCap( this, GRF__ESC, esc, status ); /* Forget the horizontal position remembered by any "%h+" escape sequences from any previous string. */ this->hmarkx = FLT_MAX; this->hmarky = FLT_MAX; /* If escape sequences are being interpreted and the string contains some escape sequences, but the grf module cannot interpret escape sequences, split the supplied text up into sub-strings delimited by escape sequences and plot each sub-string individually, modifying the reference point and graphics attributes as indicated by the escape sequences. */ if( esc && HasEscapes( text, status ) && !grfcap ) { /* Take a copy of the supplied text so that we can temporarily terminate each sub-string by poking a null (0) character into it. */ lt = (char *) astStore( NULL, (void *) text, strlen( text ) + 1 ); /* Indicate that the current baseline is at its normal height. */ rise = 0.0; /* Get the graphical attribute values for normal text. */ GAttr( this, GRF__SIZE, AST__BAD, &nsize, GRF__TEXT, method, class, status ); GAttr( this, GRF__WIDTH, AST__BAD, &nwidth, GRF__TEXT, method, class, status ); GAttr( this, GRF__FONT, AST__BAD, &nfont, GRF__TEXT, method, class, status ); GAttr( this, GRF__STYLE, AST__BAD, &nstyle, GRF__TEXT, method, class, status ); GAttr( this, GRF__COLOUR, AST__BAD, &ncol, GRF__TEXT, method, class, status ); /* The "concatenation point" (cx,cy) is the point where the normal baseline crosses the left hand edge of the substring bounding box. Initialise this to the left edge of the first substring. */ cx = x0; cy = y0; /* Loop round the whole string, drawing each sub-string. */ a = lt; while( *a && astOK ) { /* Examine the start of the remaining string and note if it begins with an escape sequence. If so, the type and value of the escape sequnece is returned. In either case the number of characters to the next delimiter is returned. */ got_esc = astFindEscape( a, &estype, &esval, &nc ); /* If the string starts with an escaped percent sign, modify things so that we can draw the percent sign with the normal text drawing code below. */ if( got_esc && estype == GRF__ESPER ) { got_esc = 0; a++; nc = 1; } /* If the string starts with any other escape sequence, modify the graphics attributes and concatenation point as required by the escape sequence. */ if( got_esc ) { InterpEscape( this, estype, (double) esval, &cx, &cy, ux, uy, rx, ry, lj, &rise, nsize, nstyle, nwidth, ncol, nfont, method, class, status ); /* If the remaining string starts with normal text, draw it. */ } else { /* Temporarily terminate the sub-string which ends with the next escape sequence. */ cc = a[ nc ]; a[ nc ] = 0; /* We now have to decide on the reference point for this sub-string. If the justification is "BL" then the reference point is just the current concatenation point. */ if( lj[ 0 ] == 'B' && lj[ 1 ] == 'L' ) { lx = cx; ly = cy; /* Otherwise, the reference point is offset from the concatenation point. It would be simpler to draw all substrings with "BL" justification but this causes problems with some grf modules (such as GAIA) which zoom the display by modifying the position of text strings without also modifying the size of text strings. Using the correct reference point for all sub-strings minimises the drift which occurs when such a grf modules zooms the display. */ } else { /* Find the width and height of this substring, and the distance between the bottom of the bounding box and the baseline (the drop). We do this by calling this function recursively, using "BL" justification to avoid infinite recursion. */ /* Forget the horizontal position remembered by any "%h+" escape sequences from any previous string. Save and re-instate the position of the horizontal mark since the call to DrawText may change it. */ hmx = this->hmarkx; hmy = this->hmarky; DrawText( this, 0, esc, a, cx, cy, "BL", upx, upy, txbn, tybn, &tdrop, method, class, status ); this->hmarkx = hmx; this->hmarky = hmy; dx = txbn[ 0 ] - txbn[ 3 ]; dy = tybn[ 0 ] - tybn[ 3 ]; width = sqrt( dx*dx + dy*dy ); dx = txbn[ 0 ] - txbn[ 1 ]; dy = tybn[ 0 ] - tybn[ 1 ]; height = sqrt( dx*dx + dy*dy ); /* First move right from the concatenation point by a fraction of the width of the substring (0.5 for "C" and 1.0 for "R"). */ if( lj[ 1 ] == 'C' ) { width *= 0.5; } else if( lj[ 1 ] != 'R' ) { width = 0; } lx = cx + rxu*width; ly = cy + ryu*width; /* Now move vertically by an amount which produes the requested vertical justification. */ if( lj[ 0 ] == 'T' ) { height -= tdrop; lx += height*uxu; ly += height*uyu; } else if( lj[ 0 ] == 'C' ) { height = 0.5*height - tdrop; lx += height*uxu; ly += height*uyu; } else if( lj[ 0 ] == 'M' ) { lx -= tdrop*uxu; ly -= tdrop*uyu; } } /* Draw it, and then find its real bounding box (i.e. using the correct reference position found above). */ if( ink ) GText( this, a, lx, ly, lj, upx, upy, method, class, status ); GTxExt( this, a, lx, ly, lj, upx, upy, txbn, tybn, method, class, status ); /* Re-instate the orignal value of the terminator character.*/ a[ nc ] = cc; /* Move the concatenation point to the right (i.e. in the direction of the text baseline) by an amount equal to the width of the bounding box. Also update the total bounding box limits.*/ UpdateConcat( txbn, tybn, ux, uy, rx, ry, &cx, &cy, x0, y0, &alpha_lo, &alpha_hi, &beta_lo, &beta_hi, status ); } /* Move on to the next character. */ a += nc; } /* Free resources. */ lt = astFree( lt ); /* Reset all attributes to their normal values. */ GAttr( this, GRF__SIZE, nsize, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__WIDTH, nwidth, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__COLOUR, ncol, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__FONT, nfont, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__STYLE, nstyle, NULL, GRF__TEXT, method, class, status ); /* If any escape sequences can be interpreted by the grf module, just pass the text string on to the grf module. */ } else { if( ink ) GText( this, text, lx, ly, lj, upx, upy, method, class, status ); GTxExt( this, text, lx, ly, lj, upx, upy, txbn, tybn, method, class, status ); /* The corners in the bounding box returned by GTxExt are in no particular order. But this function is contracted to return them in a specified order. So we use UpdateConcat to find the verical and horizontal limits of the box in a form which can be used to produce the correct order. UpdateConcat will also update the concatenation point, but that is irrelevant in this context. */ UpdateConcat( txbn, tybn, ux, uy, rx, ry, &lx, &ly, x0, y0, &alpha_lo, &alpha_hi, &beta_lo, &beta_hi, status ); } /* Return the total bounding box,in the order bottom left, topleft, top right, bottom right. */ xbn[ 0 ] = x0 + alpha_lo*ux + beta_lo*rx; ybn[ 0 ] = y0 + alpha_lo*uy + beta_lo*ry; xbn[ 1 ] = x0 + alpha_hi*ux + beta_lo*rx; ybn[ 1 ] = y0 + alpha_hi*uy + beta_lo*ry; xbn[ 2 ] = x0 + alpha_hi*ux + beta_hi*rx; ybn[ 2 ] = y0 + alpha_hi*uy + beta_hi*ry; xbn[ 3 ] = x0 + alpha_lo*ux + beta_hi*rx; ybn[ 3 ] = y0 + alpha_lo*uy + beta_hi*ry; /* Return the drop. */ if( drop ) *drop = -alpha_lo*ulen; /* Free memory.*/ lj = astFree( (void *) lj ); /* If OK, update the box containing all drawn graphics primitives. */ if( ink && astOK && !Boxp_freeze ) { for( i = 0; i < 4; i++ ){ Boxp_lbnd[ 0 ] = MIN( xbn[ i ], Boxp_lbnd[ 0 ] ); Boxp_ubnd[ 0 ] = MAX( xbn[ i ], Boxp_ubnd[ 0 ] ); Boxp_lbnd[ 1 ] = MIN( ybn[ i ], Boxp_lbnd[ 1 ] ); Boxp_ubnd[ 1 ] = MAX( ybn[ i ], Boxp_ubnd[ 1 ] ); } } } static void DrawTicks( AstPlot *this, TickInfo **grid, int drawgrid, double *labelat, double *gap, const char *method, const char *class, int *status ){ /* * * Name: * DrawTicks * Purpose: * Draw tick marks for a 2-D annotated coordinate grid. * Type: * Private function. * Synopsis: * #include "plot.h" * void DrawTicks( AstPlot *this, TickInfo **grid, int drawgrid, * double *labelat, double *gap, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws major and minor tick marks. It uses a different * technique depending on whether the tick marks are to be put along the * edges of the plotting area, or along a curve through the middle of the * plotting area. The physical axis values at which to put tick marks * are supplied in parameter "grid". * * If the ticks are placed on the edges of the plotting area, The * EdgeCrossings function is used to find all points along the edge which * have a physical axis value correspoinding to a tick value (there can in * general be more than one point on an edge with a given physical axis * value). Ticks are put at all such crossings. * * If ticks are placed within the plotting area, then they are put * along a curve defined by the "other axis" values supplied in * parameter "labelat". * Parameters: * this * A pointer to the Plot. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick marks on the axis. See function GridLines. * drawgrid * If non-zero, then a grid of curves has been drawn to mark the * major axis values. * labelat * A pointer to a 2 element array in holding the constant axis * values at which tick marks are to be put. Element 0 should hold * the axis 1 value at which tick marks for axis 0 are placed. Element * 1 should hold the axis 0 value at which tick marks for axis * 1 are placed. If ticks are to be placed round the edges of the * plotting zone instead of within the plotting zone, then values of * AST__BAD should be supplied. * gap * Pointer to array of two values holding the gap between major * tick marks on the two axes. This will be the difference between, * or the ratio of, adjacent tick mark values, depending on the * setting of the LogTicks attribute. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This function assumes the current Frame of the Plot is 2 * dimensional, and it should not be called if this is not the case. */ /* Local Variables: */ AstFrame *frame; /* Pointer to current Frame in Plot */ AstMapping *mapping; /* Pointer to graphics->physical Mapping */ AstPointSet *pset1; /* Pointer to PointSet holding physical coords. */ AstPointSet *pset2; /* Pointer to PointSet holding graphics coords. */ AstPointSet *pset3; /* Pointer to PointSet holding clipped graphics coords. */ EdgeCrossingsStatics *ecstatics = NULL; /* For static data structure */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ double *ptr1[2]; /* Pointer to physical data */ double **ptr2; /* Pointer to graphics data */ double **ptr3; /* Pointer to clipped graphics data */ double *a; /* Pointer to next current axis value */ double *b; /* Pointer to next other axis value */ double *value; /* Current tick value */ double *x; /* Pointer to next X value */ double *xc; /* Pointer to next clipped X value */ double *y; /* Pointer to next Y value */ double *yc; /* Pointer to next clipped Y value */ double a0; /* Physical axis value at base of tick */ double axmax; /* Upper axis limit */ double axmin; /* Lower axis limit */ double delta1; /* Increment between minor ticks above major tick */ double delta2; /* Increment between minor ticks below major tick */ double diff; /* Difference between adjacent major ticks */ double dl2; /* Squared increment between points */ double dl2_limit; /* Minimum usable squared increment between points */ double dl; /* Increment between points */ double dx; /* X component of increment along tick mark */ double dy; /* Y component of increment along tick mark */ double ex; /* X component of increment between points */ double ey; /* Y component of increment between points */ double lblat2; /* Other axis value part way up each tick */ double lblat; /* Other axis value at base of each tick */ double mindim; /* Shortest dimension of plotting area */ double minval; /* Current axis value at next minor tick */ double mjsign; /* Sign of the major tick mark length */ double mjtklen; /* Length of major tick marks */ double mnsign; /* Sign of the minor tick mark length */ double mntklen; /* Length of minor tick marks */ double ux; /* X component of unit vector along tick mark */ double uy; /* Y component of unit vector along tick mark */ double val; /* Major axis value */ double x0; /* X at base of tick */ double x1; /* X at end of tick */ double x2; /* Clipped X at base of tick */ double y0; /* Y at base of tick */ double y1; /* Y at end of tick */ double y2; /* Clipped Y at base of tick */ int *majflag; /* Pointer to next major/minor flag */ int *majflags; /* Pointer to aray of major/minor flags */ int axis; /* Current axis index */ int ed; /* Doing a secondary edge? */ int edge; /* Index of edge being ticked */ int first; /* Is this the first tick to be drawn? */ int gelid; /* ID for next graphical element to be drawn */ int i; /* Minor tick mark index */ int logticks; /* Are major tick marks logarithmically spaced? */ int minhi; /* Highest minor tick mark index */ int minlo; /* Lowest minor tick mark index */ int nedge; /* No. of edges to be ticked for each axis */ int nel; /* Actual number of tick marks to draw */ int ntot; /* Maximum number of tick marks */ int tick; /* Tick index */ int lasttick; /* Index of last major tick mark */ /* Check the global status. */ if( !astOK ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ a = NULL; delta1 = 0.0; delta2 = 0.0; lblat2 = 0.0; uy = 0.0; logticks = 0; /* Get the minimum dimension of the plotting ares. */ mindim = MIN( this->xhi - this->xlo, this->yhi - this->ylo ); /* Information about the drawn tick marks is saved in the Plot structure. Reset this information now so that we are ready to store information about the new ticks that will be drawn by this function invocation. */ SaveTick( this, -1, 0.0, 0.0, 0, status ); /* If ticks are to be put round the edges of the plotting area... */ /* ============================================================== */ if( labelat[ 0 ] == AST__BAD || labelat[ 1 ] == AST__BAD ){ /* Store the number of edges to be ticked for each axis. */ nedge = astGetTickAll( this )? 2 : 1; /* Do each required edge. */ for( ed = 0; ed < nedge; ed++ ){ /* Initialize the id value for graphical element being drawn. */ gelid = AST__TICKS1_ID; /* Do each axis. */ for( axis = 0; axis < 2; axis++ ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, gelid, 1, GRF__LINE, method, class ); /* Store the length in graphics coordinates of major tick marks for this axis. Use a default of zero if a grid has been drawn. */ if( astTestMajTickLen( this, axis ) || !drawgrid ){ mjtklen = astGetMajTickLen( this, axis )*mindim; } else { mjtklen = 0.0; } /* Store the length in graphics coordinates of minor tick marks. */ mntklen = astGetMinTickLen( this, axis )*mindim; /* Get the edge to be labelled with the axis values. Edge 0 is the left hand edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 is the bottom edge. */ edge = ( astGetEdge( this, axis ) + ed*2 ) % 4; if( edge < 0 ) edge = -edge; /* Store a pointer to the structure containing information describing the positions of the major tick marks along this axis. */ info = grid[ axis ]; /* Store a pointer to the axis value at the first major tick mark. */ value = info->ticks; /* Minor tick marks are drawn on both sides of each major tick mark. They are identified by an index number relative to major tick mark at zero. Store the indicies of the first and last minor tick marks. */ minlo = ( 1 - info->nminor )/2; minhi = info->nminor/2; /* If major ticks are linear, store the difference between minor tick marks. This value will be the same for all major ticks. */ logticks = astGetLogTicks( this, axis ); if( !logticks ) { delta1 = gap[ axis ]/(double)info->nminor; delta2 = delta1; } /* Loop round until all ticks have been done. */ for( tick = 0; tick < info->nmajor; tick++ ){ /* Draw tick marks at all occurrences of the current major tick value on the selected edge of the plotting area. */ Ticker( this, edge, axis, *value, gap, mjtklen, 1, ( ed == 0 ), &ecstatics, method, class, status ); /* If minor tick mark values were not supplied, calculate them as even intervals between the major tick values. */ if( !info->minticks ) { /* If major ticks are logarithmic, store the difference between minor tick marks. This value will be different for each major tick. Also, since the minor ticks are drawn on either side of the major tick, the minor tick spacing above the major tick will be different to that below the minor tick when using logarathmic ticks. "delta1" is the minor gap above the major value, and "delta2" is the minor gap below the major value. */ if( logticks ) { delta1 = (*value) * ( gap[ axis ] - 1.0 )/ (double)info->nminor; delta2 = delta1 / gap[ axis ]; } /* Extra minor tick marks are drawn below the first major tick mark and above the last major tick mark to fill in any gaps caused by axis limits being exceeded. */ if( tick == 0 ) { minlo = 1 - info->nminor; } if( tick == 1 ) { minlo = ( 1 - info->nminor )/2; } else if( tick == info->nmajor - 1 ) { minhi = info->nminor - 1; } /* Store the axis value at the first minor tick mark. */ minval = *value + minlo*delta2; /* Loop round all the minor tick marks, storing the physical coordinates defining the tick mark. */ for( i = minlo; i <= minhi; i++ ){ /* Draw tick marks at all occurrences of the current minor tick value on the selected edge of the plotting area. Do not do the minor tick mark with index zero, since this corresponds to the position of the major tick mark. */ if( i ) Ticker( this, edge, axis, minval, gap, mntklen, 0, ( ed == 0 ), &ecstatics, method, class, status ); /* Get the axis value at the next minor tick mark. */ minval += ( i < 0 ) ? delta2 : delta1; } } /* Point to the next major tick value. */ value++; } /* If minor tick mark values have been supplied, used them. */ if( info->minticks ) { value = info->minticks; for( tick = 0; tick < info->nminor; tick++, value++ ){ Ticker( this, edge, axis, *value, gap, mntklen, 0, ( ed == 0 ), &ecstatics, method, class, status ); } } /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gelid, 0, GRF__LINE, method, class ); /* Set up the id for the next graphical element to be drawn. */ gelid = AST__TICKS2_ID; } } /* Free the static resources allocated within EdgeCrossings (called by Ticker). */ (void) EdgeCrossings( NULL, 0, 0, 0.0, NULL, NULL, &ecstatics, method, class, status ); /* If ticks are to put within the interior of the plotting area... */ /* ============================================================== */ } else { /* Get the mapping from base Frame (graphics coords) to current Frame (physical coords). */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Get the current Frame from the Plot. */ frame = astGetFrame( this, AST__CURRENT ); /* Initialize the id value for graphical element being drawn. */ gelid = AST__TICKS1_ID; /* Do each axis. */ for( axis = 0; axis < 2; axis++ ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, gelid, 1, GRF__LINE, method, class ); /* Store the length in graphics coordinates of major tick marks for this axis. Use a default of zero if a grid has been drawn. */ if( astTestMajTickLen( this, axis ) || !drawgrid ){ mjtklen = astGetMajTickLen( this, axis )*mindim; } else { mjtklen = 0.0; } /* Store the length in graphics coordinates of minor tick marks. */ mntklen = astGetMinTickLen( this, axis )*mindim; /* Indicate that the tick mark lengths should not be negatated. */ mjsign = 1.0; mnsign = 1.0; /* Store the smallest squared distance in graphics coordinates which can reliably be used to determine the direction of a tick mark. */ dl2_limit = 0.0001*mindim; dl2_limit *= dl2_limit; /* Store a pointer to the structure containing information describing the positions of the major tick marks along this axis. */ info = grid[ axis ]; /* Store a pointer to the axis value at the first major tick mark. */ value = info->ticks; /* Get the maximum number of tick marks to be drawn on this axis. */ ntot = 0; ntot = info->nmajor; if( info->minticks ) { ntot += info->nmajor + info->nminor; } else { ntot += ( info->nmajor + 1 )*( info->nminor - 1 ); } /* Pass on to the next axis if no ticks are to be drawn. */ if( ntot ) { /* Allocate memory to hold the physical coordinates defining all the required tick marks. Each tick mark is defined by 2 points. */ ptr1[ 0 ] = (double *) astMalloc( sizeof(double)*(size_t)(2*ntot) ); ptr1[ 1 ] = (double *) astMalloc( sizeof(double)*(size_t)(2*ntot) ); /* Allocate memory to hold a set of flags indicating whether each tick mark is minor or major. */ majflags = (int *) astMalloc( sizeof(int)*(size_t)ntot ); /* Check the pointers can be used. */ if( astOK ){ /* If the tick values have been supplied using astSetTickValues, just copy them into the above arrays. */ if( info->minticks ) { a = ptr1[ axis ]; b = ptr1[ 1 - axis ]; majflag = majflags; for( tick = 0; tick <= info->nmajor; tick++ ){ val = info->ticks[ tick ]; if( logticks ) { diff = val * ( gap[ axis ] - 1.0 ); lblat2 = labelat[ axis ] + 0.2*diff; } else { lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; } *(a++) = val; *(b++) = labelat[ axis ]; *(a++) = val; *(b++) = lblat2; *(majflag++) = 1; } for( tick = 0; tick <= info->nminor; tick++ ){ val = info->minticks[ tick ]; if( logticks ) { diff = val * ( gap[ axis ] - 1.0 ); lblat2 = labelat[ axis ] + 0.2*diff; } else { lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; } *(a++) = val; *(b++) = labelat[ axis ]; *(a++) = val; *(b++) = lblat2; *(majflag++) = 0; } /* If the tick values were not supplied using astSetTickValues, then we need to calculate the minor tick positions explicitly. */ } else { /* Store pointers to the next point on each axis. "a" always refers to the current axis. Also store the value on the other axis at which the tick marks starts, and another value on the other axis which is used to defined the tick mark directions. */ a = ptr1[ axis ]; b = ptr1[ 1 - axis ]; majflag = majflags; lblat = labelat[ axis ]; /* Store another value on the other axis which is used to defined the tick mark directions, and the difference between minor tick marks. For linearly spaced tick marks these values will be the same for all major ticks. Minor ticks are always drawn above the correponding major value (i.e. minlo == 1 ) and so we do not need to set delta2. */ logticks = astGetLogTicks( this, axis ); if( !logticks ) { lblat2 = labelat[ axis ] + 0.2*gap[ 1 - axis ]; delta1 = gap[ axis ]/(double)info->nminor; } /* Store the indicies of the first and last minor tick marks, relative to a major tick mark. */ minlo = 1; minhi = info->nminor - 1; /* Get the axis limits. */ axmin = astGetBottom( frame, axis ); axmax = astGetTop( frame, axis ); /* Loop round until all ticks have been done. We include a hypothetical tick at index -1 (i.e. one gap below the first listed tick value) in order to get minor tick marks below the first major tick. But the hypothetical major tick value is not included in the list of major tick values to draw. */ lasttick = info->nmajor - 1; for( tick = -1; tick <= lasttick; tick++ ){ /* Get the major tick value. */ if( tick == -1 ) { if( !logticks ) { val = (*value) - gap[ axis ]; }else { val = (*value)/gap[ axis ]; } } else { val = *(value++); } /* Now find the value on the other axis which is used to defined the tick mark directions, and the difference between minor tick marks, in the case of logarithmically spaced tick marks. These values will be different for every major tick. Minor ticks are always drawn above the correponding major value (i.e. minlo == 1 ) and so we do not need to set delta2. */ if( logticks ) { diff = val * ( gap[ axis ] - 1.0 ); lblat2 = labelat[ axis ] + 0.2*diff; delta1 = diff / (double)info->nminor; } /* If major tick marks are required, store the physical coordinates at the start of the major tick mark, and at a point a little way up the major tick mark. */ if( tick > -1 ){ *(a++) = val; *(b++) = lblat; *(a++) = val; *(b++) = lblat2; *(majflag++) = 1; } /* Store the points defining the minor tick marks on either side of this major tick mark. First store the axis value at the first minor tick mark. */ minval = val + minlo*delta1; /* Loop round all the minor tick marks, storing the physical coordinates defining the tick mark. */ for( i = minlo; i <= minhi; i++ ){ /* Do not do the minor tick mark with index zero, since this corresponds to the position of the major tick mark. Do not do any minor ticks that are outside the axis range. */ if( i && minval >= axmin && minval <= axmax ){ *(a++) = minval; *(b++) = lblat; *(a++) = minval; *(b++) = lblat2; *(majflag++) = 0; } /* Get the axis value at the next minor tick mark. */ minval += delta1; } } } } /* Adjust the size of the arrays to exclude any unused space. */ nel = a - ptr1[axis]; ptr1[axis] = (double *) astRealloc( (void *) ptr1[axis], sizeof(double)*nel ); ptr1[1-axis] = (double *) astRealloc( (void *) ptr1[1-axis], sizeof(double)*nel ); /* Create a pointset holding these coordinates. */ pset1 = astPointSet( nel, 2, "", status ); astSetPoints( pset1, ptr1 ); /* Transform these physical coordinates into graphics coordinates, without doing any clipping (this is so that tick marks are still drawn even if they extend into the area containing clipped physical coordinates). */ pset2 = astTransform( mapping, pset1, 0, NULL ); ptr2 = astGetPoints( pset2 ); /* Transform them again this time with clipping. */ pset3 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); ptr3 = astGetPoints( pset3 ); /* Check the pointers can be used.*/ if( astOK ){ /* Store pointers to the next point on each axis. */ a = ptr1[ axis ]; x = ptr2[ 0 ]; y = ptr2[ 1 ]; xc = ptr3[ 0 ]; yc = ptr3[ 1 ]; majflag = majflags; /* Loop round all ticks (major and minor). */ ux = AST__BAD; first = 1; for( tick = 0; tick < nel/2; tick++ ){ /* Store the physical axis value at the base of the tick mark (skip over the physical axis value at the point up the tick mark). */ a0 = *(a++); a++; /* Store the x and y coordinates at the base of the tick mark. */ x0 = *(x++); y0 = *(y++); /* Store the x and y coordinates at a point up the tick mark. */ x1 = *(x++); y1 = *(y++); /* Store the clipped x and y coordinates at the base of the tick mark. */ x2 = *(xc++); y2 = *(yc++); /* Skip over the clipped x and y coordinates at the point up the tick mark. */ xc++; yc++; /* Check they are all valid, and that the start of the tick mark is within the plotting area. */ if( x0 != AST__BAD && y0 != AST__BAD && x1 != AST__BAD && y1 != AST__BAD && x2 != AST__BAD && y2 != AST__BAD && x0 <= this->xhi && x0 >= this->xlo && y0 <= this->yhi && y0 >= this->ylo ){ /* Get the increments in X and Y beyween the two points, and the squared distance between the two points. */ dx = x1 - x0; dy = y1 - y0; dl2 = dx*dx + dy*dy; /* Check the two points are not co-incident. */ if( dl2 > dl2_limit ){ /* Store the distance between the two points. */ dl = sqrt( dl2 ); /* If this is the first tick to be drawn on this axis, decide which direction to draw the tick mark so that they will appear on the right hand side of the axis as seen by someone moving along the axis in the positive direction (the numerical labels are also drawn on the same side). */ if( first ){ first = 0; /* If the next tick mark is not defined, make an arbitrary decision by leaving the sign of the tick mark length unchanged. */ if( tick + 1 < nel/2 && *x != AST__BAD && *y != AST__BAD && a0 != AST__BAD && *a != AST__BAD ){ /* Form the vector joining this tick mark to the next. */ ex = *x - x0; ey = *y - y0; /* Ensure this vector is in the positive direction of the axis. */ if( *a < a0 ) { ex = -ex; ey = -ey; } /* If a positive tick mark length would put the marks on the wrong side, negate the tick mark length. */ if( ex*dy > ey*dx ){ mjsign = -1.0; mnsign = -1.0; } } } /* Store the unit vector in the direction of the tick mark. This is used as the default vector for the next tick mark if the direction of the next tick mark is indeterminate. */ ux = dx/dl; uy = dy/dl; } /* Only draw this tickmark if its direction is known. */ if( ux != AST__BAD ) { /* Get the position of the end of the tick mark. The length of the tick mark depends on whether it is a major or minor tick mark. */ if( *majflag ){ x1 = x0 + mjsign*mjtklen*ux; y1 = y0 + mjsign*mjtklen*uy; } else { x1 = x0 + mnsign*mntklen*ux; y1 = y0 + mnsign*mntklen*uy; } /* Save and draw the tick mark. */ SaveTick( this, axis, x0, y0, *majflag, status ); if( x0 != x1 || y0 != y1 ) { Bpoly( this, (float) x0, (float) y0, status ); Apoly( this, (float) x1, (float) y1, status ); Opoly( this, status ); } } } /* Point to the next major/minor flag. */ majflag++; } } /* Free the memory holding the physical coordinates. */ ptr1[ 0 ] = (double *) astFree( ( void *) ptr1[ 0 ] ); ptr1[ 1 ] = (double *) astFree( ( void *) ptr1[ 1 ] ); majflags = (int *) astFree( (void *) majflags ); /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); pset3 = astAnnul( pset3 ); } /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gelid, 0, GRF__LINE, method, class ); /* Set up the id for the next graphical element to be drawn. */ gelid = AST__TICKS2_ID; } /* Annul the pointers to the Mapping and Frame. */ mapping = astAnnul( mapping ); frame = astAnnul( frame ); } /* Return. */ return; } static void EBuf( AstPlot *this, int *status ) { /* *++ * Name: c astEBuf f AST_EBUF * Purpose: * End the current graphical buffering context. * Type: * Public function. * Synopsis: c #include "plot.h" c void astEBuf( AstPlot *this ) f CALL AST_EBUF( THIS STATUS ) * Class Membership: * Plot member function. * Description: c This function f This routine * ends the current graphics buffering context. It should match a * corresponding call to the c astBBuf function. f AST_EBUF routine. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - The nature of the buffering is determined by the underlying * graphics system (as defined by the current grf module). Each call c to this function f to this routine * simply invokes the astGEBuf function in the grf module. *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the active GRF EBuf function. */ GEBuf( this, "astEBuf", astGetClass( this ), status ); } static int EdgeLabels( AstPlot *this, int ink, TickInfo **grid, AstPlotCurveData **cdata, int force, const char *method, const char *class, int *status ){ /* * * Name: * EdgeLabels * Purpose: * Attempts to display labels for the major tick values around the edges * of the plotting area. * Type: * Private function. * Synopsis: * #include "plot.h" * int EdgeLabels( AstPlot *this, int ink, TickInfo **grid, * AstPlotCurveData **cdata, int force, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function determines how many major tick value labels could be * placed on the specified edges of the plotting area, and then if * requested, and if sufficient such labels are found (more than 3 on * each axis), they are drawn. To place a label on an edge, the curve * defining the major tick value must cross the edge at a reasonably * angle (at least 3 degrees). Labels are not drawn which would overlap * other, previously drawn, labels. A flag is returned indicating if * edge labels were (or could be) drawn. * Parameters: * this * A pointer to the Plot. * ink * If zero, then no labels are drawn, but the decision whether or * not to draw them is still made and indicated in the returned function * value. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick marks on the axis. See function GridLines. * cdata * A pointer to an array of two AstPlotCurveData pointers (one for each axis), * each pointing to an array of AstPlotCurveData structure (one for each * major tick value on the axis), holding information about breaks * in the curves drawn to mark the major tick values. See function * DrawGrid. * force * If non-zero, then an attempt is made to draw edge labels even if * it looks like insufficient edge labels can be produced. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * If edge labels were drawn, 1 is returned. Otherwise 0 is returned. * Notes: * - Zero is returned if an error has already occurred. */ /* Local Variables: */ AstFrame *frame; /* Pointer to current Frame */ AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ LabelList *labellist; /* Pointer to a ingle list of labels to be plotted */ LabelList *ll; /* Pointer to next label to be plotted */ LabelList *llist[2]; /* Pointers to both lists of labels to be plotted */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ const char *just[ 2 ]; /* Justification string */ const char *text; /* Pointer to label text */ double edgeval; /* Axis value at the labelled edge */ double mindim; /* Minimum dimension of the plotting area */ double oppval; /* Axis value on the edge opposite to the labels */ double tol; /* Max. distance between a break and the edge */ double txtgap; /* Absolute gap between labels and edges */ float *box; /* Pointer to array of label bounding boxes */ float *vxbrk; /* X component of unit vector at current break */ float *vybrk; /* Y component of unit vector at current break */ float *xbrk; /* X coord. of current break */ float *ybrk; /* Y coord. of current break */ float xref; /* X coordinate at label's reference position */ float yref; /* Y coordinate at label's reference position */ int axis; /* Current axis index */ int brk; /* Current break index */ int edge; /* The edge to be labelled */ int edgeax; /* Index of axis parallel to the labelled edge */ int edgelabs; /* Can edge labels be produced? */ int esc; /* INterpret escape sequences? */ int gelid; /* ID for next graphical element to be drawn */ int ii; /* Index into existing labels */ int maxlab; /* Number of distinct edge labels */ int medge[2]; /* No. of distinct edge labels for each axis */ int naxlab; /* Number of edge labels */ int near; /* Draw a label on the near edge? */ int nedge[2]; /* No. of edge labels for each axis */ int ok; /* Can the current tick mark be labelled on the edge? */ int labfound; /* Label value has already been used? */ int tick; /* Tick index */ int upright; /* Draw all labels upright? */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ xref = 0.0; yref = 0.0; /* See if escape sequences in text strings are to be interpreted. */ esc = astGetEscape( this ); /* Initialise the returned flag to indicate that edge labels cannot be produced. */ edgelabs = 0; /* Get the minimum dimension of the plotting ares. */ mindim = MIN( this->xhi - this->xlo, this->yhi - this->ylo ); /* Set up the tolerance for curve breaks occuring on an edge of the plotting zone. */ tol = 0.005*mindim; /* First, we get a list of all the labels which can be produced on each axis. The list includes the labels reference position in graphics coordinates, and the index of the major tick value which it represents. We do not yet know whether enough of the grid lines cross the required edge to make it feasable to use edge labelling, so we do not yet draw the labels. =====================================================================*/ /* Initialise pointers to arrays of structures holding information about the labels which can be draw round the edge for both axes. */ llist[ 0 ] = NULL; llist[ 1 ] = NULL; /* Indicate that no labels can yet be drawn on either axis. */ nedge[ 0 ] = 0; nedge[ 1 ] = 0; /* The "nedge" array counts the number of labels on each edge. But some of these labels may be for the same tick mark (if the tick mark curve has more than 1 intersection with the edge). The "medge" array counts the number of *distinct* tick mark labels (i.e. the number of tick mark values which have 1 or more interesections with the edge). */ medge[ 0 ] = 0; medge[ 1 ] = 0; /* For each axis, identify the the usable edge labels. */ for( axis = 0; axis < 2; axis++ ){ /* See if labels for this axis are to be drawn upright. */ if( astTestLabelUp( this, axis ) ) { upright = astGetLabelUp( this, axis ); } else { upright = 1; } /* Store the required gap between the label text and the axis. */ txtgap = astGetNumLabGap( this, axis )*mindim; /* Get the edge to be labelled with the axis values. Edge 0 is the left hand edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 is the bottom edge. */ edge = astGetEdge( this, axis ) % 4; if( edge < 0 ) edge = -edge; /* If edge labels for the current axis are to go on the left hand edge of the plotting area... */ if( edge == 0 ){ /* Choose the justification based on the sign of the text gap. */ if( !upright ) { just[ axis ] = "BC"; } else if( txtgap > 0.0 ){ just[ axis ] = "CR"; } else if( txtgap < 0.0 ){ just[ axis ] = "CL"; } else { just[ axis ] = "CC"; } /* Store the constant X axis value at the edge being labelled. Also store the X value to use for the reference position for all labels. Take into account whether or not the X axis is displayed reversed (i.e. with high X values at the left hand side of the screen ). */ if( !this->xrev ){ edgeval = this->xlo; oppval = this->xhi; xref = (float)( edgeval - txtgap ); } else { edgeval = this->xhi; oppval = this->xlo; xref = (float)( edgeval + txtgap ); } /* Indicate that the "edgeval" value refers to axis 1 (the X axis). */ edgeax = 1; /* Do the same if the labels are to go on the top edge. */ } else if( edge == 1 ){ if( txtgap > 0.0 ){ just[ axis ] = "BC"; } else if( txtgap < 0.0 ){ just[ axis ] = "TC"; } else { just[ axis ] = "CC"; } if( !this->yrev ){ edgeval = this->yhi; oppval = this->ylo; yref = (float)( edgeval + txtgap ); } else { edgeval = this->ylo; oppval = this->yhi; yref = (float)( edgeval - txtgap ); } edgeax = 0; /* Do the same if the labels are to go on the right-hand edge. */ } else if( edge == 2 ){ if( !upright ) { just[ axis ] = "BC"; } else if( txtgap > 0.0 ){ just[ axis ] = "CL"; } else if( txtgap < 0.0 ){ just[ axis ] = "CR"; } else { just[ axis ] = "CC"; } if( !this->xrev ){ edgeval = this->xhi; oppval = this->xlo; xref = (float)( edgeval + txtgap ); } else { edgeval = this->xlo; oppval = this->xhi; xref = (float)( edgeval - txtgap ); } edgeax = 1; /* Do the same if the labels are to go on the bottom edge. */ } else { if( txtgap > 0.0 ){ just[ axis ] = "TC"; } else if( txtgap < 0.0 ){ just[ axis ] = "BC"; } else { just[ axis ] = "CC"; } if( !this->yrev ){ edgeval = this->ylo; oppval = this->yhi; yref = (float)( edgeval - txtgap ); } else { edgeval = this->yhi; oppval = this->ylo; yref = (float)( edgeval + txtgap ); } edgeax = 0; } /* Get a pointer to the structure containing information describing the positions of the major tick marks along this axis. */ info = grid[ axis ]; /* Get a pointer to the structure containing information describing the breaks in the curve which is parallel to the other axis and passes through the first major tick mark. */ cdt = cdata[ axis ]; /* Initialise the pointer to the list of text strings to be drawn. */ labellist = NULL; /* Initialise the number of labels which can be placed on the near edge of the plotting zone (some of which may be the same). */ naxlab = 0; /* Initialise the number of distinct labelled tick mark values. */ maxlab = 0; /* Loop round each of the major tick marks on the current axis. */ for( tick = 0; cdt && info && tick < info->nmajor; tick++ ){ /* Store pointers to the values giving the position and unit direction vector of the curve at the first break. */ xbrk = cdt->xbrk; ybrk = cdt->ybrk; vxbrk = cdt->vxbrk; vybrk = cdt->vybrk; /* Loop round each of the breaks in the curve which passes through the current major tick mark, and is parallel to the other axis. */ ok = 0; for( brk = 0; brk < cdt->nbrk; brk++ ){ /* A label can be produced on the near edge of the plotting zone if the current break occurs on, or close to, the edge, and the curve is not nearly parallel to the axis (limit is 5 degs). */ near = ( ( edgeax == 0 && fabs( (double) *ybrk - edgeval ) < tol && fabs( (double) *vybrk ) > 0.09 ) || ( edgeax == 1 && fabs( (double) *xbrk - edgeval ) < tol && fabs( (double) *vxbrk ) > 0.09 ) ); /* Get the label text. */ if( info->labels ) { text = (info->labels)[ tick ]; } else { text = NULL; } /* If a label can be produced, record the information needed to draw the label. */ if( near && text ){ labellist = (LabelList *) astGrow( (void *) labellist, naxlab + 1, sizeof(LabelList) ); if ( !astOK ) break; if( edgeax == 0 ){ (labellist + naxlab)->index = (double) *xbrk; (labellist + naxlab)->x = (double) *xbrk; (labellist + naxlab)->y = (double) yref; } else { (labellist + naxlab)->index = (double) *ybrk; (labellist + naxlab)->x = (double) xref; (labellist + naxlab)->y = (double) *ybrk; } (labellist + naxlab)->text = (char *) astStore( NULL, (void *) text, strlen(text) + 1 ); (labellist + naxlab)->just = (char *) astStore( NULL, (void *) just[ axis ], strlen(just[ axis ]) + 1 ); /* The up vector depends on which edge is being labelled and whether all labels are being drawn upright or not. */ if( edge == 1 || edge == 3 || upright ) { (labellist + naxlab)->upx = 0.0; (labellist + naxlab)->upy = 1.0; } else if( edge == 0 ) { (labellist + naxlab)->upx = -1.0; (labellist + naxlab)->upy = 0.0; } else { (labellist + naxlab)->upx = 1.0; (labellist + naxlab)->upy = 0.0; } (labellist + naxlab)->val = (info->ticks)[ tick ]; naxlab++; /* If this label has not already been included in the label list, indicate that we have found another usable label. */ labfound = 0; for( ii = 0; ii < naxlab-1; ii++ ) { if( fabs( (info->ticks)[ tick ] - (labellist + ii)->val ) < 0.2*info->gap ) { labfound = 1; break; } } if( !labfound ) ok = 1; } /* Increment the pointers to the values giving the position and unit direction vector of the next break. */ xbrk++; ybrk++; vxbrk++; vybrk++; } /* If an error has occurred, break out of the loop. */ if( !astOK ) break; /* If one or more labels could be produced for this tick mark value, increment the number of labeled tick marks found. */ if( ok ) maxlab++; /* Get a pointer to the curve through the next major tick mark. */ cdt++; } /* If an error has occurred, break out of the loop. */ if( !astOK ) break; /* Store the number of labels for this axis, and the pointer to the drawable labels. */ nedge[ axis ] = naxlab; medge[ axis ] = maxlab; llist[ axis ] = labellist; } /* We now know how many labels would be produced on each axis if edge labelling were to be used. We also know what those labelled values are, and where the labels would be drawn. We now take the decision as to whether there are enough of these labels to make edge labelling feasable. If so, we carry on and draw the labels. There need to be at least 3 labels on each axis for linear tick spacing and 2 for log tick spacing (or a non-zero value supplied for "force")... ================================================================= */ if( astOK && ( ( medge[ 0 ] > ( astGetLogTicks( this, 0 ) ? 1 : 2 ) && medge[ 1 ] > ( astGetLogTicks( this, 1 ) ? 1 : 2 ) ) || force ) ) { /* Set the returned flag to indicate that edge labelling is being used. */ edgelabs = 1; /* Initialise the pointer to the memory holding the bounding boxes for all labels (used by function Overlap). */ box = NULL; /* Get a pointer to the current Frame in the Plot. */ frame = astGetFrame( this, AST__CURRENT ); /* Initialize the id value for graphical element being drawn. */ gelid = AST__NUMLAB1_ID; /* If required, draw the labels for each axis in turn. */ for( axis = 0; axis < 2 && ink; axis++ ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); /* Plot them. */ info = grid[ axis ]; PlotLabels( this, esc, frame, axis, llist[ axis ], info->fmt, nedge[ axis ], &box, method, class, status ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); /* Set up the id for the next graphical element to be drawn. */ gelid = AST__NUMLAB2_ID; } /* Free the memory used to hold the bounding boxes. */ box = (float *) astFree( (void *) box ); /* Annul the pointer to the Frame. */ frame = astAnnul( frame ); } /* Free the memory used to store the label information. */ for( axis = 0; axis < 2; axis++ ){ ll = llist[ axis ]; if( ll ) { for( tick = 0; tick < nedge[ axis ]; tick ++ ) { ll->text = (char *) astFree( (void *) ll->text ); ll->just = (char *) astFree( (void *) ll->just ); ll++; } llist[ axis ] = (LabelList *) astFree( (void *) llist[ axis ] ); } } /* Return the flag indicating if edge labels were produced. */ return edgelabs; } static int EdgeCrossings( AstPlot *this, int edge, int axis, double axval, double *gap, double **cross, EdgeCrossingsStatics **pstatics, const char *method, const char *class, int *status ){ /* * * Name: * EdgeCrossings * Purpose: * Find all occurrences of a given physical axis value on an edge of the * plotting area. * Type: * Private function. * Synopsis: * #include "plot.h" * int EdgeCrossings( AstPlot *this, int edge, int axis, double axval, * double *gap, double **cross, * EdgeCrossingsStatics **pstatics, * const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function finds all occurences of a given physical axis value * along a specified edge of the plotting area. Firstly, a set of evenly * spaced points ("edge samples") are placed along the edge and the * corresponding physical coordinates are found. These physical coordinates * are then offset slightly from their original positions in the direction * of the "other" axis (i.e. index [ 1 - axis ] ), and transformed back * into graphics coordinates. These coordinates give the tangent vector * at each of the edge samples. * * To find the crossings, the supplied axis value is compared with the axis * value at each sample in turn, starting from one end of the edge and * working through to the other end. When a crossing is found, linear * interpolation is used between the two adjacent edge samples to find a * more accurate estimate of the crossing. The vector at the crossing * is also estimated by linear interpolation between the vectors at the two * adjacent samples. * * This basic algorithm fails if there is a discontinuity in the axis * values along the edge. For instance, if the edge covers a range of * Right Ascension from 23h to 1h, there will be a discontinuity at 0h * at which the RA values suddenly jump from 2*PI to zero. This jump * encompasses all normalised RA values and so every axis value would be * given a crossing at this point. To avoid this, a bad sample is * interposed between the two samples on either side of the * discontinuity. This prevents any crossings from being placed at the * discontinuity. * * There is a second problem related to discontinuities. If the supplied * axis value is zero (using the above RA example again), then no * crossings will be found, not only because of the extra bad sample, * but also because the samples will not quite cover the range of axis * values covered by the discontinuity because of the discrete nature * of the samples). To get round this, the sections on either side * of the discontinity are extended by a single sample. These extra * samples are assumed to be conincident with the neighbouring sample, * except that the value for the searched axis is modified to be a * linear extension from the neighbouring samples. * Parameters: * this * A pointer to the Plot. Supply a NULL pointer to release resources. * edge * The edge of the plotting area to be used. Edge 0 is the left hand * edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 * is the bottom edge. * axis * The index of the axis to which "axval" refers. * axval * The physical axis value to be searched for. * gap * Pointer to array of two values holding the gap between major * tick marks on the two axes. * cross * A pointer to the location at which to return a pointer to an * array of doubles holding the crossing information. Each crossing * is described by 4 doubles. The first pair are the graphiucs (x,y) * coordinates of the point on the edge at which the crossing occurs. * The second pair represents a unit vector in graphics coordinates * which is tangential to the curve of constant axis value at the * crossing. The memory allocated within this function to hold this * data should be freed using astFree when no longer needed. If no * crossings are found a NULL pointer is returned. * pstatics * Address of a pointer to a structure holding values for variables * which were statically defined within this function prior to the * thread-safe version of AST. If the pointer is supplied as NULL, * then a new structure is allocated and initialised. Any supplied * structure is freed if a NULL pointer is supplied for "this". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Return Value: * The number of crossings found. * Notes: * - This function allocates static resource on the first invocation * which should be freed when no more calls are to be made, by making a * final call with a NULL pointer supplied for "this". All other parameters * are then ignored. * - The static resources are re-initialised each time "edge" or * "axis" changes, and so the calling function should be structure in * order to minimise the number of times these parameter values change. * - If an error has already occurred, or if this function should * fail for any reason, zero is returned, and a NULL pointer is stored at * "cross". */ /* Local Variables: */ EdgeCrossingsStatics *statics; /* Structure holding static data */ AstMapping *mapping; /* Pointer to graphics->physical mapping */ AstPointSet *pset1a; /* Physical cooords at offset edge samples */ AstPointSet *pset2a; /* Physical cooords at offset edge samples */ AstPointSet *pset3; /* Physical cooords at offset edge samples */ AstPointSet *pset4a; /* Physical cooords at offset edge samples */ double **ptr1a; /* Pointer to physical coord. data */ double **ptr2a; /* Pointer to physical coord. data */ double **ptr3; /* Pointer to physical coord. data */ double **ptr4a; /* Pointer to physical coord. data */ double *data; /* Pointer to next item of crossing information */ double *p1; /* Pointer to graphics axis with constant value */ double *p1a; /* Pointer to graphics axis with constant value */ double *p2; /* Pointer to graphics axis with varying value */ double *p2a; /* Pointer to graphics axis with varying value */ double *q1; /* Pointer to physical axis being searched */ double *q1a; /* Pointer to physical axis being searched */ double *q2; /* Pointer to other physical axis */ double *q2a; /* Pointer to other physical axis */ double *v1; /* Pointer to vector component on axis 0 */ double *v2; /* Pointer to vector component on axis 1 */ double *v1a; /* Pointer to vector component on axis 0 */ double *v2a; /* Pointer to vector component on axis 1 */ double dd; /* The gap between edge samples */ double diff; /* Squared differences between adjacent edge samples */ double dl2; /* Squared vector length */ double dl; /* Vector length */ double dx; /* Vector X component */ double dy; /* Vector Y component */ double f; /* Weight for the current edge sample */ double offset; /* Physical offset */ double pp2; /* Varying graphics axis value at previous sample */ double pq1; /* Required physical axis value at previous sample */ double pv1; /* Previous vector component on axis 0 */ double pv2; /* Previous vector component on axis 1 */ double sum; /* Sum of squared differences between adjacent edge samples */ double value; /* The current graphics axis value */ double vx; /* Vector component on axis 0 at crossing */ double vy; /* Vector component on axis 1 at crossing */ double z; /* Varying graphics axis value at crossing */ int i; /* Edge sample index */ int iter; /* Iteration index */ int larger; /* Is current axis value larger than target? */ int logticks; /* Are major ticks logarithmically spaced? */ int ncross; /* No. of crossings */ int ndisc; /* No. of discontinuities along the edge */ int nsum; /* Number of values summed in "sum" */ int plarger; /* Was previous axis value larger than target? */ /* Get a pointer to the supplied statics object. */ statics = *pstatics; /* If a NULL Plot pointer has been supplied, release the static resources, and return. */ if( !this ){ if( statics ){ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); if( statics->pset4 ) statics->pset4 = astAnnul( statics->pset4 ); if( statics->frame ) statics->frame = astAnnul( statics->frame ); *pstatics = astFree( statics ); } return 0; } /* Initialise the number of crossings found, and the pointer to the place to store them. */ ncross = 0; *cross = NULL; /* Check the global status. */ if( !astOK ) return 0; /* If no statics structure was supplied, create one now and initialise it. */ if( !statics ) { statics = astMalloc( sizeof( EdgeCrossingsStatics ) ); if( statics ) { statics->frame = NULL; statics->pset1 = NULL; statics->pset2 = NULL; statics->pset4 = NULL; statics->ptr1 = NULL; statics->ptr2 = NULL; statics->ptr4 = NULL; statics->paxis = -1; statics->pedge = -1; *pstatics = statics; } } /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ pp2 = 0.0; pv1 = 0.0; pv2 = 0.0; plarger = 0; /* See if the major ticks on the other axis are logarithmically or linearly spaced. */ logticks = astGetLogTicks( this, 1 - axis ); /* Ensure that "edge" is in the range 0 - 3. */ edge = edge % 4; if( edge < 0 ) edge = -edge; /* If the edge or axis has changed since the last invocation, or if this is the first invocation, initialise some static data. */ /* ======================================================================*/ if( statics->pedge == -1 || statics->pedge != edge || statics->paxis != axis ){ /* Save the edge and axis. */ statics->pedge = edge; statics->paxis = axis; /* Annull any previous static data objects */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); if( statics->pset4 ) statics->pset4 = astAnnul( statics->pset4 ); if( statics->frame ) statics->frame = astAnnul( statics->frame ); /* Store some values so that the code does not need to consider each edge separately. First deal with the left hand edge. */ if( edge == 0 ){ statics->edgeax = 0; if( this->xrev ){ statics->edgeval = this->xhi; } else { statics->edgeval = this->xlo; } statics->edgehi = this->yhi; statics->edgelo = this->ylo; /* Now deal with the right hand edge. */ } else if( edge == 2 ){ statics->edgeax = 0; if( this->xrev ){ statics->edgeval = this->xlo; } else { statics->edgeval = this->xhi; } statics->edgehi = this->yhi; statics->edgelo = this->ylo; /* Now deal with the bottom edge. */ } else if( edge == 3 ){ statics->edgeax = 1; if( this->yrev ){ statics->edgeval = this->yhi; } else { statics->edgeval = this->ylo; } statics->edgehi = this->xhi; statics->edgelo = this->xlo; /* Finally deal with the top edge. */ } else { statics->edgeax = 1; if( this->yrev ){ statics->edgeval = this->ylo; } else { statics->edgeval = this->yhi; } statics->edgehi = this->xhi; statics->edgelo = this->xlo; } /* Get a pointer to the current Frame in the supplied Plot. */ statics->frame = astGetFrame( this, AST__CURRENT ); /* Get a pointer to the mapping from base to current Frame in the supplied Plot. */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Create a PointSet to hold the graphics coordinates at a set of regularly spaced points along the specified edge of the plotting area. */ pset1a = astPointSet( EDGETICKS_DIM, 2, "", status ); ptr1a = astGetPoints( pset1a ); /* Create a PointSet to hold the corresponding physical coordinates. */ pset2a = astPointSet( EDGETICKS_DIM, 2, "", status ); ptr2a = astGetPoints( pset2a ); /* Check they can be used. */ if( astOK ){ /* Set up the graphics coordinates. */ dd = ( statics->edgehi - statics->edgelo )/(double)( EDGETICKS_DIM - 1 ); value = statics->edgelo; p1 = ptr1a[ statics->edgeax ]; p2 = ptr1a[ 1 - statics->edgeax ]; for( i = 0; i < EDGETICKS_DIM; i++ ){ *(p1++) = statics->edgeval; *(p2++) = value; value += dd; } } /* Transform the graphics coordinates to physical coordinates, *without* normalising them into their normal ranges. */ (void) Trans( this, statics->frame, mapping, pset1a, 1, pset2a, 0, method, class, status ); /* Find the RMS step size along the axis. This is used to locate discontinuities along the edge. Do three rejection iterations. */ statics->limit = DBL_MAX; for( iter = 0; iter < 3; iter ++ ){ q1 = ptr2a[ axis ]; pq1 = AST__BAD; sum = 0.0; nsum = 0; for( i = 0; i < EDGETICKS_DIM; i++ ){ if( *q1 != AST__BAD && pq1 != AST__BAD ){ diff = *q1 - pq1; if( fabs( diff ) < statics->limit ){ sum += diff*diff; nsum++; } } pq1 = *(q1++); } if( nsum == 0 ) break; statics->limit = 3.0*sqrt( sum/(double)nsum ); } /* Now create another PointSet holding positions slightly offset from the physical coordinates at the edge samples. The offset is in the direction of the other physical axis. These positions are used to determine the vector at the crossings. */ if( nsum > 0 ){ pset3 = astPointSet( EDGETICKS_DIM, 2, "", status ); ptr3 = astGetPoints( pset3 ); /* Create a PointSet to hold the corresponding graphics coordinates. */ pset4a = astPointSet( EDGETICKS_DIM, 2, "", status ); ptr4a = astGetPoints( pset4a ); /* Check they can be used. */ if( astOK ){ /* Copy the physical coordinates from PointSet 2 to PointSet 3, offseting them slightly along the other axis. */ p1 = ptr2a[ axis ]; p2 = ptr2a[ 1 - axis ]; q1 = ptr3[ axis ]; q2 = ptr3[ 1 - axis ]; offset = 0.2*gap[ 1 - axis ]; pq1 = AST__BAD; for( i = 0; i < EDGETICKS_DIM; i++ ){ if( *p1 != AST__BAD && *p2 != AST__BAD ){ if( logticks ) offset = 0.2*(*p2)*( gap[ 1 -axis ] - 1.0 ); *(q2++) = *p2 + offset; } else { *(q2++) = AST__BAD; } pq1 = *(p1++); *(q1++) = pq1; p2++; } } /* Transform the physical coordinates to graphics coordinates. */ (void) Trans( this, NULL, mapping, pset3, 0, pset4a, 0, method, class, status ); /* Check they can be used. */ if( astOK ){ /* Modify the contents of PointSet 4 to represent the unit vector in graphics coordinates at each edge sample. */ p1 = ptr1a[ 0 ]; p2 = ptr1a[ 1 ]; q1 = ptr4a[ 0 ]; q2 = ptr4a[ 1 ]; for( i = 0; i < EDGETICKS_DIM; i++ ){ if( *p1 != AST__BAD && *p2 != AST__BAD && *q1 != AST__BAD && *q2 != AST__BAD ){ dx = *q1 - *p1; dy = *q2 - *p2; dl2 = dx*dx + dy*dy; if( dl2 > 0.0 ){ dl = sqrt( dl2 ); *q1 = dx/dl; *q2 = dy/dl; } else { *q1 = AST__BAD; *q2 = AST__BAD; } } else { *q1 = AST__BAD; *q2 = AST__BAD; } p1++; p2++; q1++; q2++; } } /* Annul the PointSet holding offset physical cooridnates. */ pset3 = astAnnul( pset3 ); /* Discontinuities in the axis values can cause problems. For instance, using the above PointSets, no tick mark could be put at 0 hours RA because of the discontinuity there. To get round this, 3 extra samples are added at each discontinuity, the first extends the continuous section which ends at the discontinuity, and the third extends the secion which starts at the discontinuity. This results in the two sections overlapping by one sample. The second is placed between these two and has a bad axis value. It prevents crossings from being found in between the values at the ends of the two sections. First count the number of discontinuities in the axis values. Discontinuites are defined as steps of more than 9 times the RMS step size. */ q1 = ptr2a[ axis ]; pq1 = AST__BAD; statics->limit *= 3.0; ndisc = 0; for( i = 0; i < EDGETICKS_DIM; i++ ){ if( *q1 != AST__BAD && pq1 != AST__BAD ){ if( fabs( *q1 - pq1 ) > statics->limit ) ndisc++; } pq1 = *(q1++); } /* Store the size of the new PointSets holding the extra samples. */ statics->dim = EDGETICKS_DIM + 3*ndisc; /* If there are no discontinuities, just clone the existing PointSets. */ if( !ndisc ){ statics->pset1 = astClone( pset1a ); statics->pset2 = astClone( pset2a ); statics->pset4 = astClone( pset4a ); statics->ptr1 = astGetPoints( statics->pset1 ); statics->ptr2 = astGetPoints( statics->pset2 ); statics->ptr4 = astGetPoints( statics->pset4 ); /* Otherwise, create new PointSets. */ } else { statics->pset1 = astPointSet( statics->dim, 2, "", status ); statics->ptr1 = astGetPoints( statics->pset1 ); statics->pset2 = astPointSet( statics->dim, 2, "", status ); statics->ptr2 = astGetPoints( statics->pset2 ); statics->pset4 = astPointSet( statics->dim, 2, "", status ); statics->ptr4 = astGetPoints( statics->pset4 ); /* Set up pointers used to walk through the arrays in the original PointSets and the new PointSets. */ p1 = statics->ptr1[ 0 ]; p2 = statics->ptr1[ 1 ]; q1 = statics->ptr2[ axis ]; q2 = statics->ptr2[ 1 - axis ]; v1 = statics->ptr4[ 0 ]; v2 = statics->ptr4[ 1 ]; p1a = ptr1a[ 0 ]; p2a = ptr1a[ 1 ]; q1a = ptr2a[ axis ]; q2a = ptr2a[ 1 - axis ]; v1a = ptr4a[ 0 ]; v2a = ptr4a[ 1 ]; /* Initialise the axis value at the previous sample. */ pq1 = AST__BAD; /* Check all samples in the original PointSets. */ for( i = 0; i < EDGETICKS_DIM; i++ ){ /* If this is the first point after a discontinuity... */ if( *q1a != AST__BAD && pq1 != AST__BAD ){ if( fabs( *q1a - pq1 ) > statics->limit ) { /* Insert an extra sample with the coordinates of the previous sample, but with an axis value which is linearly extrapolated from the previous samples. */ *(p1++) = p1a[ 0 ]; *(p2++) = p2a[ 0 ]; *(v1++) = v1a[ -1 ]; *(v2++) = v2a[ -1 ]; *(q2++) = q2a[ -1 ]; if( i > 1 && q1a[ -2 ] != AST__BAD ){ *(q1++) = 2.0*pq1 - q1a[ -2 ]; } else { *(q1++) = pq1; } /* Insert an extra sample with bad coordinates. */ *(p1++) = AST__BAD; *(p2++) = AST__BAD; *(v1++) = AST__BAD; *(v2++) = AST__BAD; *(q2++) = AST__BAD; *(q1++) = AST__BAD; /* Insert an extra sample with the cooridnates of the current sample, but with an axis value which is linearly extrapolated from the subsequent samples. */ *(p1++) = p1a[ -1 ]; *(p2++) = p2a[ -1 ]; *(v1++) = *v1a; *(v2++) = *v2a; *(q2++) = *q2a; if( i < EDGETICKS_DIM - 1 && q1a[ 1 ] != AST__BAD ){ *(q1++) = 2.0*(*q1a) - q1a[ 1 ]; } else { *(q1++) = pq1; } } } /* Save the current axis value. */ pq1 = *q1a; /* Copy the current input values to the new PointSets, and move on the next point in the original PointSets. */ *(p1++) = *(p1a++); *(p2++) = *(p2a++); *(q1++) = *(q1a++); *(q2++) = *(q2a++); *(v1++) = *(v1a++); *(v2++) = *(v2a++); } } /* Anull the original PointSets. */ pset4a = astAnnul( pset4a ); /* If all the physical coordinates are bad, indicate this by setting the limiting step size bad. */ } else { statics->limit = AST__BAD; } /* Anull the original PointSets. */ pset1a = astAnnul( pset1a ); pset2a = astAnnul( pset2a ); /* Annul the pointer to the mapping from base to current Frame. */ mapping = astAnnul( mapping ); } /* ======================================================================*/ /* The initialisation has now been done. Check the physical coordinate data can be used. */ if( astOK && statics->limit != AST__BAD ){ /* Store pointers to the graphics and physical coordinates at the first edge sample. */ p1 = statics->ptr1[ statics->edgeax ]; /* Graphics axis with constant value */ p2 = statics->ptr1[ 1 - statics->edgeax ]; /* Graphics axis with varying value */ q1 = statics->ptr2[ axis ]; /* Physical axis values to be searched */ q2 = statics->ptr2[ 1 - axis ]; /* The other physical axis */ /* Store pointers to the components of the unit vector at the first edge sample. */ v1 = statics->ptr4[ 0 ]; v2 = statics->ptr4[ 1 ]; /* Inidicate that there is currently no "previous sample". */ pq1 = AST__BAD; /* Check each point in turn... */ for( i = 0; i < statics->dim; i++ ){ /* Skip this point if the physical coordinates are undefined. */ if( *q1 != AST__BAD && *q2 != AST__BAD ){ /* Get a flag indicating if the required axis value has been exceeded at the current edge sample. */ larger = ( *q1 > axval ); /* If the state of this flag has changed since the previous edge sample, and if we know where the previous sample was, we have found a crossing. */ if( pq1 != AST__BAD && larger != plarger ){ /* Find the distance from the previous physical axis value to the required axis value, as a fraction of the distance from the previous axis value to the current axis value. Since the flag has changed, we know that the q1 value at this edge sample and the previous one must be different, so we know that the denominator is not zero. */ f = ( axval - pq1 )/( *q1 - pq1 ); /* Use linear interpolation to estimate the graphics axis value at the crossing. */ if( f != -1.0 ){ z = pp2 + f*( *p2 - pp2 ); /* Use linear interpolation to estimate the two components of the unit vector at the crossing. */ if( *v1 != AST__BAD && pv1 != AST__BAD && *v2 != AST__BAD && pv2 != AST__BAD ){ vx = pv1 + f*( *v1 - pv1 ); vy = pv2 + f*( *v2 - pv2 ); /* Normalise the vector. */ dl2 = vx*vx + vy*vy; if( dl2 > 0.0 ){ dl = sqrt( dl2 ); vx /= dl; vy /= dl; } else { vx = AST__BAD; vy = AST__BAD; } } else { vx = AST__BAD; vy = AST__BAD; } /* Grow the returned array to hold another crossing. */ ncross++; *cross = (double *) astGrow( (void *) *cross, ncross, 4*sizeof( double ) ); /* If succesful, store the crossing. */ if( astOK ) { data = *cross + 4*( ncross - 1 ); if( statics->edgeax ){ *(data++) = z; *(data++) = statics->edgeval; } else { *(data++) = statics->edgeval; *(data++) = z; } *(data++) = vx; *(data++) = vy; } } } /* Save the flag for use on the next pass through this loop. */ plarger = larger; } /* Save the varying graphics axis value and the required physical axis value at the current edge sample (also save the vector). */ pp2 = *p2; pq1 = *q1; pv1 = *v1; pv2 = *v2; /* Point to the next edge sample. */ p1++; p2++; q1++; q2++; v1++; v2++; } } /* If an error has occurred, free the array holding the crossings, and indicate that there are zero corssing. */ if( !astOK ) { *cross = (double *) astFree( (void *) *cross ); ncross = 0; } /* Return the answer. */ return ncross; } int astFindEscape_( const char *text, int *type, int *value, int *nc, int *status ){ /* *+ * Name: * astFindEscape * Purpose: * Check if a string starts with a graphics escape sequence. * Type: * Protected function. * Synopsis: * #include "plot.h" * int astFindEscape( const char *text, int *type, int *value, int *nc ) * Description: * This function returns a flag indiciating if the first character in * the supplied string is the start of a graphics escape sequence. If * so, the type and associated value (if any) of the escape sequence * are returned in "type" and "value", and the number of characters * occupied by the escape sequence is returned in "nc". If the * supplied text string does not begin with an escape sequence, the * number of characters before the first escape sequence is returned in * "nc" (the length of the string is returned in "nc" if the string * contains no escape sequences). * * This function can be used by grf modules which wish to implement * interpretation of escape sequences internally, rather than allowing the * Plot class to do the interpretation. * 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. 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 astGAttr 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. * 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. * * %^...+ - 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. * %^+ - 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. * * %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. * * %<...+ - 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. * * %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; * * %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; * * %w+ - Reset the Size attribute to its "normal" value. * * %f...+ - Change the Font attribute for subsequent characters. The * digits "..." give the new Font value. * * %f+ - Reset the Font attribute to its "normal" value. * * %c...+ - Change the Colour attribute for subsequent characters. The * digits "..." give the new Colour value. * * %c+ - Reset the Colour attribute to its "normal" value. * * %t...+ - Change the Style attribute for subsequent characters. The * digits "..." give the new Style value. * * %t+ - Reset the Style attribute to its "normal" value. * * %h+ - Remember the current horizontal position (see "%g+") * * %g+ - Go to the horizontal position of the previous "%h+" (if any). * * %- - Push the current graphics attribute values onto the top of * the stack (see "%+"). * * %+ - Pop attributes values of the top the stack (see "%-"). If * the stack is empty, "normal" attribute values are restored. * Notes: * - Zero is returned if an error has already occurred. *- */ /* Local Variables: */ int result; const char *a; const char *b; int nd; const char *perc; /* Initialise */ result = 0; *type = GRF__ESPER; *value = 0; *nc = 0; perc = NULL; /* Check inherited status and supplied pointer. */ if( !astOK || !text ) return result; /* Loop round, looking for percent signs. Break out of the loop when a complete escape sequence has been found and read, leaving the "b" pointer pointing to the first character following the escape sequence. */ b = NULL; a = text; while( ( a = strchr( a, '%' ) ) ) { perc = a; /* Compare the following character to each known escape sequence type. */ a++; if( *a == '%') { *type = GRF__ESPER; b = a + 1; break; } else if( *a == '^') { *type = GRF__ESSUP; } else if( *a == 'v') { *type = GRF__ESSUB; } else if( *a == '>') { *type = GRF__ESGAP; } else if( *a == '<') { *type = GRF__ESBAC; } else if( *a == 's') { *type = GRF__ESSIZ; } else if( *a == 'w') { *type = GRF__ESWID; } else if( *a == 'f') { *type = GRF__ESFON; } else if( *a == 'c') { *type = GRF__ESCOL; } else if( *a == 'g') { *type = GRF__ESG; } else if( *a == 'h') { *type = GRF__ESH; } else if( *a == 't') { *type = GRF__ESSTY; } else if( *a == '-') { *type = GRF__ESPSH; b = a + 1; break; } else if( *a == '+') { *type = GRF__ESPOP; b = a + 1; break; /* If the next character is illegal, skip to the next percent sign. */ } else { continue; } /* The escape sequence looks legal so far, so move on to the next character (if any). */ if( *(++a) ){ /* If the next character is a "+" sign, the attribute needs to be reset to its "normal" value. Indicate this by returning a value of "-1" (all usable values will be positive). */ if( *a == '+' ) { *value = -1; b = a + 1; break; /* Otherwise, to be a legal escape sequence, this character must be the first in a sequence of digits, terminated by a "+" sign.*/ } else if( (nd = 0, astSscanf( a, "%d%n+", value, &nd ))) { b = a + nd + 1; break; } } } /* Was a usable escape sequence found at the start of the supplied text? If so, return a function value of 1 and store the number of characters in the escape sequence. */ if( b && perc == text ) { result = 1; *nc = b - perc; /* Otherwise, return the preset function value of zero. If an escape sequence was found later in the text, return the number of characters prior to the escape sequence. */ } else if( b ) { *nc = perc - text; /* Otherwise, if no escape sequence was found, return the length of the supplied text. */ } else { *nc = strlen( text ); } /* Return the result. */ return result; } static int FindMajTicks( AstMapping *map, AstFrame *frame, int axis, double refval, double width, double gap, double *cen, int ngood, double *data, double **tick_data, int *status ){ /* * Name: * FindMajTicks * Purpose: * Place the major tick marks for a physical coordinate axis. * Type: * Private function. * Synopsis: * #include "plot.h" * int FindMajTicks( AstMapping *map, AstFrame *frame, int axis, * double refval, double width, double gap, double *cen, int ngood, * double *data, double **tick_data ) * Class Membership: * Plot member function. * Description: * The caller supplies an array of axis values (non-normalized), sorted * into ascending order (with any bad values at the end), together with * the gap size for the axis. The array of axis values is assumed to cover * the entire range which the axis can take within the plotting zone. The * first tick mark is placed just below the smallest axis value, at a * position which is an integral number of gaps away from the value * supplied in "cen" (if a value of AST__BAD is supplied for "cen" then * "cen = 0.0" is assumed). Notionally, tick marks are then placed at * intervals given by "gap" all the way upto, and just beyond, the * largest axis value. However, it could be that large sections of the * axis are not actually present within the plotting zone. For instance, * an RA axis covering the two hour range from 23h to 1h (centred on * 0h), will have some values at zero and some at 23.999.., but there * will be a large range inbetween these limits which is not represented * in the plotting area (i.e. the 22h range from 1h to 23h centred on * 12h). For this reason, tick marks are removed if there are no axis * values inbetween the tick mark and either of its neighbours. However, * small "holes" in the axis coverage are allowed, and ticks marks are * returned covering such small holes. Extra tick marks are also placed * at each end of the range to guard against the supplied array of axis * values not entirely covering the range of axis values in the plotting * area. * * For SkyFrames, positions which have latitude values outside the * normal ranges are ignored. Longitude ranges are not checked to * avoid problems with CAR projections. * * The returned tick mark values are placed into their primary domain * using the Norm1 method, but are NOT normalised using the astNorm * method for the supplied Frame. Duplicate tick marks values are * removed from the returned list. * Parameters: * map * Mapping from the Plot Base Frame to Plot Current Frame. * frame * Pointer to the Frame. * axis * Zero-based index of the axis being used. * refval * Value to use for the other axis (index [1-axis]) when placing * the tick mark values into their primary domain. * width * Range of used values on the other axis (index [1-axis]). * gap * The supplied value for the gaps between ticks on the axis. * cen * Pointer to the supplied axis value at which to put a central tick. * Other ticks will be placed evenly on either side of this tick. If * AST__BAD is provided, a value will be used which would put a tick * at an axis value of zero. The used value is returned. * ngood * The number of good values in the array pointer to by "data" (i.e. * values not equal to AST__BAD). * data * A pointer to an array holding sorted axis values (non-normalized) * covering the entire plotting area. * tick_data * A pointer to a place at which to store a pointer to an array * holding the returned tick mark values for the axis. * Returned Value: * The number of major tick mark values stored in the array pointer to * by "*tick_data". * Notes: * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned in "tick_data", and zero * is returned for the function value. */ /* Local Variables: */ double *r; /* Pointer to next tick value to be read */ double *ticks; /* Pointer to the axis values at the major tick marks */ double *w; /* Pointer to last tick value to be written */ double bot; /* Lowest axis value to be displayed */ double centre; /* The axis value at the first tick mark */ double delta; /* A safe distance from an axis limit */ double f; /* The nearest acceptable tick mark index */ double tmp; /* Temporary storage */ double top; /* Highest axis value to be displayed */ int inc; /* This times increase in nticks */ int k; /* Tick mark index */ int linc; /* Last times increase in nticks */ int lnfill; /* Last used value for nfill */ int nfill; /* No of tick marks to extend by at edges of coverage */ int nsame; /* Number of equal inc values there have been */ int nticks; /* Number of major tick marks used */ int ntnew; /* This times new value of nticks */ int use_nfill; /* nfill value which started this run of equal inc values */ /* Initialise the returned pointer. */ *tick_data = NULL; /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ nsame = 0; use_nfill = 0; /* Decide where to put the first major tick. Use any value supplied by the caller. Otherwise put it an integral number of gaps away from the origin. This would result in the origin being at a major tick mark. */ if( cen && *cen != AST__BAD ) { centre = *cen; } else { centre = gap*floor( 0.5 + data[ 0 ]/gap ); if( cen ) *cen = centre; } /* Find the number of candidate tick marks assuming an nfill value of 0. */ nfill = 0; nticks = FindMajTicks2( nfill, gap, centre, ngood, data, &ticks, status ); /* Loop round increasing the nfill value until an unreasonably large value of nfill is reached. The loop will exit early via a break statement when all small holes in the axis coverage are filled in. */ lnfill = nfill; linc = -100000; while( nfill < 100 && astOK ){ /* Increment the number of ticks added as "padding" at the edges of any gaps in the coverage of axis values. */ nfill++; /* Form a new set of tick mark values using this new nfill value */ ticks = (double *) astFree( (void *) ticks ); ntnew = FindMajTicks2( nfill, gap, centre, ngood, data, &ticks, status ); /* We need to know if the rate of increase of nticks has settled down to a constant value. Inititially increasing nfill will cause the total number of ticks (nticks) to increase rapidly. But this rate of increase will get less as any small gaps in axis coverage are filled in. We break out of the while loop when the rate of increase has settled down to a constant value (indicating that only very large holes are left in the axis coverage). Find the increase in the number of ticks caused by the increase in the nfill value made in this loop. If this increase is the same as the increase caused by the previous loop, increment the number of equal increases there have been. If the increase is different to last time, reset the number of equal increases to zero. */ inc = ntnew - nticks; if( inc == linc ) { nsame++; } else { nsame = 0; use_nfill = nfill; } /* If the past 3 increases in nfill has not caused any change in the rate of increase of nticks, then re-create the ticks for the value of nfill which started the current run of equal increment values, and leave the loop. */ if( nsame == 3 ) { ticks = (double *) astFree( (void *) ticks ); nticks = FindMajTicks2( use_nfill, gap, centre, ngood, data, &ticks, status ); break; } /* Save this times values for use in the next loop. */ linc = inc; nticks = ntnew; } /* Remove ticks which are not within the axis ranges to be displayed. Ticks which are very close to the limit are moved to a safe (but visually negligable) distance away from the limit). */ bot = astGetBottom( frame, axis ); top = astGetTop( frame, axis ); if( bot > top ) { tmp = top; top = bot; bot = tmp; } delta = 0.05*gap; r = ticks; for( k = 0; k < nticks; k++ ){ if( *r != AST__BAD ) { if( fabs( *r - bot ) < delta ) { *r = bot + delta; } else if( fabs( *r - top ) < delta ) { *r = top - delta; } else if( *r < bot || *r > top ) { *r = AST__BAD; } } r++; } /* Use the Mapping to place each tick mark value in its primary domain. This is a sort of normalization, similar but different to that performed by the astNorm method. */ Norm1( map, axis, nticks, ticks, refval, width, status ); /* Check for success. */ if( astOK ){ /* Ensure that all ticks marks are offset from the "centre" value by an integer multiple of the gap size. This is done by changing each tick value to the closest acceptable value. Also ensure that values close to zero (i.e. less than 1E-10 of the gap size) are set exactly to zero. */ r = ticks; for( k = 0; k < nticks; k++ ){ if( *r != AST__BAD ) { f = floor( 0.5 + ( *r - centre )/gap ); *r = f*gap + centre; if( fabs( *r ) < 1.0E-10*gap ) *r = 0.0; r++; } else { r++; } } /* Sort the tick values into increasing order. */ qsort( (void *) ticks, (size_t) nticks, sizeof(double), Compared ); /* Remove any duplicate or BAD tick values by shuffling the higher unique values down to over-write them. We subtract the centre value of both tick values before comparing them for equality in order to avoid unnecessarily removing tick marks in high precsion data. */ r = ticks + 1; w = ticks; for( k = 1; k < nticks && astOK; k++ ){ if( *r != AST__BAD && !EQUAL( *r-centre, *w-centre ) ){ w++; *w = *r; } r++; } /* Modify the number of ticks to exclude the duplicate ones. */ nticks = (int) ( w - ticks ) + 1; } /* If an error has occurred, free the memory holding the major tick mark values, and indicate that zero tick marks have been found. */ if( !astOK ){ ticks = (double *) astFree( (void *) ticks ); nticks = 0; } /* Store the pointer to the major tick mark values. */ *tick_data = ticks; /* Return the number of major ticks. */ return nticks; } static int FindMajTicks2( int nfill, double gap, double centre, int ngood, double *data, double **tick_data, int *status ){ /* * Name: * FindMajTicks2 * Purpose: * Find candidate major tick marks for FindMajTicks. * Type: * Private function. * Synopsis: * #include "plot.h" * int FindMajTicks2( int nfill, double gap, double centre, int ngood, * double *data, double **tick_data, int *status ) * Class Membership: * Plot member function. * Description: * A service routine for function FindMajTicks. * Parameters: * nfill * Number of tick marks to extend by at edges of coverage * gap * The supplied value for the gaps between ticks on the axis. * centre * The supplied axis value at which to put a central tick. * ngood * The number of good values in the array pointer to by "data" (i.e. * values not equal to AST__BAD). * data * A pointer to an array holding sorted axis values covering the * entire plotting area. * tick_data * A pointer to a place at which to store a pointer to an array * holding the returned tick mark values for the axis. * status * Pointer to the inherited status variable. * Returned Value: * The number of major tick mark values stored in the array pointer to * by "*tick_data". * Notes: * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned in "tick_data", and zero * is returned for the function value. */ /* Local Variables: */ double *ticks; /* Pointer to the axis values at the major tick marks */ int i; /* Index of current axis value */ int j; /* Index of filled in tick */ int k; /* Tick mark index */ int klast; /* Index of the previous tick mark */ int nticks; /* Number of major tick marks used */ /* Initialise the returned pointer. */ *tick_data = NULL; /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ nticks = 0; /* Reserve memory to hold a reasonable number of tick mark axis values. This memory is later extended as necessary. */ ticks = (double *) astMalloc( sizeof(double)*( 6*nfill + 14 ) ); /* Check that the pointer can be used. */ if( astOK ){ /* Put the first tick marks just below the lowest axis value (in case the grid did not sample the entire range of the axis). */ k = floor( ( data[ 0 ] - centre )/gap ); for ( i = 0; i < nfill; i++ ){ ticks[ i ] = gap*(double)( k - nfill + i ) + centre; } ticks[ nfill ] = gap*(double)( k ) + centre; /* Initialise the number of major tick marks found so far. */ nticks = nfill + 1; /* Loop round each of the remaining good ordered axis values. */ klast = k; for( i = 1; i < ngood && astOK; i++ ) { /* Find the tick marks enclosing the axis value. The tick mark placed at "centre" is called tick mark zero, and tick marks are indexed (positive or negative) from an origin at "centre". Find the index of the more negative of the two tick marks enclosing the axis value. */ k = floor( ( data[ i ] - centre )/gap ); /* Ensure that the tick marks enclosing the current axis value are used. Some extra tick marks are used at the start and end of any gaps in the axis coverage. This is done to "fill in" small holes caused by the grid of physical coordinate values not completely covering the plotting area. Large holes, such as occur on an RA axis covering the 2 hour range from 23 hours to 1 hour are left without any tick marks in them (the "hole" in this case is the 22 hours range from 1 hour to 23 hours). */ for( j = 0; j < nfill + 1; j++ ){ if( k - klast > nfill + 2 - j ) { ticks = (double *) astGrow( ticks, nticks + 1, sizeof( double ) ); if( astOK ) ticks[ nticks++ ] = gap*(double)( klast + nfill + 1 - j ) + centre; } if( k - klast > nfill - j ) { ticks = (double *) astGrow( ticks, nticks + 1, sizeof( double ) ); if( astOK ) ticks[ nticks++ ] = gap*(double)( k - nfill + j ) + centre; } } /* Save the index of the current tick mark. */ klast = k; } /* Add extra tick marks beyond the end in case the grid did not sample the entire range of the axis. */ ticks = (double *) astGrow( ticks, nticks + nfill + 1, sizeof( double ) ); for( i = 0; i < nfill && astOK; i++ ){ ticks[ nticks++ ] = gap*(double)( klast + i + 1 ) + centre; } } /* If an error has occurred, free the memory holding the major tick mark values, and indicate that zero tick marks have been found. */ if( !astOK ){ ticks = (double *) astFree( (void *) ticks ); nticks = 0; } /* Store the pointer to the major tick mark values. */ *tick_data = ticks; /* Return the number of major ticks. */ return nticks; } static int FindDPTZ( AstFrame *fr, int axis, const char *fmt, const char *text, int *ndp, int *ntz, int *status ) { /* * Name: * FindDPTZ * Purpose: * Find the number of decimal places and trailing zeros in a label. * Type: * Private function. * Synopsis: * #include "plot.h" * int FindDPTZ( AstFrame *fr, int axis, const char *fmt, * const char *text, int *ndp, int *ntz, int *status ) * Class Membership: * Plot member function. * Description: * The supplied label is split into fields using the astFields method of * the supplied frame. The number of decimal places in the last * field is returned in *ndp, and the total number of trailing zeros * (excluding exponents) is returned in *ntz. * Parameters: * fr * The frame. * axis * The axis index to which the label applies. * fmt * The format string used to format the label. * text * The text of the label. * ndp * Pointer to an int in which to return the number of decimal * places in the final field. * ntz * Pointer to an int in which to return the number of trailing zeros. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if and only if a non-zero digit is found in any field. */ /* Local Constants: */ #define MAXFLD 10 /* Local Variables: */ char *fields[ MAXFLD ]; const char *a; const char *dot; const char *ff; double junk; int fnc; int i; int j; int l; int mxnd; int nc[ MAXFLD ]; int nf; int result; /* Initialise */ *ndp = 0; *ntz = 0; result = 0; /* Check inherited status */ if( !astOK ) return result; /* Split the label up into fields. */ nf = astFields( fr, axis, fmt, text, MAXFLD, fields, nc, &junk ); if( nf > 0 ) { /* Search the last fields (assumed to be the least significant) for a decimal point. */ ff = fields[ nf - 1 ]; fnc = nc[ nf - 1 ]; dot = strchr( ff, '.' ); if( dot && ( ff - dot >= fnc ) ) dot = NULL; /* Find the number of digits following the decimal point. */ if( dot ) { *ndp = strspn( dot + 1, "0123456789" ); mxnd = fnc - ( dot - ff ) - 1; if( *ndp > mxnd ) *ndp = mxnd; } else { *ndp = 0; } /* Loop through all the fields, from least significant to most significant, counting the number of trailing zeros. */ *ntz = 0; for( i = nf - 1; i >= 0; i-- ) { l = strspn( fields[ i ], "-+0123456789." ); if( l > nc[ i ] ) l = nc[ i ]; a = fields[ i ] + l - 1; for( j = l - 1; j >= 0; j--,a-- ){ if( *a == '0' ) { (*ntz)++; } else if( isdigit( *a ) ) { result = 1; break; } } if( j >= 0 ) break; } } /* Return the result. */ return result; /* Undefine local constants: */ #undef MAXFLD } static int FindString( int n, const char *list[], const char *test, const char *text, const char *method, const char *class, int *status ){ /* * Name: * FindString * Purpose: * Find a given string within an array of character strings. * Type: * Private function. * Synopsis: * #include "plot.h" * int FindString( int n, const char *list[], const char *test, * const char *text, const char *method, const char *class, * int *status ) * Class Membership: * Plot method. * Description: * This function identifies a supplied string within a supplied * array of valid strings, and returns the index of the string within * the array. The test option may not be abbreviated, but case is * insignificant. * Parameters: * n * The number of strings in the array pointed to be "list". * list * A pointer to an array of legal character strings. * test * A candidate string. * text * A string giving a description of the object, parameter, * attribute, etc, to which the test value refers. * This is only for use in constructing error messages. It should * start with a lower case letter. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The index of the identified string within the supplied array, starting * at zero. * Notes: * - A value of -1 is returned if an error has already occurred, or * if this function should fail for any reason (for instance if the * supplied option is not specified in the supplied list). */ /* Local Variables: */ int ret; /* The returned index */ /* Check global status. */ if( !astOK ) return -1; /* Compare the test string with each element of the supplied list. Leave the loop when a match is found. */ for( ret = 0; ret < n; ret++ ) { if( !Ustrcmp( test, list[ ret ], status ) ) break; } /* Report an error if the supplied test string does not match any element in the supplied list. */ if( ret >= n ) { astError( AST__OPT, "%s(%s): Illegal value '%s' supplied for %s.", status, method, class, test, text ); ret = -1; } /* Return the answer. */ return ret; } static char *FindWord( char *ptr, const char *d, const char **p, int *status ) { /* * Name: * FindWord * Purpose: * Return a copy of the next word in a supplied string. * Type: * Private function. * Synopsis: * #include "plot.h" * char *FindWord( char *ptr, const char *d, const char **p, int *status ) * Class Membership: * Plot method. * Description: * This function locates the start and end of the first word in the * string pointed to by *p, and returns a copy of the word. The pointer * *p is modified to point to the start of the following word (if any). * The characters which delimit words are supplied in string "d". * Parameters: * ptr * A pointer to a character string in which to store the returned * word. The memory holding this string should have been allocated * using one of the functions in the AST "memory" module. The memory * area will be modified in size to fit the returned word. A NULL * pointer may be supplied if no memory has yet been allocated. * Any memory pointed to by ptr is freed if a NULL pointer is * returned by this function (i.e. if no word is found). * d * A string holding the characters which are to be used as word * delimiters. * p * The address of a character string pointer. On entry, this pointer * identifies the start of the string to be searched. On exit, it is * modified to point to the start of the following word. It is * returned NULL if there are no more words. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated character string holding the * next word, or NULL if no word could be found. */ /* Local Variables: */ const char *a, *b, *c; char *ret; int nc; /* Free any allocated memory and return if any of the supplied pointers (except ptr) is NULL, or if an error has occurred. */ if( !astOK || !d || !p || !*p ) { (void) astFree( (void *) ptr ); return NULL; } /* Get a pointer to the first character which is not in "d". Terminate the loop if a null character is encountered. */ a = *p; while( *a && strchr( d, (int) *a ) ) a++; /* Get a pointer to the next character which is in "d". Terminate the loop if a null character is encountered. */ b = a; while( *b && !strchr( d, (int) *b ) ) b++; /* Get a pointer to the next character which is not in "d". Terminate the loop if a null character is encountered. */ c = b; while( *c && strchr( d, (int) *c ) ) c++; /* Adjust the supplied pointer so that it points to the start of the next word. */ if( *c ){ *p = c; } else { *p = NULL; } /* Get a null-terminated copy of the word between a and b. */ nc = b - a; if( nc > 0 ) { ret = (char *) astStore( (void *) ptr, (void *) a, (size_t) (nc + 1) ); ret[ nc ] = 0; } else { ret = astFree( (void *) ptr ); } return ret; } static const char *SplitValue( AstPlot *this, const char *value, int axis, int *split, int *status ) { /* * Name: * FormatValue * Purpose: * Format a coordinate value for a Frame axis. * Type: * Private function. * Synopsis: * #include "plot.h" * const char *SplitValue( AstPlot *this, const char *value, * int axis, int *split ) * Class Membership: * Plot member function * Description: * This function splits long formatted values (such as the date/time * format produced by the TimeFrame class) if possible onto two lines * by inclusion of Plot escape sequences. * Parameters: * this * Pointer to the Plot. * value * The formatted coordinate value. * axis * Indicates whether or not short lines should be split by * including a blank first line. If zero, and if "*split" is non-zero, * then short lines are put onto the second line,and the first line * is blank. * split * Pointer to an integer that controls behaviour: * * 0 - Split the line if it is too long, and return a value of +1 * in *split. * 1 - Split the line even if it does not need splitting, making * the first line blank and the second line containing all the * supplied text (*split is unchanged on exit). * Returned Value: * A pointer to a static buffer containing a null-terminated string * holding the (possibly split) formatted value. This will be a copy of * the supplied pointer if the string does not need to be split. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS char *d; const char *result; float rsp; int aft_end; int aft_start; int bef_end; int bef_start; int i; int id; int idmin; int imin; int l; int naft; int nbef; int nlong; int nshort; int nsp; /* Initialise */ result = value; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Do nothing more if the formatted value already contains graphical escape sequences, or if graphical escapes sequences are not being interpreted. */ if( value && astGetEscape( this ) && !HasEscapes( value, status ) ) { /* Attempt to find a space close to the centre of the formatted string. */ l = strlen( value ); idmin = 2*l; imin = -1; for( i = 0; i < l; i++ ) { if( isspace( value[ i ] ) ) { id = abs( i - l/2 ); if( id < idmin ) { idmin = id; imin = i; } } } /* We split the line if previous lines have been split (i.e. if *split was non-zero on entry) or if this line is long AND it contains a space. This means that a sequence of long labels will not be split unless they contain spaces. */ if( *split || ( l > 9 && imin != -1 ) ) { *split = 1; /* Initialse the pointer into the returned buffer at which the next character will be placed. */ d = splitvalue_buff; /* If no spaces were found... */ if( imin == -1 ) { /* If axis is zero, we add a blank first line. */ if( axis == 0 ) { /* Fill the first line with spaces. */ for( i = 0; i < l; i++ ) *(d++) = ' '; /* Add an escape sequence that moves down by one character height. */ d += sprintf( d, "%%v170+" ); } /* Add the whole of the supplied text. */ for( i = 0; i < l; i++ ) *(d++) = value[ i ]; /* If a space was found... */ } else { /* Find the first and last non-blank characters before the mid-space. */ bef_start = -1; bef_end = -1; for( i = 0; i < imin; i++ ) { if( !isspace( value[ i ] ) ) { if( bef_start == -1 ) bef_start = i; bef_end = i; } } /* Find the first and last non-blank characters after the mid-space. */ aft_start = -1; aft_end = -1; for( i = imin + 1; i < l; i++ ) { if( !isspace( value[ i ] ) ) { if( aft_start == -1 ) aft_start = i; aft_end = i; } } /* How many significant characters before and after the space? */ nbef = bef_end - bef_start + 1; naft = aft_end - aft_start + 1; /* Get the lengths of the longer and shorter line. */ if( nbef > naft ) { nlong = nbef; nshort = naft; } else { nlong = naft; nshort = nbef; } /* Find the fractional number of spaces before the significant text of the shorter line.*/ rsp = 0.5*( nlong - nshort + 1 ); /* If the top line is the shorter line, put some spaces in at the start. */ if( nbef < naft ) { nsp = (int) rsp; for( i = 0; i < nsp; i++ ) *(d++) = ' '; } /* Add the significant text from the top line. */ for( i = bef_start; i <= bef_end; i++ ) *(d++) = value[ i ]; /* Add an escape sequence that moves down by one character height. */ d += sprintf( d, "%%v100+" ); /* Add an escape sequence that moves to the left by the required amount. */ d += sprintf( d, "%%<%d+", (int) ( 60.0*( (float) nlong - rsp )) ); /* Add the significant text from the bottom line. */ for( i = aft_start; i <= aft_end; i++ ) *(d++) = value[ i ]; } /* Terminate it. */ *d = 0; /* Return a pointer to the buffer. */ result = splitvalue_buff; } } /* If an error occurred, clear the returned value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static void Fpoly( AstPlot *this, const char *method, const char *class, int *status ){ /* * Name: * Fpoly * Purpose: * Flush all stored poly lines to the graphics system. * Type: * Private function. * Synopsis: * #include "plot.h" * void Fpoly( AstPlot *this, const char *method, const char *class, * int *status ) * Class Membership: * Plot member function. * Description: * This function sends all previously drawn poly lines to the graphics * system for rendering, and frees the memory used to hold the poly * lines. It attempts to reduce the number of graphics calls by * concatenating continuous polylines together. * Parameters: * this * Pointer to the Plot. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS float xmid; float xt; float ymid; float *xnew; float *ynew; int polylen; float *xp1; float *xp2; float *yp1; float *yp2; float yt; int *ekey; int *p; int *skey; int *drawn; int ihi; int ikey; int ilo; int imid; int ipass; int ipoint; int ipoly; int jpoly; int kpoly; int *polylist; int npoly; int np; /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Output any pending polyline. */ Opoly( this, status ); /* If there is just one polyline to output, just draw it and then free the memory used to hold the polyline. */ if( Poly_npoly == 1 ) { GLine( this, Poly_np[ 0 ], Poly_xp[ 0 ], Poly_yp[ 0 ], method, class, status ); Poly_xp[ 0 ] = astFree( Poly_xp[ 0 ] ); Poly_yp[ 0 ] = astFree( Poly_yp[ 0 ] ); Poly_np[ 0 ] = 0; /* If there are multiple polylines to output, see if any of them can be combined before drawing them. */ } else if( Poly_npoly > 1 ) { /* No polyline buffer allocated yet. */ xnew = NULL; ynew = NULL; /* Allocate an array to hold the order in which polylines should be concatenated. Each value in this array will be the index of one of the original polylines. A positive index indicates that the polyline should be appended in its original order. A negative index indicates that the polyline should be appended in reversed order. Polyline zero is always appended in its original order. */ polylist = astMalloc( Poly_npoly*sizeof( int ) ); npoly = 0; /* Create an array of drawn, one for each individual polyline. The flag is zero if the corresponding polyline has not yet been drawn. */ drawn = astCalloc( Poly_npoly, sizeof( int ) ); /* Create two sorted keys for the polylines - one that sorts them into increasing x at the start of the polyline, and another that sorts them into increasing x at the end of the polyline. */ skey = astMalloc( Poly_npoly*sizeof( int ) ); ekey = astMalloc( Poly_npoly*sizeof( int ) ); if( astOK ) { p = skey; for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) *(p++) = ipoly; qsort( skey, Poly_npoly, sizeof(int), Fpoly_scmp ); p = ekey; for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) *(p++) = ipoly; qsort( ekey, Poly_npoly, sizeof(int), Fpoly_ecmp ); } /* Continue to search for separate polylines that can be combined together until we know there are no more. */ while( astOK ) { /* Search for the first polyline that has not already been drawn. */ for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) { if( !drawn[ ipoly ] ) break; } /* Leave the loop if no more polylines remain to be plotted. */ if( ipoly == Poly_npoly ) break; /* Initialise the list of polylines to hold the polyline found above, in its forward sense. */ polylist[ 0 ] = ipoly; npoly = 1; drawn[ 0 ] = 1; /* Initialise the concatenation point to be the end of the polyline found above. Also, initialise the total number of points in the combined polyline (polylen). */ ipoint = Poly_np[ ipoly ] - 1; xt = Poly_xp[ ipoly ][ ipoint ]; yt = Poly_yp[ ipoly ][ ipoint ]; polylen = ipoint + 1; /* Loop until we can find no more polylines to append to the list. A polyline can be appended if it starts or ends at the current concatenation point. */ while( astOK ) { /* On the first pass through the next loop, search for a polyline that starts at the concatenation point. If no such polyline is found, do a second pass in which we search for a polyline that ends at the concatenation point. Do not include any previously drawn polylines in the search. */ for( ipass = 0; ipass < 2; ipass++ ) { /* We use a binary chop to find a polyline which starts (or ends) at the x value of the concatenation point. */ jpoly = -1; ilo = 0; ihi = Poly_npoly - 1; while( 1 ) { imid = ( ilo + ihi )/2; if( ipass == 0 ) { jpoly = skey[ imid ]; xmid = Poly_xp[ jpoly ][ 0 ]; } else { jpoly = ekey[ imid ]; xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; } if( EQUAL( xmid, xt ) ) { ikey = imid; break; } else if( xmid > xt ) { if( ihi == imid ) { if( ipass == 0 ) { jpoly = skey[ ilo ]; xmid = Poly_xp[ jpoly ][ 0 ]; } else { jpoly = ekey[ ilo ]; xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; } if( !EQUAL( xmid, xt ) ) jpoly = -1; ikey = ilo; break; } ihi = imid; } else { if( ilo == imid ) { if( ipass == 0 ) { jpoly = skey[ ihi ]; xmid = Poly_xp[ jpoly ][ 0 ]; } else { jpoly = ekey[ ihi ]; xmid = Poly_xp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; } if( !EQUAL( xmid, xt ) ) jpoly = -1; ikey = ihi; break; } ilo = imid; } } /* If found, there may be more than one such polyline. So we now search for a polyline that also has the y value of the concatenation point. */ if( jpoly != -1 ) { /* If the polyline found above starts (or ends) at the same Y value as the concatenation point, then we have found the required polyline. */ if( ipass == 0 ) { ymid = Poly_yp[ jpoly ][ 0 ]; } else { ymid = Poly_yp[ jpoly ][ Poly_np[ jpoly ] - 1 ]; } if( EQUAL( ymid, yt ) && !drawn[ jpoly ] ) break; jpoly = -1; /* Otherwise, search down the list, starting at the polyline found above. */ if( imid > 0 ) { for( ikey = imid - 1; ikey >= 0; ikey-- ) { if( ipass == 0 ) { kpoly = skey[ ikey ]; xmid = Poly_xp[ kpoly ][ 0 ]; ymid = Poly_yp[ kpoly ][ 0 ]; } else { kpoly = ekey[ ikey ]; xmid = Poly_xp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; ymid = Poly_yp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; } if( EQUAL( xmid, xt ) ) { if( EQUAL( ymid, yt ) && !drawn[ kpoly ] ) { jpoly = kpoly; break; } } else { break; } } if( jpoly != -1 ) break; } /* Now search up the list, starting at the polyline found above. */ if( imid < Poly_npoly - 1 ) { for( ikey = imid + 1; ikey < Poly_npoly; ikey++ ) { if( ipass == 0 ) { kpoly = skey[ ikey ]; xmid = Poly_xp[ kpoly ][ 0 ]; ymid = Poly_yp[ kpoly ][ 0 ]; } else { kpoly = ekey[ ikey ]; xmid = Poly_xp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; ymid = Poly_yp[ kpoly ][ Poly_np[ kpoly ] - 1 ]; } if( EQUAL( xmid, xt ) ) { if( EQUAL( ymid, yt ) && !drawn[ kpoly ] ) { jpoly = kpoly; break; } } else { break; } } if( jpoly != -1 ) break; } } } /* If a polyline was found that can be combined with the total polyline, increment the total number of points in the total polyline, add it to the list, and update the concatenation point. Note, we can omit the start or end point of the new polyline since it will already be present in the total polyline, hence the " - 1 " below. */ if( ipass < 2 ) { ipoint = Poly_np[ jpoly ] - 1; if( ipass == 0 ) { polylist[ npoly++ ] = jpoly; xt = Poly_xp[ jpoly ][ ipoint ]; yt = Poly_yp[ jpoly ][ ipoint ]; } else { polylist[ npoly++ ] = -jpoly; xt = Poly_xp[ jpoly ][ 0 ]; yt = Poly_yp[ jpoly ][ 0 ]; } polylen += ipoint; /* Indicate the polyline has been drawn. */ drawn[ jpoly ] = 1; /* If we cannot find any polyline that starts or ends at the concatenation point, then we have completed the total polyline. So break out of the loop, and move on to draw the total polyline. */ } else { break; } } /* If a single polyline is to be drawn, just draw it. */ if( npoly == 1 ) { jpoly = polylist[ 0 ]; GLine( this, Poly_np[ jpoly ], Poly_xp[ jpoly ], Poly_yp[ jpoly ], method, class, status ); /* If more than one polyline is to be drawn, ensure we have arrays that are large enough to hold all the vertices in the combined polyline. */ } else { xnew = astRealloc( xnew, polylen*sizeof( float ) ); ynew = astRealloc( ynew, polylen*sizeof( float ) ); if( astOK ) { /* Loop round all the polylines that are to be combined to form the total polyline, and copy all the vertex coordinates into the above arrays. */ xp1 = xnew; yp1 = ynew; for( ipoly = 0; ipoly < npoly; ipoly++ ) { /* Index of the next polyline to include in the total polyline. */ jpoly = polylist[ ipoly ]; /* The jpoly value is positive if the polylline is to be inclued in its original direction. */ if( jpoly >= 0 ) { /* Use the whole of the first polyline. */ if( ipoly == 0 ) { np = Poly_np[ jpoly ]; xp2 = Poly_xp[ jpoly ]; yp2 = Poly_yp[ jpoly ]; /* Omit eh first point of subsequent polylines since it will be the same as the last pointy already in the total polyline. */ } else { np = Poly_np[ jpoly ] - 1; xp2 = Poly_xp[ jpoly ] + 1; yp2 = Poly_yp[ jpoly ] + 1; } /* Copy the vertex values in their original order, and update the pointers to the next element of the total polyline. */ memcpy( xp1, xp2, np*sizeof(float) ); memcpy( yp1, yp2, np*sizeof(float) ); xp1 += np; yp1 += np; /* The jpoly value is negative if the polyline is to be included in its reversed direction. */ } else { jpoly = -jpoly; /* Get the number of points to copy. Omit the last point if this is not the first polyline, since it is already in the total polyline. */ if( ipoly == 0 ) { np = Poly_np[ jpoly ]; } else { np = Poly_np[ jpoly ] - 1; } /* Copy the individual values in reversed order. */ xp2 = Poly_xp[ jpoly ] + np - 1; yp2 = Poly_yp[ jpoly ] + np - 1; for( ipoint = 0; ipoint < np; ipoint++ ) { *(xp1++) = *(xp2--); *(yp1++) = *(yp2--); } } } /* And finally, draw the total polyline. */ GLine( this, polylen, xnew, ynew, method, class, status ); } } } /* Free all the individual polylines. */ for( ipoly = 0; ipoly < Poly_npoly; ipoly++ ) { Poly_xp[ ipoly ] = astFree( Poly_xp[ ipoly ] ); Poly_yp[ ipoly ] = astFree( Poly_yp[ ipoly ] ); Poly_np[ ipoly ] = 0; } /* Free other resources. */ polylist = astFree( polylist ); drawn = astFree( drawn ); xnew = astFree( xnew ); ynew = astFree( ynew ); skey = astFree( skey ); ekey = astFree( ekey ); } /* Indicate that all polylines have been sent to the graphics system. */ Poly_npoly = 0; } static int Fpoly_ecmp( const void *a, const void *b ){ /* * Name: * Fpoly_ecmp * Purpose: * Compare two polylines ending X position * Type: * Private function. * Synopsis: * #include "plot.h" * int Fpoly_ecmp( const void *a, const void *b ) * Class Membership: * Plot member function. * Description: * This function is designed to be used as a comparison function with * the "qsort" function. It is used in function Fpoly. * * If orders the two polylines on the basis of the X coordinate at * their ends. * Parameters: * a * Pointer to an int holding the index of the first polyline. * b * Pointer to an int holding the index of the second polyline. * Returned Value: * -1 if the first polyline ends at a lower X than the second. * +1 if the first polyline ends at a higher X than the second. * 0 if the two polylines end at the same X. */ /* Local Variables: */ float xa; /* X at end of first polyline */ float xb; /* X at end of second polyline */ int result = 0; /* Returned value */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get the x coord at the end of the two polylines. */ xa = Poly_xp[ *( (int *) a) ][ Poly_np[ *( (int *) a) ] - 1 ]; xb = Poly_xp[ *( (int *) b) ][ Poly_np[ *( (int *) b) ] - 1 ]; /* Compare them. */ if( xa < xb ) { result = -1; } else if( xa > xb ){ result = 1; } return result; } static int Fpoly_scmp( const void *a, const void *b ){ /* * Name: * Fpoly_scmp * Purpose: * Compare two polylines starting X position * Type: * Private function. * Synopsis: * #include "plot.h" * int Fpoly_scmp( const void *a, const void *b ) * Class Membership: * Plot member function. * Description: * This function is designed to be used as a comparison function with * the "qsort" function. It is used in function Fpoly. * * If orders the two polylines on the basis of the X coordinate at * their starts. * Parameters: * a * Pointer to an int holding the index of the first polyline. * b * Pointer to an int holding the index of the second polyline. * Returned Value: * -1 if the first polyline starts at a lower X than the second. * +1 if the first polyline starts at a higher X than the second. * 0 if the two polylines starts at the same X. */ /* Local Variables: */ float xa; /* X at start of first polyline */ float xb; /* X at start of second polyline */ int result = 0; /* Returned value */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get the x coord at the start of the two polylines. */ xa = Poly_xp[ *( (int *) a) ][ 0 ]; xb = Poly_xp[ *( (int *) b) ][ 0 ]; /* Compare them. */ if( xa < xb ) { result = -1; } else if( xa > xb ){ result = 1; } return result; } static AstFrameSet *Fset2D( AstFrameSet *fset, int ifrm, int *status ) { /* * Name: * Fset2D * Purpose: * Create a FrameSet with no more than 2 dimensions for a given Frame. * Type: * Private function. * Synopsis: * #include "plot.h" * AstFrameSet *Fset2D( AstFrameSet *fset, int ifrm, int *status ) * Class Membership: * Plot method. * Description: * This function checks a specified Frame in the supplied FrameSet. * If the Frame has more than 2 dimensions, a new Frame is added to * the FrameSet containing just the first two axes of the specified * Frame. A PermMap is used to connect this Frame to the specified * Frame, which supplied bad values for any missing axes. If the * specified Frame is the base Frame in the supplied FrameSet, then the * new Frame becomes the base Frame in the returned FrameSet. Like-wise, * if the specified Frame is the current Frame, then the new Frame * will be the current Frame in the returned FrameSet. * * If the specified Frame does not have more than 2 axes, then a clone * of the FrameSet pointer is returned, otherwise the returned pointer * points to a copy of the supplied FrameSet with the new 2-D Frame * added. * Parameters: * fset * Pointer to the FrameSet. * ifrm * The index of the Frame to check. This should be AST__BASE or * AST_CURRENT. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a FrameSet in which the Frame with index given by ifrm * has no more than 2 axes. */ /* Local Variables: */ AstFrame *frm; AstFrame *newfrm; AstFrameSet *ret; AstPermMap *map; double zero; int *inperm; int axes[2]; int i; int ic; int nax; /* Check the inherited status. */ if( !astOK ) return NULL; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ map = NULL; /* Get a pointer to the requested Frame in the supplied FrameSet. */ frm = astGetFrame( fset, ifrm ); /* See how many dimensions the specified Frame of the supplied FrameSet has. */ nax = astGetNaxes( frm ); /* If it is more than 2-dimensionbal, create a 2D Frame by picking axes 1 and 2 from the original Frame. */ if( nax > 2 ) { axes[ 0 ] = 0; axes[ 1 ] = 1; newfrm = astPickAxes( frm, 2, axes, NULL ); /* Create a PermMap to describe the mapping between the two Frames. Use zero as the value for unknown axes (the optional mapping which can be returned by astPickAxes uses AST__BAD for unknown axes). */ inperm = (int *) astMalloc( sizeof(int)*(size_t) nax ); if( astOK ){ inperm[ 0 ] = 0; inperm[ 1 ] = 1; for( i = 2; i < nax; i++ ) inperm[ i ] = -1; zero = 0.0; map = astPermMap( nax, inperm, 2, axes, &zero, "", status ); inperm = (int *) astFree( (void *) inperm ); } /* Get a copy of the supplied FrameSet. */ ret = astCopy( fset ); /* Add the new Frame to the FrameSet (it becomes the current Frame). */ ic = astGetCurrent( ret ); astAddFrame( ret, ifrm, map, newfrm ); newfrm = astAnnul( newfrm ); /* If the new Frame was derived from the base frame, set the new base Frame, and re-instate the original current Frame */ if( ifrm == AST__BASE ){ astSetBase( ret, astGetCurrent( ret ) ); astSetCurrent( ret, ic ); } /* If the specified Frame in the supplied FrameSet is 2-dimensional, just return a clone of it. */ } else { ret = astClone( fset ); } /* Annul the pointer to the original Frame. */ frm = astAnnul( frm ); return ret; } static int FullForm( const char *list, const char *test, const char *text, const char *method, const char *class, int *status ){ /* * Name: * FullForm * Purpose: * Identify the full form of an option string. * Type: * Private function. * Synopsis: * #include "plot.h" * int FullForm( const char *list, const char *test, const char *text, * const char *method, const char *class, int *status ) * Class Membership: * Plot method. * Description: * This function identifies a supplied test option within a supplied * list of valid options, and returns the index of the option within * the list. The test option may be abbreviated, and case is * insignificant. * Parameters: * list * A list of space separated option strings. * test * A candidate option string. * text * A string giving the context in which the supplied test option * was supplied. For instance, this may be an attribute setting string. * This is only for use in constructing error messages. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The index of the identified option within the supplied list, starting * at zero. * Notes: * - A value of -1 is returned if an error has already occurred, or * if this function should fail for any reason (for instance if the * supplied option is not uniquely specified in the supplied list). */ /* Local Variables: */ char *option; /* Pointer to a copy of the next option */ const char *p; /* Pointer to the start of the next word */ int i; /* Current option index */ int len; /* Length of supplied option */ int nmatch; /* Number of matching options */ int ret; /* The returned index */ /* Initialise the answer to indicate that the option has not been uniquely identified. */ ret = -1; /* Check global status. */ if( !astOK ) return ret; /* Save the number of characters in the supplied test option (excluding trailing spaces). */ len = ChrLen( test, status ); /* Compare the supplied test option against each of the known options in turn. Count the number of matches. */ nmatch = 0; p = list; option = FindWord( NULL, " ", &p, status ); i = 0; while( option ){ /* If the test string and the current option are identical (including length). use the current option. */ /* If every character in the supplied label matches the corresponding character in the current test label we have a match. Increment the number of matches and save the current item index. If the test string and the current option are identical (including length), use the current option. */ if( !Ustrncmp( test, option, len, status ) ) { ret = i; if( ChrLen( option, status ) == len ) { nmatch = 1; option = astFree( option ); break; } else { nmatch++; } } /* Get a pointer to the next option. */ option = FindWord( option, " ", &p, status ); i++; } /* Report an error if no match was found, and return -1. */ if( !nmatch ){ astError( AST__OPT, "%s(%s): Option '%.*s' is unknown in '%.*s'.", status, method, class, len, test, ChrLen( text, status ), text ); ret = -1; /* Report an error if the label was ambiguous, and return -1. */ } else if( nmatch > 1 ){ astError( AST__OPT, "%s(%s): Option '%.*s' is ambiguous in '%.*s'.", status, method, class, len, test, ChrLen( text, status ), text ); ret = -1; } /* Return the answer. */ return ret; } static void GAttr( AstPlot *this, int attr, double value, double *old_value, int prim, const char *method, const char *class, int *status ) { /* * * Name: * GAttr * Purpose: * Call the GAttr Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GAttr( AstPlot *this, int attr, double value, double *old_value, * int prim, const char *method, const char *class, int *status ) * Class Membership: * Plot private function. * Description: * This function calls the GAttr grf function to enquire or set a * graphics attribute value. It either calls the version registered using * astGrfSet, or the version in the linked grf module. The linked version * is used if the Grf attribute is zero, or if no function has been * registered for GAttr using astGrfSet. * Parameters: * this * The Plot. * attr * An integer value identifying the required attribute. The * following symbolic values are defined in grf.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 * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. Also return if there is nothing to do. */ if ( !astOK || ( !old_value && value == AST__BAD ) ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GATTR ] ) { grf_status = ( *( this->GAttr ) )( this, attr, value, old_value, prim, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGAttr( attr, value, old_value, prim ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGAttr. ", status, method, class ); } } static AstKeyMap *GetGrfContext( AstPlot *this, int *status ){ /* *++ * Name: c astGetGrfContext f AST_GETGRFCONTEXT * Purpose: * Return the KeyMap that describes a Plot's graphics context. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c AstKeyMap *astGetGrfContext( AstPlot *this ) f RESULT = AST_GETGRFCONTEXT( THIS, STATUS ) * Class Membership: * Plot method. * Description: c This function f This routine * returns a reference to a KeyMap that will be passed to any drawing c functions registered using astGrfSet. f routines registered using AST_GRFSET. * This KeyMap can be used by an application to pass information to c the drawing functions f the drawing routines * about the context in which they are being called. The contents of * the KeyMap are never accessed byt the Plot class itself. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetGrfContext() f AST_GETGRFCONTEXT = INTEGER * A pointer to the graphics context KeyMap. The returned pointer * should be annulled when it is no longer needed. *-- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Ensure that a grfcon KeyMap exists. */ (void) astGrfConID(this); /* Return a cloned pointer to the KeyMap. */ return astClone( this->grfcontext ); } AstKeyMap *astGrfConID_( AstPlot *this, int *status ) { /* *+ * * Name: * astGrfConID * Purpose: * Ensure a GrfContext KeyMap exists and return an ID for it. * Type: * Protected function. * Synopsis: * #include "plot.h" * AstKeyMap *astGrfConID( AstPlot *this ) * Class Membership: * Plot private function. * Description: * This function creates a GrfContext KeyMap if the Plot does not * currently have one, and returns an ID for it. * Parameters: * this * The Plot. * Returned Value: * ID for the GrfContext KeyMap. *- */ if( !this->grfcontext ) { this->grfcontext = astKeyMap("", status ); this->grfcontextID = astMakeId( astClone( this->grfcontext ) ); astExempt( this->grfcontextID ); } return this->grfcontextID; } static void GScales( AstPlot *this, float *alpha, float *beta, const char *method, const char *class, int *status ) { /* * * Name: * GScales * Purpose: * Call the GScales Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GScales( AstPlot *this, float *alpha, float *beta, * const char *method, const char *class, int *status ) * Class Membership: * Plot private function. * Description: * This function calls the GScales grf function, either calling the * version registered using astGrfSet, or the version in the linked grf * module. The linked version is used if the Grf attribute is zero, or if * no function has been registered for GScales using astGrfSet. * Parameters: * this * The Plot. * alpha * A pointer to the location at which to return the scale for the * X axis (i.e. Xnorm = alpha*Xworld). * beta * A pointer to the location at which to return the scale for the * Y axis (i.e. Ynorm = beta*Yworld). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* if we already have the required values, return them. */ if( Grf_alpha != 0.0 && Grf_beta != 0.0 ) { if( alpha ) *alpha = Grf_alpha; if( beta ) *beta = Grf_beta; return; } /* Check that the grf mdoule can give us scales information. */ if( GCap( this, GRF__SCALES, 1, status ) ) { /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GSCALES ] ) { grf_status = ( *( this->GScales ) )( this, &Grf_alpha, &Grf_beta, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGScales( &Grf_alpha, &Grf_beta ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Check neither value is zero. */ if( grf_status && ( Grf_alpha == 0.0 || Grf_beta == 0.0 ) ) { astError( AST__GRFER, "astGScales: Returned axis scales are %g and %g " "but zero is illegal!", status, Grf_alpha, Grf_beta ); grf_status = 0; } /* Report an error if anything went wrong, and return safe values. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGScales. ", status, method, class ); Grf_alpha = 1.0; Grf_beta = 1.0; } /* If the grf module is not capable of giving us scale information, then just assume the the axes are equally scaled, except for any axis reversal indicated in the supplied Plot. */ } else { Grf_alpha = ( this->xrev ) ? -1.0 : 1.0; Grf_beta = ( this->yrev ) ? -1.0 : 1.0; } /* Store them for future use. */ if( alpha ) *alpha = Grf_alpha; if( beta ) *beta = Grf_beta; } static int GCap( AstPlot *this, int cap, int value, int *status ){ /* * * Name: * GCap * Purpose: * Call the GCap Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * int GCap( AstPlot *this, int cap, int value, int *status ) * Class Membership: * Plot private function. * Description: * This function calls the GCap grf function to inquire a capability * of the grf module, either calling the version registered using * astGrfSet, or the version in the linked grf module. The linked * version is used if the Grf attribute is zero, or if no function * has been registered for GCap using astGrfSet. * Parameters: * this * The Plot. * cap * The capability to be inquired aboue. * value * The value ot assign to the capability. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the grf module is capabale of performing the action * requested by "cap". */ /* Local Variables: */ int result; /* Value retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return 0; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GCAP ] ) { result = ( *( this->GCap ) )( this, cap, value, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { result = astGCap( cap, value ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Return the result. */ return result; } static void GenCurve( AstPlot *this, AstMapping *map, int *status ){ /* *++ * Name: c astGenCurve f AST_GENCURVE * Purpose: * Draw a generalized curve. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astGenCurve( AstPlot *this, astMapping *map ) f CALL AST_GENCURVE( THIS, MAP ) * Class Membership: * Plot method. * Description: c This function draws a general user-defined curve defined by the f This routine draws a general user-defined curve defined by the * supplied Mapping. Note that the curve is transformed into graphical * coordinate space for plotting, so that a straight line in * physical coordinates may result in a curved line being drawn if * the Mapping involved is non-linear. Any discontinuities in the * Mapping between physical and graphical coordinates are c catered for, as is any clipping established using astClip. f catered for, as is any clipping established using AST_CLIP. * c If you need to draw simple straight lines (geodesics), astCurve c or astPolyCurve will usually be easier to use and faster. f If you need to draw simple straight lines (geodesics), AST_CURVE f or AST_POLYCURVE will usually be easier to use and faster. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c map f MAP = INTEGER (Given) * Pointer to a Mapping. This Mapping should have 1 input * coordinate representing offset along the required curve, * normalized so that the start of the curve is at offset 0.0, * and the end of the curve is at offset 1.0. Note, this offset * does not need to be linearly related to distance along the curve. * The number of output coordinates should equal the number of axes * in the current Frame of the Plot. The Mapping should map a * specified offset along the curve, into the corresponding * coordinates in the current Frame of the Plot. The inverse * transformation need not be defined. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - An error results if the base Frame of the Plot is not 2-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ const char *class; /* Object class */ const char *method; /* Current method */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double tol; /* Absolute tolerance value */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ int i; /* Loop count */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astGenCurve"; class = astGetClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Only proceed if there has been no error. */ if( astOK ){ /* Initialise the bounding box for primitives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Set up the externals used to communicate with the Map4 function... */ Map4_ncoord = astGetNout( this ); Map4_plot = this; Map4_map = astGetMapping( this, AST__BASE, AST__CURRENT ); Map4_umap = map; /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Now set up the external variables used by the Crv and CrvLine function. */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_ux0 = AST__BAD; Crv_tol = tol; Crv_limit = 0.5*tol*tol; Crv_map = Map4; Crv_ink = 1; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_out = 1; Crv_xbrk = Curve_data.xbrk; Crv_ybrk = Curve_data.ybrk; Crv_vxbrk = Curve_data.vxbrk; Crv_vybrk = Curve_data.vybrk; Crv_clip = astGetClip( this ) & 1; /* Set up a list of points spread evenly over the curve. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Map these points into graphics coordinates. */ Map4( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map4 to draw the curve. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* End the current poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map4. */ Map4( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* If no part of the curve could be drawn, set the number of breaks and the length of the drawn curve to zero. */ if( Crv_out ) { Crv_nbrk = 0; Crv_len = 0.0F; /* Otherwise, add an extra break to the returned structure at the position of the last point to be plotted. */ } else { Crv_nbrk++; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; } } /* Store extra information about the curve in the returned structure, and purge any zero length sections. */ Curve_data.length = Crv_len; Curve_data.out = Crv_out; Curve_data.nbrk = Crv_nbrk; PurgeCdata( &Curve_data, status ); /* Annul the Mapping. */ Map4_map = astAnnul( Map4_map ); /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); } /* Return. */ return; } static int GetLabelUnits( AstPlot *this, int axis, int *status ) { /* * Name: * GetLabelUnits * Purpose: * Return the value of the LabelUnits attribute for a Plot axis. * Type: * Private function. * Synopsis: * #include "plot.h" * int GetLabelUnits( AstPlot *this, int axis, int *status ) * Class Membership: * Plot method. * Description: * This function returns the value of the LabelUnits attribute for a * Plot axis, supplying a suitable default if not set. * Parameters: * this * The Plot. * axis * The axis index (zero based). * status * Pointer to the inherited status variable. * Returned Value: * The attribute value. */ /* Local Variables: */ AstFrame *fr; /* The current Frame in the Plot */ AstFrame *primframe; /* The primary Frame holding the requested axis */ AstSystemType system; /* The SkyFrame System attribute */ int primaxis; /* Index of requested axis in the primary frame */ int ret; /* The returned value */ /* Initialise. */ ret = 0; /* Check global status. */ if( !astOK ) return ret; /* If a value has been set, return it. */ ret = this->labelunits[ axis ]; /* If no value has been set, find a default. */ if( ret == -1 ) { /* Assume "no" for any SkyAxis axes within the current frame of the Plot, and "yes" for other axes. Get a pointer to the current Frame of the Plot. */ fr = astGetFrame( this, AST__CURRENT ); /* The current Frame may be a CmpFrame. So find the primary Frame containing the requested axis. The primary Frame is guaranteed not to be a CmpFrame. */ astPrimaryFrame( fr, axis, &primframe, &primaxis ); /* If the primary Frame is a SkyFrame representing ICRS, equatorial, ecliptic, galactic or supergalactic coords, use a default of "no" for LabelUnits. Otherwise use a default of "yes". */ ret = 1; if( IsASkyFrame( (AstObject *) primframe, status ) ) { system = astGetSystem( primframe ); if( system == AST__ICRS || system == AST__FK4 || system == AST__FK4_NO_E || system == AST__FK5 || system == AST__GAPPT || system == AST__ECLIPTIC || system == AST__GALACTIC || system == AST__SUPERGALACTIC ) ret = 0; } /* Annul the frame pointers. */ primframe = astAnnul( primframe ); fr = astAnnul( fr ); } /* Return the answer. */ return ret; } static void GBBuf( AstPlot *this, const char *method, const char *class, int *status ) { /* * * Name: * GBBuf * Purpose: * Call the GBBuf Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GBBuf( AstPlot *this, const char *method, * const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the GBBuf grf function to begin a new graphics * context, either calling the version registered using astGrfSet, or * the version in the linked grf module. The linked version is used * if the Grf attribute is zero, or if no function has been registered * for GBBuf using astGrfSet. * Parameters: * this * The Plot. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GBBUF ] ) { grf_status = ( *( this->GBBuf ) )( this, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGBBuf(); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGBBuf. ", status, method, class ); } } static void GEBuf( AstPlot *this, const char *method, const char *class, int *status ) { /* * * Name: * GEBuf * Purpose: * Call the GEBuf Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GEBuf( AstPlot *this, const char *method, * const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the GEBuf grf function to end the current graphics * context, either calling the version registered using astGrfSet, or * the version in the linked grf module. The linked version is used * if the Grf attribute is zero, or if no function has been registered * for GEBuf using astGrfSet. * Parameters: * this * The Plot. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GEBUF ] ) { grf_status = ( *( this->GEBuf ) )( this, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGEBuf(); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGEBuf. ", status, method, class ); } } static void GFlush( AstPlot *this, const char *method, const char *class, int *status ) { /* * * Name: * GFlush * Purpose: * Call the Gflush Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GFlush( AstPlot *this, const char *method, * const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the Gflush grf function to flush graphics, either * calling the version registered using astGrfSet, or the version in the * linked grf module. The linked version is used if the Grf attribute * is zero, or if no function has been registered for Gflush using * astGrfSet. * Parameters: * this * The Plot. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GFLUSH ] ) { grf_status = ( *( this->GFlush ) )( this, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGFlush(); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGFlush. ", status, method, class ); } } static void GLine( AstPlot *this, int n, const float *x, const float *y, const char *method, const char *class, int *status ) { /* * * Name: * GLine * Purpose: * Call the Gline Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GLine( AstPlot *this, int n, const float *x, * const float *y, const char *method, * const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the Gline grf function to draw a polyline, either * calling the version registered using astGrfSet, or the version in the * linked grf module. The linked version is used if the Grf attribute * is zero, or if no function has been registered for Gline using * astGrfSet. * Parameters: * this * The Plot. * 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. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int i; /* Loop count */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* Do not draw anything if we are using "invisible ink". */ if( astGetInvisible( this ) ) { grf_status = 1; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ } else if( astGetGrf( this ) && this->grffun[ AST__GLINE ] ) { grf_status = ( *( this->GLine ) )( this, n, x, y, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGLine( n, x, y ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGLine. ", status, method, class ); /* Otherwise, update the box containing all drawn graphics primitives. */ } else if( !Boxp_freeze ){ for( i = 0; i < n; i++ ) { Boxp_lbnd[ 0 ] = MIN( x[ i ], Boxp_lbnd[ 0 ] ); Boxp_ubnd[ 0 ] = MAX( x[ i ], Boxp_ubnd[ 0 ] ); Boxp_lbnd[ 1 ] = MIN( y[ i ], Boxp_lbnd[ 1 ] ); Boxp_ubnd[ 1 ] = MAX( y[ i ], Boxp_ubnd[ 1 ] ); } } } static void GMark( AstPlot *this, int n, const float *x, const float *y, int type, const char *method, const char *class, int *status ) { /* * * Name: * GMark * Purpose: * Call the GMark Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GMark( AstPlot *this, int n, const float *x, * const float *y, int type, const char *method, * const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the GMark grf function to draw markers, either * calling the version registered using astGrfSet, or the version in the * linked grf module. The linked version is used if the Grf attribute * is zero, or if no function has been registered for GMark using * astGrfSet. * Parameters: * this * The Plot. * 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. * type * An integer which can be used to indicate the type of marker symbol * required. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int i; /* Loop count */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* Do not draw anything if we are using "invisible ink". */ if( astGetInvisible( this ) ) { grf_status = 1; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ } else if( astGetGrf( this ) && this->grffun[ AST__GMARK ] ) { grf_status = ( *( this->GMark ) )( this, n, x, y, type, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGMark( n, x, y, type ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGMark. ", status, method, class ); /* Otherwise, update the box containing all drawn graphics primitives. */ } else if( !Boxp_freeze ){ for( i = 0; i < n; i++ ) { Boxp_lbnd[ 0 ] = MIN( x[ i ], Boxp_lbnd[ 0 ] ); Boxp_ubnd[ 0 ] = MAX( x[ i ], Boxp_ubnd[ 0 ] ); Boxp_lbnd[ 1 ] = MIN( y[ i ], Boxp_lbnd[ 1 ] ); Boxp_ubnd[ 1 ] = MAX( y[ i ], Boxp_ubnd[ 1 ] ); } } } static void GQch( AstPlot *this, float *chv, float *chh, const char *method, const char *class, int *status ) { /* * * Name: * GQch * Purpose: * Call the GQch Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GQch( AstPlot *this, float *chv, float *chh, const char *method, * const char *class, int *status ) * Class Membership: * Plot private function. * Description: * This function calls the GQch grf function, either calling the * version registered using astGrfSet, or the version in the linked grf * module. The linked version is used if the Grf attribute is zero, or if * no function has been registered for GQch using astGrfSet. * Parameters: * this * The Plot. * chv * A pointer to the double which is to receive the height of * characters drawn with a vertical baseline . This will be an * increment in the X axis. * chh * A pointer to the double which is to receive the height of * characters drawn with a horizontal baseline. This will be an * increment in the Y axis. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* if we already have the required values, return them. */ if( Grf_chh != AST__BAD && Grf_chv != AST__BAD ) { *chh = Grf_chh; *chv = Grf_chv; return; } /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GQCH ] ) { grf_status = ( *( this->GQch ) )( this, chv, chh, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGQch( chv, chh ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Check neither value is zero. */ if( grf_status && ( *chh == 0.0 || *chv == 0.0 ) ) { astError( AST__GRFER, "astGQch: Returned text heights are %g and %g " "but zero is illegal!", status, *chv, *chh ); grf_status = 0; } /* Report an error if anything went wrong, and return safe values. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGQch. ", status, method, class ); *chh = 1.0; *chv = 1.0; } /* Store them for future use. */ Grf_chh = *chh; Grf_chv = *chv; } static void GText( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy, const char *method, const char *class, int *status ) { /* * * Name: * GText * Purpose: * Call the GText Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GText( AstPlot *this, const char *text, float x, float y, * const char *just, float upx, float upy, * const char *method, const char *class, int *status ) { * Class Membership: * Plot private function. * Description: * This function calls the GText grf function to draw a text string, either * calling the version registered using astGrfSet, or the version in the * linked grf module. The linked version is used if the Grf attribute * is zero, or if no function has been registered for GText using * astGrfSet. * Parameters: * this * The Plot. * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* Do not draw anything if we are using "invisible ink". */ if( astGetInvisible( this ) ) { grf_status = 1; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ } else if( astGetGrf( this ) && this->grffun[ AST__GTEXT ] ) { grf_status = ( *( this->GText ) )( this, text, x, y, just, upx, upy, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGText( text, x, y, just, upx, upy ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGText. ", status, method, class ); } } static void GTxExt( AstPlot *this, const char *text, float x, float y, const char *just, float upx, float upy, float *xbn, float *ybn, const char *method, const char *class, int *status ) { /* * * Name: * GTxExt * Purpose: * Call the GTxExt Grf function. * Type: * Private function. * Synopsis: * #include "plot.h" * void GTxExt( AstPlot *this, const char *text, float x, float y, * const char *just, float upx, float upy, float *xbn, * float *ybn, const char *method, const char *class, int *status ) * Class Membership: * Plot private function. * Description: * This function calls the GTxExt grf function to find the extent * of a text string, either calling the version registered using * astGrfSet, or the version in the linked grf module. The linked * version is used if the Grf attribute is zero, or if no function * has been registered for GTxExt using astGrfSet. * Parameters: * this * The Plot. * text * Pointer to a null-terminated character string to be displayed. * x * The reference x coordinate. * y * The reference y coordinate. * 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. * upx * The x component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. * upy * The y component of the up-vector for the text, in graphics world * coordinates. If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * xbn * An array of 4 elements in which to return the x coordinate of * each corner of the bounding box. * ybn * An array of 4 elements in which to return the y coordinate of * each corner of the bounding box. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - The corners are returned in no particular order. */ /* Local Variables: */ int grf_status; /* Status retruned from Grf function */ /* Check the global error status. */ if ( !astOK ) return; /* Since we are about to call an external function which may not be thread safe, prevent any other thread from executing the following code until the current thread has finished executing it. */ LOCK_MUTEX2; /* If the Grf attribute is set to a non-zero value, use the Grf function registered using astGrfSet (so long as a function has been supplied). This is called via a wrapper which adapts the interface to suit the language in which the function is written. */ if( astGetGrf( this ) && this->grffun[ AST__GTXEXT ] ) { grf_status = ( *( this->GTxExt ) )( this, text, x, y, just, upx, upy, xbn, ybn, status ); /* Otherwise, use the function in the external Grf module, selected at link-time using ast_link options.*/ } else { grf_status = astGTxExt( text, x, y, just, upx, upy, xbn, ybn ); } /* Allow the next thread to proceed. */ UNLOCK_MUTEX2; /* Report an error if anything went wrong. */ if( !grf_status ) { astError( AST__GRFER, "%s(%s): Graphics error in astGTxExt. ", status, method, class ); } } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a Plot. * Type: * Private function. * Synopsis: * #include "plot.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Plot member function (over-rides the protected astGetAttrib * method inherited from the FrameSet class). * Description: * This function returns a pointer to the value of a specified * attribute for a Plot, formatted as a character string. * * The value returned is the value which would actually be used if * astGrid was called with the current set of attribute values. This * may not always be the same as the value set by the user. For * instance, if Labelling is set to "exterior" by the user, it may not * be possible to produce exterior labels, in which case interior labels * will be produced. If this function is used to get the value of * Labelling in this situation, then the value actually used (i.e. * interior) will be returned instead of the requested value (i.e. * exterior). * * Some attributes have dynamic defaults, (i.e. the behaviour if not * set depends on the values of other attributes). If the value for * such an attribute is enquired using this function, then the dynamic * default value actually used will be returned if no value has been * set explicitly for the attribute. * Parameters: * this * Pointer to the Plot. * attrib * Pointer to a null terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the Plot, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Plot. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPlot *this; /* Pointer to the Plot structure */ const char *result; /* Pointer value to return */ char label[21]; /* Graphics item label */ double dval; /* Double attribute value */ int axis; /* Axis number */ int ival; /* Int attribute value */ int len; /* Length of attrib string */ int nax; /* Number of base Frame axes */ int nc; /* No. characters read by astSscanf */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ nax = astGetNin( this ); /* Indicate that the current bound box should not be changed during the execution of this function (this may happen if a grid is drawn to get the default value for an attribute such as Labelling). */ Boxp_freeze = 1; /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null terminated string in an appropriate format. Set "result" to point at the result string. */ /* Tol. */ /* ---- */ if ( !strcmp( attrib, "tol" ) ) { dval = astGetTol( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Grid. */ /* ----- */ } else if ( !strcmp( attrib, "grid" ) ) { ival = GetUsedGrid( this, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TickAll. */ /* -------- */ } else if ( !strcmp( attrib, "tickall" ) ) { ival = astGetTickAll( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ForceExterior. */ /* -------------- */ } else if ( !strcmp( attrib, "forceexterior" ) ) { ival = astGetForceExterior( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Invisible. */ /* ---------- */ } else if ( !strcmp( attrib, "invisible" ) ) { ival = astGetInvisible( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Border. */ /* ------- */ } else if ( !strcmp( attrib, "border" ) ) { ival = GetUsedBorder( this, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ClipOp. */ /* ------- */ } else if ( !strcmp( attrib, "clipop" ) ) { ival = astGetClipOp( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Clip. */ /* ----- */ } else if ( !strcmp( attrib, "clip" ) ) { ival = astGetClip( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Grf. */ /* ---- */ } else if ( !strcmp( attrib, "grf" ) ) { ival = astGetGrf( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* DrawTitle. */ /* --------- */ } else if ( !strcmp( attrib, "drawtitle" ) ) { ival = astGetDrawTitle( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Escape. */ /* ------- */ } else if ( !strcmp( attrib, "escape" ) ) { ival = astGetEscape( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LabelAt(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = GetUsedLabelAt( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Centre(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "centre(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = GetUsedCentre( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Gap. */ /* ---- */ } else if ( !strcmp( attrib, "gap" ) ) { dval = GetUsedGap( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Gap(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = GetUsedGap( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* LogGap. */ /* ---- */ } else if ( !strcmp( attrib, "loggap" ) ) { dval = GetUsedLogGap( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* LogGap(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = GetUsedLogGap( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* NumLabGap. */ /* -------- */ } else if ( !strcmp( attrib, "numlabgap" ) ) { dval = astGetNumLabGap( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* NumLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetNumLabGap( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* TextLabGap. */ /* ----------- */ } else if ( !strcmp( attrib, "textlabgap" ) ) { dval = astGetTextLabGap( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* TextLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetTextLabGap( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* LabelUp. */ /* -------- */ } else if ( !strcmp( attrib, "labelup" ) ) { ival = astGetLabelUp( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LabelUp(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = astGetLabelUp( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogPlot. */ /* -------- */ } else if ( !strcmp( attrib, "logplot" ) ) { ival = astGetLogPlot( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogPlot(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = astGetLogPlot( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogLabel. */ /* -------- */ } else if ( !strcmp( attrib, "loglabel" ) ) { ival = GetUsedLogLabel( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogLabel(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedLogLabel( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogTicks. */ /* -------- */ } else if ( !strcmp( attrib, "logticks" ) ) { ival = GetUsedLogTicks( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LogTicks(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedLogTicks( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* NumLab. */ /* -------- */ } else if ( !strcmp( attrib, "numlab" ) ) { ival = astGetNumLab( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* NumLab(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = astGetNumLab( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* MinTick. */ /* -------- */ } else if ( !strcmp( attrib, "mintick" ) ) { ival = GetUsedMinTick( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* MinTick(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedMinTick( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TextLab. */ /* ---------- */ } else if ( !strcmp( attrib, "textlab" ) ) { ival = GetUsedTextLab( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TextLab(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedTextLab( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* DrawAxes. */ /* ----------- */ } else if ( !strcmp( attrib, "drawaxes" ) ) { ival = astGetDrawAxes( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* DrawAxes(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetDrawAxes( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Abbrev. */ /* ----------- */ } else if ( !strcmp( attrib, "abbrev" ) ) { ival = astGetAbbrev( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Abbrev(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetAbbrev( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LabelUnits. */ /* ----------- */ } else if ( !strcmp( attrib, "labelunits" ) ) { ival = GetUsedLabelUnits( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* LabelUnits(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedLabelUnits( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Style. */ /* ------ */ } else if ( !strcmp( attrib, "style" ) ) { ival = GetUseStyle( this, AST__BORDER_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Style(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { ival = GetUseStyle( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Font. */ /* ----- */ } else if ( !strcmp( attrib, "font" ) ) { ival = GetUseFont( this, AST__TEXTLABS_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Font(label). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { ival = GetUseFont( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Colour. */ /* ------- */ } else if ( !strcmp( attrib, "colour" ) ) { ival = GetUseColour( this, AST__TEXTLABS_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Colour(label). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { ival = GetUseColour( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Color. */ /* ------ */ } else if ( !strcmp( attrib, "color" ) ) { ival = GetUseColour( this, AST__TEXTLABS_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Color(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { ival = GetUseColour( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Width. */ /* ------ */ } else if ( !strcmp( attrib, "width" ) ) { dval = GetUseWidth( this, AST__BORDER_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Width(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { dval = GetUseWidth( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Size. */ /* ----- */ } else if ( !strcmp( attrib, "size" ) ) { dval = GetUseSize( this, AST__TEXTLABS_ID, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Size(label). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { dval = GetUseSize( this, FullForm( GrfLabels, label, attrib, "astGet", astGetClass( this ), status ), status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* TitleGap. */ /* --------- */ } else if ( !strcmp( attrib, "titlegap" ) ) { dval = astGetTitleGap( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* MajTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "majticklen" ) ) { dval = GetUsedMajTickLen( this, 0, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* MajTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = GetUsedMajTickLen( this, axis - 1, status ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* MinTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "minticklen" ) ) { dval = astGetMinTickLen( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* MinTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetMinTickLen( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Labelling. */ /* ---------- */ } else if ( !strcmp( attrib, "labelling" ) ) { ival = GetUsedLabelling( this, status ); if ( astOK ) { result = ival ? xlbling[1] : xlbling[0]; } /* Edge(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { ival = GetUsedEdge( this, axis - 1, status ); if ( astOK ) { if( ival == LEFT ){ result = "left"; } else if( ival == RIGHT ){ result = "right"; } else if( ival == TOP ){ result = "top"; } else if( ival == BOTTOM ){ result = "bottom"; } else { result = ""; } } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Unfreeze the bound box so that it may be updated by subsequent plotting functions. */ Boxp_freeze = 0; /* Return the result. */ return result; } static AstPointSet *GetDrawnTicks( AstPlot *this, int axis, int major, int *status ){ /* *+ * Name: * astGetDrawnTicks * Purpose: * Return information about the ticks last drawn by astGrid. * Type: * Protected virtual function. * Synopsis: * #include "plot.h" * AstPointSet *GetDrawnTicks( AstPlot *this, int axis, int major ) * Class Membership: * Plot method. * Description: * This function returns a PointSet holding information about the * tick marks (either major and minor) that were drawn by the previous * invocation of astGrid. A NULL pointer is returned if astGrid has * not yet been invoked. * Parameters: * this * Pointer to a Plot. * axis * The zero-based axis of the axis for which tick mark information * is required. * major * Supply a non-zero value if information about the major tick * marks is to be returned, and zero if information about the minor * tick marks is to be returned. * Returned Value: * A pointSet with one point for every tick of the requested type drawn * by astGrid for the specified axis. Each point has 2 coordinate values, * being the graphics coordinates at the start of the tick mark. The * returned PointSet pointer should be annulled when no longer needed. *- */ /* Local Variables: */ AstPointSet *result = NULL; double *ptr[ 3 ]; int n; /* Check the global status. */ if( !astOK ) return result; /* Report an error if the supplied axis value is incorrect. */ if( axis < 0 || axis > 1 ) { astError( AST__INTER, "astGetDrawnTicks(Plot): Supplied \"axis\" " "value is %d - should 0 or 1 (internal AST programming " "error).", status, axis ); n = 0; /* If OK, get the number of stored tick marks. */ } else { n = major ? this->majtickcount[ axis ] : this->mintickcount[ axis ]; } /* Check that information is available. */ if( n > 0 && astOK ) { /* Create a PointSet with the required size. */ result = astPointSet( n, 2, "", status ); /* Store pointers to the arrays within the Plot that hold the required tick marks positions and types. */ ptr[ 0 ] = major ? this->majtickgx[ axis ] : this->mintickgx[ axis ]; ptr[ 1 ] = major ? this->majtickgy[ axis ] : this->mintickgy[ axis ]; astSetPoints( result, ptr ); } /* Return the PointSet. */ return result; } static double GetTicks( AstPlot *this, int axis, double *cen, double **ticks, int *nmajor, double **minticks, int *nminor, int format_set, int *inval, double *refval, GetTicksStatics **pstatics, const char *method, const char *class, int *status ){ /* * Name: * GetTicks * Purpose: * Obtain a list of logarithmically or linearly spaced tick mark values for * a single axis in a 2-D physical coordinate Frame. * Type: * Private function. * Synopsis: * #include "plot.h" * double GetTicks( AstPlot *this, int axis, double *cen, double **ticks, * int *nmajor, double **minticks, int *nminor, * int format_set, int *inval, double *refval, * GetTicksStatics **pstatics, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * For linearly spaced major ticks the "gap" returned by this function * is the constant difference between adjacent major tick marks. For * logarithmically spaced major ticks the "gap" returned by this * function is the constant ratio between adjacent major tick marks. * * If a gap size has been specified using attribute Gap (or LogGap for * logarithmic ticks) supplied, the specified value is returned, and used * to determine the tick values. If no gap size is supplied, a default * gap size is used and returned. * * All this is over-ridden if the astSetTickValues method has been * called to store explicit tick mark values in the Plot structure. * In this case, the values supplied using astSetTickValues are * returned. * Parameters: * this * The Plot. Supplying a NULL pointer will cause statics resources * to be released. * axis * The zero-based index of the axis to use. * cen * Pointer to the supplied axis value at which to put a single * central tick. Other ticks will be placed evenly on either side * of this tick. If AST__BAD is provided, a value will be used * which would put a tick at an axis value of one. The used value * is returned. * ticks * Pointer to a place at which to return a pointer to the memory in * which are stored the major tick values to be used. This pointer * should be freed using astFree when no longer needed. The number of * values in the array is given by the value returned by parameter * "nmajor". * nmajor * A pointer to a location at which to return the number of major * ticks. * minticks * Pointer to a place at which to return a pointer to the memory in * which are stored the minor tick values to be used. This pointer * should be freed using astFree when no longer needed. The number of * values in the array is given by the value returned by parameter * "nminor". The minor tick marks values returned in this array are * the ones stored in the Plot via a call to the astSetTickValues * function. If this function has not been called, then a NULL * pointer is returned, and the "nminor" value is returned holding the * number of divisions between major ticks. * nminor * A pointer to a location at which to return either the number of * division into which each gap should be divided when drawing minor * tick marks (if "*minticks" is returned holding NULL), or the * total number of minor tick values stored in "*minticks" (if * "*minticks" is returned non-NULL). The number of divisions * between major tick values is one more than the number of minor * tick marks. * format_set * Indicates if an explicit format has been set for the axis. If * not, "cen" is always assumed to be AST__BAD, and any specified * Gap value is rounded to the nearest "nice" value. This has * to be done because the algorithm for choosing a format avoiding * unnecessary precision only works if the gap size causes 1 digit to * change between adjacent labels. * inval * A pointer to a location at which to return a flag indicating if * any invalid physical coordinates were encountered. * refval * A pointer to a location at which to return a value for the other * axis which can be used when normalizing the returned tick mark * values. * pstatics * Address of a pointer to a structure holding static data values * used within this function. A NULL pointer should be supplied on * the first invocation (dynamic memory will then be allocated to * hold ths structure). The memory is freed when a NULL value for * "this" is supplied. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The used gap size. * Notes: * - This function allocates some static resources on its first * invocation, which should be released when no longer needed, or when * a different Plot is supplied, by calling this function with a NULL * pointer for parameter "this". All other parameters are ignored. * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - An error is reported if the region containing valid physical * coordinates is too small to use. * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned in "ticks", zero * is returned for the number of major and minor ticks marks. */ /* Local Variables: */ GetTicksStatics *statics; /* Pointer to statics structure */ double *tick; /* Pointer to next tick value */ double cen0; /* Supplied value of cen */ double dran; /* Dynamic range of axis values */ double frac; /* Fraction of plot area holding good coords */ double gap; /* Supplied value for Gap or LogGap */ double log_used_gap; /* Log10( the used gap size ) */ double maxv; /* Max axis value */ double minv; /* Min axis value */ double new_used_gap; /* New value for the used gap size */ double old_used_gap; /* Old value for the used gap size */ double test_gap; /* Trial gap size */ double used_cen; /* Used value of cen */ double used_gap; /* The used gap size */ int findcen; /* Find a new centre value? */ int gap_too_small; /* Test gap too small? */ int gap_too_large; /* Test gap too large? */ int i; /* Axis index */ int ihi; /* Highest tick mark index */ int ilo; /* Lowest tick mark index */ int nochange; /* No. of ineffective attempts to change gap size */ /* Initialise the returned information. */ *ticks = NULL; *minticks = NULL; *nmajor = 0; *nminor = 0; /* Get a pointer to the supplied statics object. */ statics = *pstatics; /* If a NULL pointer has been supplied for "this", release the resources allocated on the first call to this function, and return. */ if( !this ){ if( statics ) { if( statics->map ) statics->map = astAnnul( statics->map ); if( statics->pset ) statics->pset = astAnnul( statics->pset ); if( statics->frame ) statics->frame = astAnnul( statics->frame ); *pstatics = astFree( statics ); } return 0.0; } /* Check the global error status. */ if ( !astOK ) return 0.0; /* If no statics structure was supplied, create one now and initialise it. */ if( !statics ) { statics = astMalloc( sizeof( GetTicksStatics ) ); if( statics ) { statics->pset=NULL; *pstatics = statics; } } /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ maxv = 0.0; minv = 0.0; used_cen = 0.0; used_gap = 0.0; ihi = 0; ilo = 0; /* If this is the first call to this function, do some initialisation. */ if( !statics->pset ){ /* Get the Mapping from Base to Current Frame in the Plot. */ statics->map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Get a pointer to the current Frame from the Plot. */ statics->frame = astGetFrame( this, AST__CURRENT ); /* Get initial guesses at suitable gaps for each axis. A PointSet is returned holding sorted values (non-normalized) for the physical axes. */ statics->pset = DefGap( this, statics->defgaps, statics->ngood, &frac, &statics->bad, method, class, status ); /* Store the maximum and minimum number of major tick marks along each axis. These numbers are reduced if only a small part of the plotting area contains valid coordinates, so that the tick marks do not end up to close together. */ statics->maxticks = (int) ( 0.5 + MAJTICKS_MAX*sqrt( frac ) ); statics->mintick = (int) ( 0.5 + MAJTICKS_MIN*sqrt( frac ) ); if( statics->mintick < 3 ) statics->mintick = 3; if( statics->maxticks < 8 ) statics->maxticks = 8; if( statics->maxticks < statics->mintick ) statics->maxticks = statics->mintick; /* Get a pointer to the data in the PointSet. */ statics->ptr = astGetPoints( statics->pset ); /* Find a typical value on each axis. */ for( i = 0; i < 2 && astOK; i++ ){ statics->typval[ i ] = Typical( statics->ngood[ i ], statics->ptr[ i ], -DBL_MAX, DBL_MAX, statics->width + i, status ); } } /* Return the flag indicating if any regions of invalid physical coordinates were found. */ *inval = statics->bad; /* Return the typical value on the other axis. */ *refval = statics->typval[ 1 - axis ]; /* See if any tick marks values have been stored in the Plot structure using astSetTickValues. If so, copy the tick mark values to the returned arrays and exit with a gap size determined by the first two ticks. */ if( this->nmajtickval[ axis ] > 0 ) { *ticks = astStore( NULL, this->majtickval[ axis ], this->nmajtickval[ axis ]*sizeof(double) ); *minticks = astStore( NULL, this->mintickval[ axis ], this->nmintickval[ axis ]*sizeof(double) ); *nmajor = this->nmajtickval[ axis ]; *nminor = this->nmintickval[ axis ]; if( *nmajor > 1 && (*ticks)[ 0 ] != AST__BAD && (*ticks)[ 1 ] != AST__BAD ) { used_gap = fabs( (*ticks)[ 1 ] - (*ticks)[ 0 ] ); } else { used_gap = AST__BAD; } return used_gap; } /* See if the user has specified a gap size. The default for astGetLogTicks is determined in DefGaps, so we can now decide whether to use attribute Gap or LogGap to get the user-supplied gap size. Obtain the requested gap attribute values for both physical axes. */ if( astGetLogTicks( this, axis ) ) { gap = astGetLogGap( this, axis ); } else { gap = astGetGap( this, axis ); } /* Find the maximum and minimum value in the plotting area. DefGap will have reported an error if minv*maxv is negative or zero. */ if( astOK ) { maxv = statics->ptr[ axis ][ statics->ngood[ axis ] - 1 ]; minv = statics->ptr[ axis ][ 0 ]; } /* First deal with logarithmically spaced ticks. */ dran = ( minv != 0.0 ) ? maxv/minv : 0.0; if( astGetLogTicks( this, axis ) ) { /* If the ratio of max and min data value is not larger than 10, report an error. */ dran = ( minv != 0.0 ) ? maxv/minv :0.0; if( dran < 10.0 && dran > 0.1 ) { astError( AST__VSMAL, "%s(%s): Cannot produce logarithmically " "spaced major tick marks on axis %d since the dynamic " "range of the axis is too small.", status, method, class, axis + 1 ); } /* Should we find a new value for "cen"? */ findcen = !cen || *cen == AST__BAD || !format_set; /* Try to find a "nice" gap size, so long as the caller has not supplied a gap size. The default gap size obtained above is our initial guess. */ if( gap == AST__BAD && astOK ){ /* Start off using the default gap found during the initialisation. */ test_gap = statics->defgaps[ axis ]; /* Loop round until a gap size is found which gives an acceptable number of tick marks. Upto 10 gap sizes are tried. */ for( i = 0; i < 10 && astOK; i++ ){ /* Find a "nice" gap size close to the current test gap size. Also find the number of minor tick marks to use with the nice gap size. Gaps for logarithmic axes are always powers of ten. */ log_used_gap = (int) ( log10( test_gap ) + 0.5 ); if( log_used_gap == 0.0 ) { log_used_gap = ( test_gap > 1.0 ) ? 1.0 : -1.0; } *nminor = 9; used_gap = pow( 10.0, log_used_gap ); /* If no value has been supplied for *cen, choose a value which would put a major tick mark at the value 1 (or -1), and which is mid way between the maximum and minimum axis value. */ if( findcen ) { used_cen = pow( used_gap, (int) ( 0.5*log10( maxv*minv ) / log_used_gap ) ); if( maxv < 0 ) used_cen = -used_cen; } else { used_cen = *cen; } /* Find the index of the highest tick which is not larger than the lowest axis value. */ if( log_used_gap > 0.0 ) { ilo = floor( log10( minv/used_cen )/log_used_gap ); } else { ilo = ceil( log10( minv/used_cen )/log_used_gap ); } /* Find the index of the lowest tick which is not less than the highest axis value. */ if( log_used_gap > 0.0 ) { ihi = ceil( log10( maxv/used_cen )/log_used_gap ); } else { ihi = floor( log10( maxv/used_cen )/log_used_gap ); } /* Find the total number of tick marks. */ *nmajor = ihi - ilo + 1; /* If the number of ticks is unacceptable, try a different gap size. If the gap was too large to produce any ticks, try using half the gap size. */ if( *nmajor <= 0 ) { test_gap = sqrt( test_gap ); /* If there were some ticks, but not enough, decrease the gap size in proportion to the shortfall. */ } else if( *nmajor < statics->mintick ){ test_gap = pow( test_gap, (double)( *nmajor )/(double)( statics->mintick ) ); /* If there were too many ticks, increase the gap size in proportion to the excess. */ } else if( *nmajor > statics->maxticks ){ test_gap = pow( test_gap, (double)( *nmajor )/(double)( statics->maxticks ) ); /* If the number of ticks is acceptable, break out of the loop early.*/ } else { break; } } /* Increase the tick coverage by one at each end to cover up the gaps. */ ilo--; ihi++; *nmajor += 2; /* If an explicit gap size was supplied, use it. */ } else if( astOK ) { /* Check it is usable. */ if( gap == 0.0 && astOK ) { astError( AST__ATTIN, "%s(%s): Invalid value zero given for " "attribute LogGap(%d).", status, method, class, axis + 1 ); } else if( gap < 0.0 && astOK ) { astError( AST__ATTIN, "%s(%s): Invalid negative value %f given for " "attribute LogGap(%d).", status, method, class, gap, axis + 1 ); /* If necessary, take its reciprocal in order to ensure that the absolute tick mark values get smaller or larger as required. */ } else { used_gap = gap; if( fabs( maxv ) < fabs( minv ) ) { if( gap > 1.0 ) used_gap = 1.0/gap; } else { if( gap < 1.0 ) used_gap = 1.0/gap; } /* Find the nearest power of 10 ( do not allow 10**0 (=1.0) to be used). */ log_used_gap = (int) ( log10( used_gap ) + 0.5 ); if( log_used_gap == 0.0 ) { log_used_gap = ( gap > 1.0 ) ? 1.0 : -1.0; } used_gap = pow( 10.0, log_used_gap ); /* We always use 9 minor intervals. */ *nminor = 9; /* If no value has been supplied for *cen, choose a value which would put a major tick mark at the value 1 (or -1), and which is mid way between the maximum and minimum axis value. */ if( findcen ) { used_cen = pow( used_gap, (int) ( 0.5*log10( maxv*minv ) / log_used_gap ) ); if( maxv < 0 ) used_cen = -used_cen; } else { used_cen = *cen; } /* Find the index of the highest tick which is not larger than the lowest axis value. */ if( log_used_gap > 0.0 ) { ilo = floor( log10( minv/used_cen )/log_used_gap ); } else { ilo = ceil( log10( minv/used_cen )/log_used_gap ); } /* Find the index of the lowest tick which is not less than the highest axis value. */ if( log_used_gap > 0.0 ) { ihi = ceil( log10( maxv/used_cen )/log_used_gap ); } else { ihi = floor( log10( maxv/used_cen )/log_used_gap ); } /* Find the total number of tick marks. */ *nmajor = ihi - ilo + 1; if( *nmajor < 2 && astOK ) { astError( AST__ATTIN, "%s(%s): Unusable value %f given for " "attribute LogGap(%d).", status, method, class, gap, axis + 1 ); } } } /* Allocate memory to hold the tick values themselves. */ *ticks = (double *) astMalloc( sizeof( double )*( *nmajor ) ); if( astOK ) { /* Store them. */ tick = *ticks; for( i = ilo; i <= ihi; i++, tick++ ) { *tick = used_cen*pow( used_gap, i ); } } /* Store returned centre value. */ if( cen ) *cen = used_cen; /* Now deal with linearly spaced ticks */ } else { /* Store the supplied value of cen. */ cen0 = ( cen ) ? *cen : AST__BAD; /* If no format has been set for the axis, ensure AST__BAD is used for cen. */ if( !format_set ) cen0 = AST__BAD; /* Try to find a "nice" gap size, so long as the caller has not supplied a gap size. The default gap size obtained above is our initial guess. */ if( gap == AST__BAD ){ old_used_gap = AST__BAD; /* Start of using the default gap found during the initialisation. */ test_gap = statics->defgaps[ axis ]; used_gap = 0.0; /* Initialise flags saying the test gap is too large or too small */ gap_too_large = 0; gap_too_small = 0; /* So far, there have been no ineffective attempts to change the gap size. */ nochange = 0; /* Loop round until a gap size is found which gives an acceptable number of tick marks. Upto 10 gap sizes are tried. */ for( i = 0; i < 10 && astOK; i++ ){ /* Find a "nice" gap size close to the current test gap size. Also find the number of minor tick marks to use with the nice gap size. */ new_used_gap = astGap( statics->frame, axis, test_gap, nminor ); /* Find the number and positions of major tick marks which would result from using this gap size. Annul the memory used to hold any previous tick data first. Only do this if the gap being used has actually changed, otherwise we just retain the values created from the previous run with this gap size. */ if( new_used_gap != used_gap ) { nochange = 0; old_used_gap = used_gap; used_gap = new_used_gap; if( *ticks ) *ticks = astFree( *ticks ); if( cen ) *cen = cen0; *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], used_gap, cen, statics->ngood[ axis ], statics->ptr[ axis ], ticks, status ); /* If the gap size has not changed do an extra pass through this loop, but only do this a maximum of 25 times in succession. */ } else if( nochange < 25 ) { nochange++; i--; } else if( astOK ){ astError( AST__VSMAL, "%s(%s): Cannot produce enough major " "tick marks on axis %d using the current axis " "format (\"%s\").", status, method, class, axis + 1, astGetFormat( statics->frame, axis ) ); break; } /* If the number of ticks is unacceptable, try a different gap size. If the gap was too large to produce any ticks, try using half the gap size. */ if( *nmajor == 0 ) { test_gap *= 0.5; gap_too_large = 1; gap_too_small = 0; /* If there were some ticks, but not enough... */ } else if( *nmajor < statics->mintick ){ /* If the previous test gap produced too many ticks, use the current gap size. */ if( gap_too_small ) { break; /* Otherwise, decrease the gap size in proportion to the shortfall. */ } else { test_gap *= (double)( *nmajor )/(double)( statics->mintick ); gap_too_large = 1; gap_too_small = 0; } /* If there were too many ticks... */ } else if( *nmajor > statics->maxticks ){ /* If the previous test gap produced too few ticks, use the previous gap size. */ if( gap_too_large ) { used_gap = old_used_gap; if( *ticks ) *ticks = astFree( *ticks ); if( cen ) *cen = cen0; *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], used_gap, cen, statics->ngood[ axis ], statics->ptr[ axis ], ticks, status ); break; /* Otherwise, increase the gap size in proportion to the excess. */ } else { test_gap *= (double)( *nmajor )/(double)( statics->maxticks ); gap_too_small = 1; gap_too_large = 0; } /* If the number of ticks is acceptable, break out of the loop early.*/ } else { break; } } /* If an explicit gap size was supplied, use it. */ } else { /* Find a likely value for the number of minor tick marks to use, and find a nice gap close to the supplied gap (unless an explicit format has been set). */ if( format_set ){ used_gap = gap; (void) astGap( statics->frame, axis, used_gap, nminor ); } else { used_gap = astGap( statics->frame, axis, gap, nminor ); } /* Find where the major ticks should be put. */ if( cen ) *cen = cen0; *nmajor = FindMajTicks( statics->map, statics->frame, axis, *refval, statics->width[ 1-axis ], used_gap, cen, statics->ngood[ axis ], statics->ptr[ axis ], ticks, status ); } } /* Report an error if no ticks can be found. */ if( *nmajor == 0 && astOK ) { astError( AST__GRFER, "%s(%s): Cannot find any usable tick mark values. ", status, method, class ); } /* If an error has occurred, annul the memory used to hold tick data, and return zero ticks. */ if( !astOK ) { *ticks = (double *) astFree( (void *) *ticks ); *nmajor = 0; *nminor = 0; used_gap = 0.0; } /* Return. */ return used_gap; } static double GoodGrid( AstPlot *this, int *dim, AstPointSet **pset1, AstPointSet **pset2, const char *method, const char *class, int *status ){ /* * Name: * GoodGrid * Purpose: * Create a grid covering the region containing good coordinates in a * 2-D physical coordinate Frame. * Type: * Private function. * Synopsis: * #include "plot.h" * double GoodGrid( AstPlot *this, int *dim, AstPointSet **pset1, * AstPointSet **pset2, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function creates two PointSets, one holding a square grid of * graphics coordinates, and the other holding the corresponding physical * coordinates (not normalized). The grid covers just the area containing * good physical coordinates. The points are stored row by row in the * returned PointSets. * Parameters: * this * The Plot. * dim * A pointer to an integer in which to store the number of samples * along each edge of the returned grid. * pset1 * A pointer to a location at which to store a pointer to the * PointSet holding the graphics coordinates. * pset2 * A pointer to a location at which to store a pointer to the * PointSet holding the physical coordinates. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The fraction of the plotting area containing good physical * coordinates. * Notes: * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - The returned PointSets should be annulled when no longer needed, * using astAnnul. * - An error is reported if the region containing valid physical * coordinates is too small to use. * - A function value of zero, and NULL pointers are returned if an error * has already occurred, or if this function should fail for any reason. */ /* Local Variables: */ AstFrame *frm; /* Pointer to the Current Frame in the Plot */ AstMapping *map; /* Pointer to "graphics to physical" mapping */ double **ptr1; /* Pointer to physical axis value data */ double **ptr2; /* Pointer to graphics axis value data */ double *pa; /* Pointer to next value on 1st physical axis */ double *pb; /* Pointer to next value on 2nd physical axis */ double *px; /* Pointer to next value on 1st graphics axis */ double *py; /* Pointer to next value on 2nd graphics axis */ double dx; /* Cell size along graphics X (1st) axis */ double dy; /* Cell size along graphics Y (2nd) axis */ double frac; /* Fraction of good physical coordinates */ double xmax; /* High X bound of region containing good phy. coords */ double xmin; /* Low X bound of region containing good phy. coords */ double ymax; /* High Y bound of region containing good phy. coords */ double ymin; /* Low Y bound of region containing good phy. coords */ int j; /* Element offset */ int ngood; /* Number of grid points with good physical coords */ int size; /* Number of grid points */ /* Initialise the returned PointSet pointers. */ *pset1 = NULL; *pset2 = NULL; /* Check the global error status. */ if ( !astOK ) return 0.0; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ ptr1 = NULL; frac = 0.0; xmax = 0.0; xmin = 0.0; ymax = 0.0; ymin = 0.0; /* Get the Mapping from base (graphics) to current (physical) Frame in the supplied Plot. */ map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Get a pointer to the Current Frame in the Plot. */ frm = astGetFrame( this, AST__CURRENT ); /* Initialise the grid dimension. */ *dim = 16; /* We need a grid which has at least 4 good points. */ ngood = 0; while( ngood < 4 && astOK ){ /* Double the grid dimension. */ *dim *= 2; /* Report an error if the grid is now too big. */ if( *dim >= 512 ){ astError( AST__VSMAL, "%s(%s): The area of the plot containing " "usable coordinates on both axes is too small.", status, method, class ); break; } /* Get two PointSets, one holding a regular grid of graphics coordinates, and the other holding the corresponding physical coordinates. The grid covers the entire plotting area with the current grid dimension. A pointer to the physical axis values is returned. */ ptr2 = MakeGrid( this, frm, map, 1, *dim, this->xlo, this->xhi, this->ylo, this->yhi, 2, pset1, pset2, 0, method, class, status ); /* Get the number of graphics axis values. */ size = astGetNpoint( *pset1 ); /* Get a pointer to the graphics axis values. */ ptr1 = astGetPoints( *pset1 ); /* Check the pointers can be used. */ if( astOK ){ /* Find the bounds in graphics coordinates of the area enclosing the good physical positions in the grid, and count the good positions. */ ngood = 0; pa = ptr2[ 0 ]; pb = ptr2[ 1 ]; px = ptr1[ 0 ]; py = ptr1[ 1 ]; xmin = DBL_MAX; xmax = -DBL_MAX; ymin = DBL_MAX; ymax = -DBL_MAX; for( j = 0; j < size; j++ ){ if( *pa != AST__BAD && *pb != AST__BAD ){ if( *px < xmin ) xmin = *px; if( *px > xmax ) xmax = *px; if( *py < ymin ) ymin = *py; if( *py > ymax ) ymax = *py; ngood++; } px++; py++; pa++; pb++; } } } /* Store approximate fraction of the plotting area containing good physical coordinates. */ if( astOK ) { frac = ( (double) ngood )/(double)( astGetNpoint( *pset1 ) ); /* Get the size of each grid cell. */ dx = ptr1[0][1] - ptr1[0][0]; dy = ptr1[1][1] - ptr1[1][0]; /* Extend the area containing good points by one grid cell. */ xmax += dx; xmin -= dx; ymax += dy; ymin -= dy; /* If the area containing good points is significantly smaller than the supplied area, create a new grid covering just the area containing good positions. */ if( ( xmax - xmin ) < 0.9*( this->xhi - this->xlo ) || ( ymax - ymin ) < 0.9*( this->yhi - this->ylo ) ){ /* Find a new grid dimension which results in a cell size similar to the one used to create the grid, but covering only the region containing good physical coordinates. */ *dim *= MAX( (xmax - xmin)/(this->xhi - this->xlo), (ymax - ymin)/(this->yhi - this->ylo) ); if( *dim < 32 ) *dim = 32; /* Annul the PointSet holding the current grid. */ *pset1 = astAnnul( *pset1 ); *pset2 = astAnnul( *pset2 ); /* Create the new grid covering the region containing good physical coordinates. */ (void) MakeGrid( this, frm, map, 1, *dim, xmin, xmax, ymin, ymax, 2, pset1, pset2, 0, method, class, status ); } } /* Annul the Mapping from base to current Frame, and the pointer to the Current Frame. */ map = astAnnul( map ); frm = astAnnul( frm ); /* If an error has occurred, annul the two pointsets and indicate that there are no good points in the plotting area. */ if( !astOK ){ *pset1 = astAnnul( *pset1 ); *pset2 = astAnnul( *pset2 ); frac = 0.0; } /* Return. */ return frac; } static int GraphGrid( int dim, int disk, double xlo, double xhi, double ylo, double yhi, double **ptr1, int *status ){ /* * Name: * GraphGrid * Purpose: * Fill an array with a square grid of graphics coordinates. * Type: * Private function. * Synopsis: * #include "plot.h" * int GraphGrid( int dim, int disk, double xlo, double xhi, double ylo, * double yhi, double **ptr1, int *status ) * Class Membership: * Plot member function. * Description: * This function fills the supplied array with a square grid of graphics * coordinates covering the supplied area. The points are stored row by * row, i.e. if the cell size for the grid is (dx,dy), the first point * is (xmin,ymin), followed by (xmin+dx,ymin), (xmin+2*dx,ymin), up to * (xmin+(dim-1)*dx,ymin), followed by the next row (xmin,ymin+dy), * (xmin+dx,ymin+dy), etc. * Parameters: * dim * The number of samples along each edge of the grid. * disk * If non-zero, the corners of the grid are omitted, resulting in a * grid that is more disk like than rectangular. * xlo * The lower bound on the first axis of the region to be covered * by the grid. * xhi * The upper bound on the first axis of the region to be covered * by the grid. * ylo * The lower bound on the second axis of the region to be covered * by the grid. * yhi * The upper bound on the second axis of the region to be covered * by the grid. * ptr1 * A pointer to an array of two pointers giving the start of the two * arrays to receive the values for each of the two axes of the graphics * coordinate data. * status * Pointer to the inherited status variable. * Returned Value: * The number of points in the grid. If "disk" is zero, this will be * the square of "dim". If "disk" is non-zero, this will be less than * the square of "dim" to account for the lack of corner points. */ /* Local Variables: */ double *px; double *py; double cen; double dx; double dy2; double dy; double dx2; double r2; double y; int i; int j; int ok; /* Check the global error status. */ if ( !astOK ) return 0; /* Find the cell size. */ dx = ( xhi - xlo )/(double)( dim - 1 ); dy = ( yhi - ylo )/(double)( dim - 1 ); /* Store the mid cell index. */ cen = 0.5*( dim - 1 ); /* Store the squared radius of the disk. */ r2 = 1.9*cen*cen; /* Initialise pointers to the start of the two arrays to recieve the returned graphics values for each axis. */ px = ptr1[ 0 ]; py = ptr1[ 1 ]; /* Loop round row. */ for( j = 0; j < dim; j++ ){ dy2 = j - cen; dy2 *= dy2; /* Get the Y coordinate of the current row. */ y = ylo + j*dy; /* Loop round each column in the current row. */ for( i = 0; i < dim; i++ ){ /* If we are forming a disk rather than a square, check if this point is sufficiently close to the centre to be included in the disk. */ if( disk ) { dx2 = i - cen; dx2 *= dx2; ok = ( dx2 + dy2 <= r2 ); } else { ok = 1; } /* Store the coordinates of the current grid point. */ if( ok ) { *(px++) = xlo + i*dx; *(py++) = y; } } } /* Return the used length of the PointSet. */ return (int)( px - ptr1[ 0 ] ); } static void GrfPop( AstPlot *this, int *status ) { /* *++ * Name: c astGrfPop f AST_GRFPOP * Purpose: * Restore previously saved graphics functions used by a Plot. * Type: * Public function. * Synopsis: c #include "plot.h" c void astGrfPop( AstPlot *this ) f CALL AST_GRFPOP( THIS STATUS ) * Class Membership: * Plot member function. * Description: c This function restores a snapshot of the graphics functions c stored previously by calling astGrfPush. The restored graphics c functions become the current graphics functions used by the Plot. * c The astGrfPush and astGrfPop functions are intended for situations c where it is necessary to make temporary changes to the graphics c functions used by the Plot. The current functions should first be c saved by calling astGrfPush. New functions should then be registered c using astGrfSet. The required graphics should then be produced. c Finally, astGrfPop should be called to restore the original graphics c functions. f The AST_GRFPUSH and AST_GRFPOP functions are intended for situations f where it is necessary to make temporary changes to the graphics f functions used by the Plot. The current functions should first be f saved by calling AST_GRFPUSH. New functions should then be registered f using AST_GRFSET. The required graphics should then be produced. f Finally, AST_GRFPOP should be called to restore the original graphics f functions. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: f - This routine returns without action if there are no snapshots to c - This function returns without action if there are no snapshots to * restore. No error is reported in this case. *-- */ /* Local Variables: */ AstGrfPtrs *newframe; /* Pointer to the stack frame to restore */ int i; /* Loop count */ /* Check the global error status. */ if ( !astOK ) return; /* Check the stack is not already empty. */ if( this->grfnstack > 0 ) { this->grfnstack--; if( astOK ) { newframe = this->grfstack + this->grfnstack; for( i = 0; i < AST__NGRFFUN; i++ ) { this->grffun[i] = (newframe->grffun)[i]; } this->GAttr = newframe->GAttr; this->GBBuf = newframe->GBBuf; this->GEBuf = newframe->GEBuf; this->GFlush = newframe->GFlush; this->GLine = newframe->GLine; this->GMark = newframe->GMark; this->GText = newframe->GText; this->GCap = newframe->GCap; this->GTxExt = newframe->GTxExt; this->GScales = newframe->GScales; this->GQch = newframe->GQch; } } } static void GrfPush( AstPlot *this, int *status ) { /* *++ * Name: c astGrfPush f AST_GRFPUSH * Purpose: * Save the current graphics functions used by a Plot. * Type: * Public function. * Synopsis: c #include "plot.h" c void astGrfPush( AstPlot *this ) f CALL AST_GRFPUSH( THIS STATUS ) * Class Membership: * Plot member function. * Description: c This function takes a snapshot of the graphics functions which are f This routine takes a snapshot of the graphics functions which are * currently registered with the supplied Plot, and saves the snapshot * on a first-in-last-out stack within the Plot. The snapshot can be * restored later using function c astGrfPop. f AST_GRFPOP. * c The astGrfPush and astGrfPop functions are intended for situations c where it is necessary to make temporary changes to the graphics c functions used by the Plot. The current functions should first be c saved by calling astGrfPush. New functions should then be registered c using astGrfSet. The required graphics should then be produced. c Finally, astGrfPop should be called to restore the original graphics c functions. f The AST_GRFPUSH and AST_GRFPOP functions are intended for situations f where it is necessary to make temporary changes to the graphics f functions used by the Plot. The current functions should first be f saved by calling AST_GRFPUSH. New functions should then be registered f using AST_GRFSET. The required graphics should then be produced. f Finally, AST_GRFPOP should be called to restore the original graphics f functions. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstGrfPtrs *newframe; /* Pointer to the new stack frame */ int i; /* Loop count */ /* Check the global error status. */ if ( !astOK ) return; /* Increment the number of frames on the stack. */ this->grfnstack++; /* Ensure the stack is large enough to hold this many frames. */ this->grfstack = (AstGrfPtrs *) astGrow( (void *) this->grfstack, this->grfnstack, sizeof( AstGrfPtrs ) ); if( astOK ) { /* Get a pointer to the new stack frame. */ newframe = this->grfstack + this->grfnstack - 1; /* Copy the graphics function pointers from the main Plot attributes to the new stack frame. */ for( i = 0; i < AST__NGRFFUN; i++ ) { (newframe->grffun)[i] = this->grffun[i]; } newframe->GAttr = this->GAttr; newframe->GBBuf = this->GBBuf; newframe->GEBuf = this->GEBuf; newframe->GFlush = this->GFlush; newframe->GLine = this->GLine; newframe->GMark = this->GMark; newframe->GText = this->GText; newframe->GCap = this->GCap; newframe->GTxExt = this->GTxExt; newframe->GQch = this->GQch; newframe->GScales = this->GScales; } } static void GrfSet( AstPlot *this, const char *name, AstGrfFun fun, int *status ){ /* *++ * Name: c astGrfSet f AST_GRFSET * Purpose: c Register a graphics function for use by a Plot. f Register a graphics routine for use by a Plot. * Type: * Public function. * Synopsis: c #include "plot.h" c void astGrfSet( AstPlot *this, const char *name, AstGrfFun fun ) f CALL AST_GRFSET( THIS, NAME, FUN, STATUS ) * Class Membership: * Plot member function. * Description: c This function can be used to select the underlying graphics c functions to be used when the supplied Plot produces graphical output. c If this function is not called prior to producing graphical c output, then the underlying graphics functions selected at c link-time (using the ast_link command) will be used. To use c alternative graphics functions, call this function before c the graphical output is created, specifying the graphics c functions to be used. This will register the function for future c use, but the function will not actually be used until the Grf c attribute is given a non-zero value. f This routine can be used to select the underlying graphics f routines to be used when the supplied Plot produces graphical output. f If this routine is not called prior to producing graphical f output, then the underlying graphics routines selected at f link-time (using the ast_link command) will be used. To use f alternative graphics routines, call this routine before f the graphical output is created, specifying the graphics f routines to be used. This will register the routine for future f use, but the routine will not actually be used until the Grf f attribute is given a non-zero value. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c name f NAME = CHARACTER * ( * ) (Given) c A name indicating the graphics function to be replaced. c Various graphics functions are used by the c Plot class, and any combination of them may be supplied by calling c this function once for each function to be replaced. If any of the c graphics functions are not replaced in this way, the c corresponding functions in the graphics interface selected at c link-time (using the ast_link command) are used. The allowed c names are: f A name indicating the graphics routine to be replaced. f Various graphics routines are used by the f Plot class, and any combination of them may be supplied by calling f this routine once for each routine to be replaced. If any of the f graphics routines are not replaced in this way, the f corresponding routines in the graphics interface selected at f link-time (using the ast_link command) are used. The allowed f function names are: * * - Attr - Enquire or set a graphics attribute value * - BBuf - Start a new graphics buffering context * - Cap - Inquire a capability * - EBuf - End the current graphics buffering context * - Flush - Flush all pending graphics to the output device * - Line - Draw a polyline (i.e. a set of connected lines) * - Mark - Draw a set of markers * - Qch - Return the character height in world coordinates * - Scales - Get the axis scales * - Text - Draw a character string * - TxExt - Get the extent of a character string * * The string is case insensitive. For details of the interface * required for each, see the sections below. c fun f FUN = INTEGER FUNCTION (Given) c A Pointer to the function to be used to provide the c functionality indicated by parameter name. The interface for c each function is described below, but the function pointer should c be cast to a type of AstGrfFun when calling astGrfSet. f The name of the routine to be used to provide the f functionality indicated by parameter NAME (the name f should also appear in a Fortran EXTERNAL statement in the f routine which invokes AST_GRFSET). * c Once a function has been provided, a null pointer can be supplied c in a subsequent call to astGrfSet to reset the function to the c corresponding function in the graphics interface selected at c link-time. f Once a routine has been provided, the "null" routine AST_NULL can f be supplied in a subsequent call to astGrfSet to reset the routine f to the corresponding routine in the graphics interface selected at f link-time. AST_NULL is defined in the AST_PAR include file. f STATUS = INTEGER (Given and Returned) f The global status. * Function Interfaces: * All the functions listed below (except for "Cap") should return an * integer value of 0 if an error occurs, and 1 otherwise. All x and y * values refer f to "graphics cordinates" as defined by the GRAPHBOX parameter of f the AST_PLOT call which created the Plot. c to "graphics cordinates" as defined by the graphbox parameter of c the astPlot call which created the Plot. * c The first parameter ("grfcon") f The first argument (GRFCON) * for each function is an AST KeyMap pointer that can be used by the * called function to establish the context in which it is being called. * The contents of the KeyMap are determined by the calling * application, which should obtain a pointer to the KeyMap using the f AST_GETGRFCONTEXT routine, c astGetGrfContext function, * and then store any necessary information in the KeyMap using the * methods of the KeyMap class. Note, the functions listed below * should never annul or delete the supplied KeyMap pointer. * Attr: * The "Attr" function returns the current value of a specified graphics * attribute, and optionally establishes a new value. The supplied * value is converted to an integer value if necessary before use. * It requires the following interface: * c int Attr( AstObject *grfcon, int attr, double value, double *old_value, int prim ) f INTEGER FUNCTION ATTR( GRFCON, ATT, VAL, OLDVAL, PRIM ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - attr - An integer value identifying the required attribute. c The following symbolic values are defined in grf.h: f - ATT = INTEGER (Given) - An integer identifying the required attribute. f The following symbolic values are defined in GRF_PAR: * GRF__STYLE (Line style), * GRF__WIDTH (Line width), * GRF__SIZE (Character and marker size scale factor), * GRF__FONT (Character font), * GRF__COLOUR (Colour index). c - value - f - VAL = DOUBLE PRECISION (Given) - c A new value to store for the attribute. If this is AST__BAD * no value is stored. c - old_value - A pointer to a double in which to return f - OLDVAL = DOUBLE PRECISION (Returned) - Returned holding * the attribute value. c If this is NULL, no value is returned. c - prim - f - PRIM = INTEGER (Given) - * The sort of graphics primitive to be drawn with the new attribute. c Identified by the following values defined in grf.h: f Identified by the following values defined in GRF_PAR: * GRF__LINE, * GRF__MARK, * GRF__TEXT. * BBuf: * The "BBuf" function should start a new graphics buffering context. * A matching call to the function "EBuf" should be used to end the * context. The nature of the buffering is determined by the underlying * graphics system. * c int BBuf( AstObject *grfcon ) f INTEGER FUNCTION BBUF( GRFCON ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. * Cap: * The "Cap" function is called to determine if the grf module has a * given capability, as indicated by the "cap" argument: * c int Cap( AstObject *grfcon, int cap, int value ) f INTEGER FUNCTION CAP( GRFCON, CAP, VALUE ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - cap - f - CAP = INTEGER (Given) * The capability being inquired about. This will be one of the c following constants defined in grf.h: f following constants defined in GRF_PAR: * * GRF__SCALES: This function should return a non-zero value if the * "Scales" function is implemented, and zero otherwise. The supplied c "value" argument should be ignored. f VALUE argument should be ignored. * * GRF__MJUST: This function should return a non-zero value if * the "Text" and "TxExt" functions recognise "M" as a * character in the justification string. If the first character of * a justification string is "M", then the text should be justified * with the given reference point at the bottom of the bounding box. * This is different to "B" justification, which requests that the * reference point be put on the baseline of the text, since some * characters hang down below the baseline. If the "Text" or * "TxExt" function cannot differentiate between "M" and "B", * then this function should return zero, in which case "M" * justification will never be requested by Plot. The supplied c "value" argument should be ignored. f VALUE argument should be ignored. * * GRF__ESC: This function should return a non-zero value if the * "Text" and "TxExt" functions can recognise and interpret * graphics escape sequences within the supplied string (see * attribute Escape). Zero should be returned if escape sequences * cannot be interpreted (in which case the Plot class will interpret c them itself if needed). The supplied "value" argument should be f them itself if needed). The supplied VALUE argument should be * ignored only if escape sequences cannot be interpreted by "Text" and c "TxExt". Otherwise, "value" indicates whether "Text" and "TxExt" c should interpret escape sequences in subsequent calls. If "value" is f "TxExt". Otherwise, VALUE indicates whether "Text" and "TxExt" f should interpret escape sequences in subsequent calls. If VALUE is * non-zero then escape sequences should be interpreted by "Text" and * "TxExt". Otherwise, they should be drawn as literal text. * c - value - f - VALUE = INTEGER (Given) c The use of this parameter depends on the value of "cap" as f The use of this parameter depends on the value of CAP as * described above. * - Returned Function Value: c The value returned by the function depends on the value of "cap" f The value returned by the function depends on the value of CAP * as described above. Zero should be returned if the supplied * capability is not recognised. * EBuf: * The "EBuf" function should end the current graphics buffering * context. See the description of "BBuf" above for further details. * It requires the following interface: * c int EBuf( AstObject *grfcon ) f INTEGER FUNCTION EBUF( GRFCON ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. * Flush: * The "Flush" function ensures that the display device is up-to-date, * by flushing any pending graphics to the output device. It * requires the following interface: * c int Flush( AstObject *grfcon ) f INTEGER FUNCTION FLUSH( GRFCON ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. * Line: * The "Line" function displays lines joining the given positions and * requires the following interface: * c int Line( AstObject *grfcon, int n, const float *x, const float *y ) f INTEGER FUNCTION LINE( GRFCON, N, X, Y ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - n - The number of positions to be joined together. f - N = INTEGER (Given) - The number of positions to be joined together. c - x - A pointer to an array holding the "n" x values. f - X( N ) = REAL (Given) - An array holding the "n" x values. c - y - A pointer to an array holding the "n" y values. f - Y( N ) = REAL (Given) - An array holding the "n" y values. * Mark: * The "Mark" function displays markers at the given positions. It * requires the following interface: * c int Mark( AstObject *grfcon, int n, const float *x, const float *y, int type ) f INTEGER FUNCTION MARK( GRFCON, N, X, Y, TYPE ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - n - The number of positions to be marked. f - N = INTEGER (Given) - The number of positions to be marked. c - x - A pointer to an array holding the "n" x values. f - X( N ) = REAL (Given) - An array holding the "n" x values. c - y - A pointer to an array holding the "n" y values. f - Y( N ) = REAL (Given) - An array holding the "n" y values. c - type - An integer which can be used to indicate the type of marker c symbol required. f - TYPE = INTEGER (Given) - An integer which can be used to indicate f the type of marker symbol required. * Qch: * The "Qch" function returns the heights of characters drawn vertically * and horizontally in graphics coordinates. It requires the following * interface: * c int Qch( AstObject *grfcon, float *chv, float *chh ) f INTEGER FUNCTION QCH( GRFCON, CHV, CHH ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - chv - A pointer to the float which is to receive the height of f - CHV = REAL (Returned) The height of * characters drawn with a vertical baseline. This will be an * increment in the X axis. c - chh - A pointer to the float which is to receive the height of f - CHH = REAL (Returned) The height of * characters drawn with a horizontal baseline. This will be an * increment in the Y axis. * Scales: * The "Scales" function returns two values (one for each axis) which * scale increments on the corresponding axis into a "normal" coordinate * system in which: 1) the axes have equal scale in terms of (for instance) * millimetres per unit distance, 2) X values increase from left to * right, and 3) Y values increase from bottom to top. It requires the * following interface: * c int Scales( AstObject *grfcon, float *alpha, float *beta ) f INTEGER FUNCTION SCALES( GRFCON, ALPHA, BETA ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - alpha - A pointer to the float which is to receive the f - ALPHA = REAL (Returned) The * scale for the X axis (i.e. Xnorm = alpha*Xworld). c - beta - A pointer to the float which is to receive the f - BETA = REAL (Returned) The * scale for the Y axis (i.e. Ynorm = beta*Yworld). * Text: * The "Text" function displays a character string at a given * position using a specified justification and up-vector. It * requires the following interface: * c int Text( AstObject *grfcon, const char *text, float x, float y, const char *just, c float upx, float upy ) f INTEGER FUNCTION TEXT( GRFCON, TEXT, X, Y, JUST, UPX, UPY ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - text - Pointer to a null-terminated character string to be displayed. f - TEXT = CHARACTER * ( * ) (Given) - The string to be displayed. c - x - The reference x coordinate. f - X = REAL (Given) - The reference x coordinate. c - y - The reference y coordinate. f - Y = REAL (Given) - The reference y coordinate. c - just - A character string which specifies the location within the f - JUST = CHARACTER * ( * ) (Given ) - A string which specifies the f 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. c - upx - The x component of the up-vector for the text. f - UPX = REAL (Given) - The x component of the up-vector for the text. * If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * left to right on the screen. c - upy - The y component of the up-vector for the text. f - UPX = REAL (Given) - The y component of the up-vector for the text. * If necessary the supplied value should be negated * to ensure that positive values always refer to displacements from * bottom to top on the screen. * TxExt: * The "TxExt" function returns the corners of a box which would enclose * the supplied character string if it were displayed using the * Text function described above. The returned box includes any leading * or trailing spaces. It requires the following interface: * c int TxExt( AstObject *grfcon, const char *text, float x, float y, const char *just, c float upx, float upy, float *xb, float *yb ) f INTEGER FUNCTION TXEXT( GRFCON, TEXT, X, Y, JUST, UPX, UPY, XB, YB ) * c - grfcon - f - GRFCON = INTEGER (Given) - * A KeyMap containing information passed from the calling application. c - text - Pointer to a null-terminated character string to be displayed. f - TEXT = CHARACTER * ( * ) (Given) - The string to be displayed. c - x - The reference x coordinate. f - X = REAL (Given) - The reference x coordinate. c - y - The reference y coordinate. f - Y = REAL (Given) - The reference y coordinate. c - just - A character string which specifies the location within the f - JUST = CHARACTER * ( * ) (Given ) - A string which specifies the f location within the * text string which is to be placed at the reference position * given by x and y. See "Text" above. c - upx - The x component of the up-vector for the text. f - UPX = REAL (Given) - The x component of the up-vector for the text. * See "Text" above. c - upy - The y component of the up-vector for the text. f - UPX = REAL (Given) - The y component of the up-vector for the text. * See "Text" above. c - xb - An array of 4 elements in which to return the x coordinate of f - XB( 4 ) = REAL (Returned) - Returned holding the x coordinate of * each corner of the bounding box. c - yb - An array of 4 elements in which to return the y coordinate of f - YB( 4 ) = REAL (Returned) - Returned holding the y coordinate of * each corner of the bounding box. *-- */ /* Local Variables: */ const char *class; /* Object class */ const char *method; /* Current method */ int ifun; /* Index into grf function list */ void (* wrapper)(); /* Wrapper function for C Grf routine*/ /* Check the global error status. */ if ( !astOK ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ wrapper = NULL; /* Store the current method and class for inclusion in error messages generated by lower level functions. */ method = "astGrfSet"; class = astClass( this ); /* Identify the supplied function name and get its integer index into the list of grf functions. */ ifun = astGrfFunID( name, method, class ); /* Store the pointer. */ if( astOK ) { this->grffun[ifun] = fun; /* In general, the interface to each Grf function will differ for different languages. So we need a wrapper function with a known fixed interface which can be used to invoke the actual Grf function with an interface suited to the language in use. Call astGrfWrapper to store a wrapper to a suitable function which can invoke the supplied grf function. Here, we assume that the supplied function has a C interface, so we set up a C wrapper. If this function is being called from another language, then the interface for this function within that language should set up an appropriate wrapper after calling this function, thus over-riding the C wrapper set up here. */ if( ifun == AST__GATTR ) { wrapper = (AstGrfWrap) CGAttrWrapper; } else if( ifun == AST__GBBUF ) { wrapper = (AstGrfWrap) CGBBufWrapper; } else if( ifun == AST__GEBUF ) { wrapper = (AstGrfWrap) CGEBufWrapper; } else if( ifun == AST__GFLUSH ) { wrapper = (AstGrfWrap) CGFlushWrapper; } else if( ifun == AST__GLINE ) { wrapper = (AstGrfWrap) CGLineWrapper; } else if( ifun == AST__GMARK ) { wrapper = (AstGrfWrap) CGMarkWrapper; } else if( ifun == AST__GTEXT ) { wrapper = (AstGrfWrap) CGTextWrapper; } else if( ifun == AST__GCAP ) { wrapper = (AstGrfWrap) CGCapWrapper; } else if( ifun == AST__GTXEXT ) { wrapper = (AstGrfWrap) CGTxExtWrapper; } else if( ifun == AST__GSCALES ) { wrapper = (AstGrfWrap) CGScalesWrapper; } else if( ifun == AST__GQCH ) { wrapper = (AstGrfWrap) CGQchWrapper; } else if( astOK ) { astError( AST__INTER, "%s(%s): AST internal programming error - " "Grf function id %d not yet supported.", status, method, class, ifun ); } astGrfWrapper( this, name, wrapper ); } } int astGrfFunID_( const char *name, const char *method, const char *class, int *status ) { /* *+ * Name: * astGrfFunID * Purpose: * Return the integer identifier for a given GRF routine. * Type: * Hidden public function. * Synopsis: * #include "plot.h" * int astGrfFunID( const char *name, const char *method, * const char *class ) * Class Membership: * Plot member function. * Description: * This function returns an integer identifying the named grf function. * An error is reported if the named function is unknown. This function * is used by non-class modules within AST (e.g. fplot.c) which is why * it is public. It is not intended to be used by the public. * Parameters: * name * The grf function name. Any unambiguous abbreviation will do. * Case is ignored. The full list of grf function names is: * "Attr BBuf EBuf Scales Flush Line Mark Qch Text TxExt". See * grf_pgplot.c for details of these functions. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. *- */ /* Note that the list of identifiers here must be in the same order as the sorted values of the constants AST__GATTR, AST__GFLUSH, etc */ return FullForm( "Attr Flush Line Mark Text TxExt Scales Qch Cap BBuf " "EBuf", name, "Grf function name (programming error)", method, class, status ); } static char *GrfItem( int item, const char *text, int *axis, int *status ){ /* * Name: * GrfItem * Purpose: * Return the textual name corresponding to a specified graphical item * index. * Type: * Private function. * Synopsis: * #include "plot.h" * char *GrfItem( int item, const char *text, int *axis, int *status ) * Class Membership: * Plot member function. * Description: * This function returns a textual description of the graphical item * with the supplied index. * Parameters: * item * The index of the graphical item. * text * A pointer to a string which will be appended to the textual * description of the graphical item. May be NULL. * axis * Pointer to a place in which to return the index (0,1, or 2) of * the axis to which the attribute refers, If the attribute does * not refer to a specific axis, -1 is returned. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated string holding the textual * description of the graphical item, followed by any supplied "text". * Notes: * - An error is reported and a NULL pointer returned if the * index does not correspond to any graphical item. * - The returned pointer should be freed using astFree when it is no * longer needed. * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ char *desc; /* Pointer to the item description */ char *ret; /* Pointer to the returned string */ int dlen; /* Length of the item description */ if( axis ) *axis = -1; if( item == AST__BORDER_ID ) { desc = "Border"; } else if ( item == AST__GRIDLINE_ID ) { desc = "Gridline"; } else if ( item == AST__GRIDLINE1_ID ) { desc = "Axis 1 gridline"; if( axis ) *axis = 0; } else if ( item == AST__GRIDLINE2_ID ) { desc = "Axis 2 gridline"; if( axis ) *axis = 1; } else if ( item == AST__GRIDLINE3_ID ) { desc = "Axis 3 gridline"; if( axis ) *axis = 2; } else if ( item == AST__CURVE_ID ) { desc = "Curve"; } else if ( item == AST__NUMLABS_ID ) { desc = "Numerical labels"; } else if ( item == AST__TEXTLABS_ID ) { desc = "Textual labels"; } else if ( item == AST__TITLE_ID ) { desc = "Title"; } else if ( item == AST__MARKS_ID ) { desc = "Markers"; } else if ( item == AST__TEXT_ID ) { desc = "Text string"; } else if ( item == AST__TICKS_ID ) { desc = "Major and minor ticks"; } else if ( item == AST__AXIS1_ID ) { desc = "Axis 1"; if( axis ) *axis = 0; } else if ( item == AST__AXIS2_ID ) { desc = "Axis 2"; if( axis ) *axis = 1; } else if ( item == AST__AXIS3_ID ) { desc = "Axis 3"; if( axis ) *axis = 2; } else if ( item == AST__NUMLAB1_ID ) { desc = "Axis 1 numerical labels"; if( axis ) *axis = 0; } else if ( item == AST__NUMLAB2_ID ) { desc = "Axis 2 numerical labels"; if( axis ) *axis = 1; } else if ( item == AST__NUMLAB3_ID ) { desc = "Axis 3 numerical labels"; if( axis ) *axis = 2; } else if ( item == AST__TEXTLAB1_ID ) { desc = "Axis 1 textual label"; if( axis ) *axis = 0; } else if ( item == AST__TEXTLAB2_ID ) { desc = "Axis 2 textual label"; if( axis ) *axis = 1; } else if ( item == AST__TEXTLAB3_ID ) { desc = "Axis 3 textual label"; if( axis ) *axis = 2; } else if ( item == AST__TICKS1_ID ) { desc = "Axis 1 tick marks"; if( axis ) *axis = 0; } else if ( item == AST__TICKS2_ID ) { desc = "Axis 2 tick marks"; if( axis ) *axis = 1; } else if ( item == AST__TICKS3_ID ) { desc = "Axis 3 tick marks"; if( axis ) *axis = 2; } else { desc = NULL; if( astOK ){ astError( AST__INTER, "GrfItem: AST internal programming error - " "Invalid graphical item index %d supplied to GrfItem.", status, item ); } } if( desc ) { dlen = strlen( desc ); if( text ) { ret = astStore( NULL, desc, dlen + strlen( text ) + 1 ); if( ret ) strcpy( ret + dlen, text ); } else { ret = astStore( NULL, desc, dlen + 1 ); } } else { ret = NULL; } /* Return the answer. */ return ret; } static void GrfWrapper( AstPlot *this, const char *name, AstGrfWrap wrapper, int *status ) { /* *+ * Name: * astGrfWrapper * Purpose: * Register a wrapper function for a F77 or C Grf function. * Type: * Protected function. * Synopsis: * #include "plot.h" * void astGrfWrapper( AstPlot *this, const char *name, AstGrfWrap wrapper) * Description: * This function stores a pointer to the supplied wrapper function * within the plot, associating it with the grf function indicated by * the "name" parameter. The supplied wrapper function should call the * named grf function, using an interface appropriate to the language * in which the grf function is written. * Parameters: * this * The plot. * name * A name indicating the graphics function which is called by the * supplied wrapper function. See astGrfSet for details. * wrapper * A pointer to the wrapper function. This will be cast to a * specific type for the named grf function before being store * in the Plot. *- */ /* Local Variables: */ const char *class; /* Object class */ const char *method; /* Current method */ int ifun; /* Index into grf function list */ /* Check the global error status. */ if ( !astOK ) return; /* Store the current method and class for inclusion in error messages generated by lower level functions. */ method = "astGrfWrapper"; class = astClass( this ); /* Identify the supplied function name and get its integer index into the list of grf functions. */ ifun = astGrfFunID( name, method, class ); /* Cast the wrapper to an interface appropriate for the wrapped grf function, and store it in the appropriate component of the Plot. */ if( ifun == AST__GATTR ) { this->GAttr = (AstGAttrWrap) wrapper; } else if( ifun == AST__GBBUF ) { this->GBBuf = (AstGBBufWrap) wrapper; } else if( ifun == AST__GEBUF ) { this->GEBuf = (AstGEBufWrap) wrapper; } else if( ifun == AST__GFLUSH ) { this->GFlush = (AstGFlushWrap) wrapper; } else if( ifun == AST__GLINE ) { this->GLine = (AstGLineWrap) wrapper; } else if( ifun == AST__GMARK ) { this->GMark = (AstGMarkWrap) wrapper; } else if( ifun == AST__GTEXT ) { this->GText = (AstGTextWrap) wrapper; } else if( ifun == AST__GCAP ) { this->GCap = (AstGCapWrap) wrapper; } else if( ifun == AST__GTXEXT ) { this->GTxExt = (AstGTxExtWrap) wrapper; } else if( ifun == AST__GSCALES ) { this->GScales = (AstGScalesWrap) wrapper; } else if( ifun == AST__GQCH ) { this->GQch = (AstGQchWrap) wrapper; } else if( astOK ) { astError( AST__INTER, "%s(%s): AST internal programming error - " "Grf function id %d not yet supported.", status, method, class, ifun ); } } static void Grid( AstPlot *this_nd, int *status ){ /* *++ * Name: c astGrid f AST_GRID * Purpose: * Draw a set of labelled coordinate axes. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astGrid( AstPlot *this ) f CALL AST_GRID( THIS, STATUS ) * Class Membership: * Plot method. * Description: c This function draws a complete annotated set of f This routine draws a complete annotated set of * coordinate axes for a Plot with (optionally) a coordinate grid * superimposed. Details of the axes and grid can be controlled by * setting values for the various attributes defined by the Plot * class (q.v.). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - If the supplied Plot is a Plot3D, the axes will be annotated * using three 2-dimensional Plots, one for each 2D plane in the 3D * current coordinate system. The plots will be "pasted" onto 3 faces * of the cuboid graphics volume specified when the Plot3D was * constructed. The faces to be used can be controlled by the "RootCorner" * attribute. * - An error results if either the current Frame or the base Frame * of the Plot is not 2-dimensional or (for a Plot3D) 3-dimensional. * - An error also results if the transformation between the base * and current Frames of the Plot is not defined in either * direction (i.e. the Plot's TranForward or TranInverse attribute * is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPlot *this; /* Plot with 2d current Frame */ AstPlotCurveData **cdata;/* Pointer to info. about breaks in curves */ TickInfo **grid; /* Pointer to info. about tick marks */ const char *class; /* Object class */ const char *method; /* Current method */ double cen[ 2 ]; /* Position of first tick mark */ double gap[ 2 ]; /* Gap between tick marks */ double labelat[ 2 ]; /* Axis values at which tick marks are put */ int axis; /* Physical axis index */ int border; /* Draw a border? */ int clip; /* Original Clip attribute value */ int dounits[2]; /* Include Units in each axis label? */ int drawgrid; /* Is a grid of lines to be drawn? */ int clredge; /* Clear the Edge attributes before returning? */ int edgeticks; /* Draw labels round edges of plotting area? */ int escs; /* Original astEscapes value */ int ink; /* Draw the grid with visible ink? */ int inval; /* Were areas of invalid coordinates found? */ int labelling; /* Value of Labelling attribute */ int loglabelset[2]; /* Were the LogLabel attributes set initially? */ int logticksset[2]; /* Were the LogTicks attributes set initially? */ int naxes; /* No. of axes in the base or current Frame */ int oldedge0; /* Default value for Edge(1) */ int oldedge1; /* Default value for Edge(2) */ int useint; /* Do interior labels give us an advantage? */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_nd); /* Store the current method and class for inclusion in error messages generated by lower level functions. */ method = "astGrid"; class = astClass( this_nd ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this_nd ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Ensure AST functions included graphical escape sequences in any returned text strings. */ escs = astEscapes( 1 ); /* Note if attributes which have complex dynamic defaults are set initially. */ logticksset[0] = astTestLogTicks( this_nd, 0 ); logticksset[1] = astTestLogTicks( this_nd, 1 ); loglabelset[0] = astTestLogLabel( this_nd, 0 ); loglabelset[1] = astTestLogLabel( this_nd, 1 ); /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Get a Plot with a 2D (or 1D) current Frame. */ this = (AstPlot *) Fset2D( (AstFrameSet *) this_nd, AST__CURRENT, status ); /* Check the current Frame of the Plot is 2-D. */ naxes = astGetNout( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Ensure that all lines are clipped at the plot boundary.*/ if( astTestClip( this ) ) { clip = astGetClip( this ); astSetClip( this, 1 ); } else { clip = -1; } /* If the protected attribute "Ink" is set to zero, then the plot is drawn in "invisble ink" (i.e. all the calculations needed to produce the grid are performed, but nothing is actually drawn). */ ink = astGetInk( this ); /* Initialise the bounds of the box containing all plotted lines and numerical labels. */ Box_lbnd[ 0 ] = FLT_MAX; Box_lbnd[ 1 ] = FLT_MAX; Box_ubnd[ 0 ] = FLT_MIN; Box_ubnd[ 1 ] = FLT_MIN; /* Obtain the requested centre attribute values for both physical axes. */ for( axis = 0; axis < 2; axis++ ){ cen[ axis ] = astGetCentre( this, axis ); } /* Determine where to put the major axis values. */ grid = GridLines( this, cen, gap, &inval, method, class, status ); /* If the user has set an explicit value for Grid, use it. */ if( astTestGrid( this ) ){ drawgrid = astGetGrid( this ); /* If not, the default for Grid is based on whether or not there are any invalid regions. */ } else if( inval ){ drawgrid = 1; } else { drawgrid = 0; } /* Draw the curves marking the major tick values on each axis. Information is returned describing the positions of the breaks in these curves. */ cdata = DrawGrid( this, grid, ( ink && drawgrid ), method, class, status ); /* See if labels and tick marks will be drawn round the edges of the plotting area, rather than within it (no labels are actually drawn yet). Interior labels can always be produced, in which case edgeticks is set explicitly to zero to indicate that ticks will be internal. Exterior labelling may or may not be possible. If it is requested, check to see if it is possible. */ clredge = 0; labelling = astGetLabelling( this ); if( labelling ){ edgeticks = 0; } else { edgeticks = EdgeLabels( this, 0, grid, cdata, 0, method, class, status ); /* If the external labelling was requested, but could not be produced... */ if( !edgeticks ) { /* and if the Edge attributes have not been set... */ if( !astTestEdge( this, 0 ) && !astTestEdge( this, 1 ) ) { /* Try flipping the default Edge values, to see if this allows us to honour the requested Labelling scheme. */ oldedge0 = astGetEdge( this, 0 ); oldedge1 = astGetEdge( this, 1 ); astSetEdge( this, 0, oldedge1 ); astSetEdge( this, 1, oldedge0 ); /* See if exterior labels could be drawn with these new edges. */ edgeticks = EdgeLabels( this, 0, grid, cdata, 0, method, class, status ); /* If this would allow us to use the requested labelling scheme, retain the new Edge values, setting a flag to indicate that they will need to be cleared before returning. Otherwise, clear them. */ if( edgeticks ) { clredge = 1; } else { astClearEdge( this, 0 ); astClearEdge( this, 1 ); } } } } /* If edge ticks can still not be produced, but the ForceExterior attribute has a non-zero value, attempt to create exterior labels even though it looks like there may be insufficient of them to justify their use. */ if( !edgeticks && astGetForceExterior( this ) ) { edgeticks = EdgeLabels( this, 0, grid, cdata, 1, method, class, status ); } /* We may also need to swap edge values when using interior labelling in order to ensure that the text labels are placed on appropriate edges of the plotting box. */ if( !edgeticks && !astTestEdge( this, 0 ) && !astTestEdge( this, 1 ) ) { if( swapEdges( this, grid, cdata, status ) ) { oldedge0 = astGetEdge( this, 0 ); oldedge1 = astGetEdge( this, 1 ); astSetEdge( this, 0, oldedge1 ); astSetEdge( this, 1, oldedge0 ); clredge = 1; } } /* If edge ticks are being used, store bad values for the labelat values to indicate that labels are not being drawn within the interior of the plotting area. */ if( edgeticks ){ labelat[ 0 ] = AST__BAD; labelat[ 1 ] = AST__BAD; /* Otherwise, see where interior labels and tick marks should go (the axis values are put in "labelat"). */ } else { useint = Labelat( this, grid, cdata, labelat, method, class, status ); /* If interior labelling does not allow us to draw any more ticks, revert to edge labelling if that is what the user requested. */ if( !useint && !labelling ) { labelat[ 0 ] = AST__BAD; labelat[ 1 ] = AST__BAD; edgeticks = EdgeLabels( this, 0, grid, cdata, 1, method, class, status ); } } /* See if a border is required. By default, a border is drawn only when using exterior labelling. */ if( astTestBorder( this ) ) { border = astGetBorder( this ); } else { border = edgeticks; } /* See if the Units string is to be inluded in the label. */ dounits[ 0 ] = astGetLabelUnits( this, 0 ); dounits[ 1 ] = astGetLabelUnits( this, 1 ); /* The rest is not done if no output is required. */ if( ink ) { /* Draw tick marks (major and minor). */ DrawTicks( this, grid, drawgrid, labelat, gap, method, class, status ); /* If required, ensure that curves through the tick marks have been drawn */ DrawAxis( this, grid, labelat, gap, method, class, status ); /* If required, draw a curve around the edge of the area containing valid physical coordinates. */ if( border ) (void) astBorder( this ); /* Draw the numerical labels at the major tick values. */ Labels( this, grid, cdata, gap, labelat, method, class, status ); /* Draw the textual labels for each axis and a title. */ TextLabels( this, edgeticks, dounits, method, class, status ); } /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); /* Store the actual values used for all attributes which have dynamic defaults. Check the global status to ensure the pointer "grid" can be used without the possibility of a segmentation violation. */ for( axis = 0; axis < 2 && astOK ; axis++ ) { SetUsedLogTicks( this_nd, axis, astGetLogTicks( this, axis ), status ); SetUsedLogLabel( this_nd, axis, astGetLogLabel( this, axis ), status ); if( astGetLogTicks( this, axis ) ) { SetUsedLogGap( this_nd, axis, gap[ axis ], status ); } else { SetUsedGap( this_nd, axis, gap[ axis ], status ); } SetUsedCentre( this_nd, axis, cen[ axis ], status ); SetUsedEdge( this_nd, axis, astGetEdge( this, axis ), status ); SetUsedLabelAt( this_nd, axis, labelat[ axis ], status ); SetUsedLabelUnits( this_nd, axis, dounits[ axis ], status ); /* If explicit minor tick values were supplied using astSetTickValues, then set MinTick to the average number of minor tick divisions per major tick division. */ if( grid[ axis ]->minticks ) { SetUsedMinTick( this_nd, axis, ( grid[ axis ]->nminor + grid[ axis ]->nmajor )/ ( grid[ axis ]->nmajor - 1 ), status ); } else { SetUsedMinTick( this_nd, axis, grid[ axis ]->nminor, status ); } if( astTestTextLab( this, axis ) ) { SetUsedTextLab( this_nd, axis, astGetTextLab( this, axis ), status ); } else { SetUsedTextLab( this_nd, axis, edgeticks, status ); } if( astTestMajTickLen( this, axis ) ) { SetUsedMajTickLen( this_nd, axis, astGetMajTickLen( this, axis ), status ); } else { SetUsedMajTickLen( this_nd, axis, drawgrid ? 0.0 : astGetMajTickLen( this, axis ), status ); } } SetUsedGrid( this_nd, drawgrid, status ); SetUsedLabelling( this_nd, edgeticks ? 0 : 1, status ); SetUsedBorder( this_nd, border, status ); /* Free the memory used to hold information about the curves. */ cdata = CleanCdata( cdata, status ); /* Free the memory used to hold information about the tick marks. */ grid = CleanGrid( grid, status ); /* If required clear attributes. */ if( clredge ) { astClearEdge( this, 0 ); astClearEdge( this, 1 ); } if( !logticksset[ 0 ] ) astClearLogTicks( this, 0 ); if( !logticksset[ 1 ] ) astClearLogTicks( this, 1 ); if( !loglabelset[ 0 ] ) astClearLogLabel( this, 0 ); if( !loglabelset[ 1 ] ) astClearLogLabel( this, 1 ); /* Restore the original value of the Clip attribute. */ if( clip != -1 ) astSetClip( this, clip ); /* Free the 2D Plot. */ this = astAnnul( this ); /* Restore the original value of the flag which says whether graphical escape sequences should be incldued in any returned text strings. */ astEscapes( escs ); /* Copy the total bounding box to the box which is returned by astBoundingBox. */ if( !Boxp_freeze ){ Boxp_lbnd[ 0 ] = Box_lbnd[ 0 ]; Boxp_lbnd[ 1 ] = Box_lbnd[ 1 ]; Boxp_ubnd[ 0 ] = Box_ubnd[ 0 ]; Boxp_ubnd[ 1 ] = Box_ubnd[ 1 ]; } /* Return. */ return; } static void GridLine( AstPlot *this, int axis, const double start[], double length, int *status ){ /* *++ * Name: c astGridLine f AST_GRIDLINE * Purpose: * Draw a grid line (or axis) for a Plot. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astGridLine( AstPlot *this, int axis, const double start[], c double length ) f CALL AST_GRIDLINE( THIS, AXIS, START, LENGTH, STATUS ) * Class Membership: * Plot method. * Description: c This function draws a curve in the physical coordinate system of f This routine draws a curve in the physical coordinate system of * a Plot by varying only one of the coordinates along the length * of the curve. It is intended for drawing coordinate axes, * coordinate grids, and tick marks on axes (but note that these c are also available via the more comprehensive astGrid function). f are also available via the more comprehensive AST_GRID routine). * * The curve is transformed into graphical coordinate space for * plotting, so that a straight line in physical coordinates may * result in a curved line being drawn if the Mapping involved is * non-linear. Any discontinuities in the Mapping between physical * and graphical coordinates are catered for, as is any c clipping established using astClip. f clipping established using AST_CLIP. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c axis f AXIS = INTEGER (Given) * The index of the Plot axis whose physical coordinate value is * to be varied along the length of the curve (all other * coordinates will remain fixed). This value should lie in the * range from 1 to the number of Plot axes (Naxes attribute). c start f START( * ) = DOUBLE PRECISION (Given) * An array, with one element for each axis of the Plot, giving * the physical coordinates of the start of the curve. c length f LENGTH = DOUBLE PRECISION (Given) * The length of curve to be drawn, given as an increment along * the selected physical axis. This may be positive or negative. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - No curve is drawn if the "start" array contains any c coordinates with the value AST__BAD, nor if "length" has this value. f - No curve is drawn if the START array contains any f coordinates with the value AST__BAD, nor if LENGTH has this value. * - An error results if the base Frame of the Plot is not 2-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ const char *class; /* Object class */ const char *method; /* Current method */ int naxes; /* No. of axes in the base Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astGridLine"; class = astGetClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Initialise the bounding box for primatives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Validate the axis index, converting the axis index to be zero-based. */ (void) astValidateAxis( this, axis - 1, 1, method ); /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Draw the curve. The break information is stored in an external structure where it can be accessed by public methods which return information about the most recently drawn curve. */ AxPlot( this, axis - 1, start, length, 1, &Curve_data, method, class, status ); /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); } static TickInfo **GridLines( AstPlot *this, double *cen, double *gap, int *inval, const char *method, const char *class, int *status ){ /* * Name: * GridLines * Purpose: * Obtain information desribing the major tick values within the plotting * area. * Type: * Private function. * Synopsis: * #include "plot.h" * TickInfo **GridLines( AstPlot *this, double *cen, double *gap, * int *inval, const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * A pointer is returned which points to an array of two pointers. Each * of these pointers points to a TickInfo structure which holds * information about the ticks on a single axis. These structures, * together with the array holding the two pointers, should be released * when no longer needed using CleanGrid. * Parameters: * this * The Plot. * cen * A pointer to an array holding axis values at which to put a single * central tick. Other ticks are placed evenly on either side of this * tick. If AST__BAD is provided, a value will be used which would put a * tick at an axis value of zero. * gap * A pointer to an array holding the gaps between ticks required on * each axis. If this is AST__BAD a suitable default value will be used * and returned in place of the AST__BAD value. * inval * A pointer to a location at which to return a flag indicating if * any invalid physical coordinates were encountered while deciding on * the tick values. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to an array of two TickInfo pointers. * Notes: * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned. */ /* Local Variables: */ AstFrame *fr; /* Pointer to current Frame */ GetTicksStatics *statics = NULL; /* Pointer to static data for GetTicks */ TickInfo **info; /* Returned array of two TickInfo pointers */ double *lengths; /* Pointer to lengths of each curve section */ double *starts; /* Pointer to start of each curve section */ double *ticks; /* Pointer to tick mark values */ double bot; /* Lowest axis value to display */ double end; /* Axis value at end of curve section */ double tmp; /* Temp storage */ double top; /* Highest axis value to display */ int i; /* Tick mark index */ int j; /* Axis index */ int k; /* Section index */ int logticks[ 2 ]; /* Uses logarithmicaly spaced tick marks? */ int nticks; /* Number of tick marks */ /* Check the global status. */ if( !astOK ) return NULL; /* Get memory to hold two TickInfo pointers. */ info = (TickInfo **) astMalloc( 2*sizeof( TickInfo *) ); /* If succesfull... */ if( astOK ){ /* Initialise the two pointers. */ info[ 0 ] = NULL; info[ 1 ] = NULL; /* Obtain the tick mark values, and the corresponding formatted labels for each axis. */ for( j = 0; j < 2; j++ ){ info[ j ] = TickMarks( this, j, cen + j, gap + j, inval, &statics, method, class, status ); logticks[ j ] = astGetLogTicks( this, j ); } /* Release the resources allocated in the first call to TickMarks. */ for( j = 0; j < 2; j++ ){ (void) TickMarks( NULL, j, NULL, gap, NULL, &statics, method, class, status ); } /* Each major tick value for axis "j" may be marked with a curve parallel to axis "1-j" drawn across the entire plotting area. We need to decide where to start drawing this curve and how long it should be. We can simply use the minimum value on axis "1-j" together with the tick value on axis "j" to define the starting position. The length could be taken as the difference between the maximum and minimum values on axis "1-j". However, this may not be right in some situations. For instance if the plotting area covers a small range of Right Ascension from 23:59:59 to 00:00:01. Using the difference between the maximum and minimum values to give the length of the curve would result in the curve starting at 00:00:00 (the minimum axis value) and extending for a length of 23:59:59 (the axis range). To get round this sort of problem, the curve is split up into sections with lengths and starting positions determined by the tick mark values on axis "1-j". The first section starts at the minimum axis value and extends upto the first missing tick mark (in the RA example, this would be at 00:00:01). Subsequent sections starts at the next tick mark (23:59:59 in the RA example) and extends upto the next missing tick mark, or the last tick mark if none are missing. */ /* Get the current frame. */ fr = astGetFrame( this, AST__CURRENT ); /* If either axis has log tick spacing, use the simple approach which assumes that each curve has only one section. */ if( logticks[ 0 ] || logticks[ 1 ] ) { /* Find the start and length of the curve for each tick mark on axis "j". */ for( j = 0; j < 2 && astOK; j++ ){ /* Find the axis range to display on the other axis. */ bot = astGetBottom( fr, 1 - j ); top = astGetTop( fr, 1 - j ); if( bot > top ) { tmp = top; top = bot; bot = tmp; } /* Get a pointer to the major tick mark values on the other axis ("1-j"), together with the number of them. */ ticks = info[ 1 - j ]->ticks; nticks = info[ 1 - j ]->nmajor; /* Reserve memory to hold the starts and lengths of each section of the grid line marking the major ticks on the axis "j". There will only be one section. */ starts = (double *) astMalloc( sizeof(double) ); lengths = (double *) astMalloc( sizeof(double) ); info[ j ]->start = starts; info[ j ]->length = lengths; /* Check that the pointers can be used. */ if( astOK ) { /* The section starts one gap below the first tick, and ends one gap above the first tick. Limit both to the displayed range of the axis. */ if( logticks[ 1 - j ] ) { starts[ 0 ] = MIN( top, MAX( bot, ticks[ 0 ]/gap[ 1 - j ] ) ); end = MIN( top, MAX( bot, ticks[ nticks - 1 ]*gap[ 1 - j ] ) ); } else { starts[ 0 ] = MIN( top, MAX( bot, ticks[ 0 ] - gap[ 1 - j ] ) ); end = MIN( top, MAX( bot, ticks[ nticks - 1 ] + gap[ 1 - j ] ) ); } /* Store the length of the section. */ lengths[ 0 ] = end - starts[ 0 ]; /* Store the number of sections in the returned structure. */ info[ 0 ]->nsect = 1; } } /* If both axes have linear tick spacing, use the complete approach. */ } else { /* Find the start and length of each section of the curve for each tick mark on axis "j". */ for( j = 0; j < 2 && astOK; j++ ){ /* Find the axis range to display on the other axis. */ bot = astGetBottom( fr, 1 - j ); top = astGetTop( fr, 1 - j ); if( bot > top ) { tmp = top; top = bot; bot = tmp; } /* Get a pointer to the major tick mark values on the other axis ("1-j"), together with the number of them. */ ticks = info[ 1 - j ]->ticks; nticks = info[ 1 - j ]->nmajor; /* Reserve memory to hold the starts and lengths of each section of the grid line marking the major ticks on the axis "j". The allocated arrays are the largest that could possibly be needed (i.e. if every tick mark starts a new section). */ starts = (double *) astMalloc( sizeof(double)*(size_t) nticks ); lengths = (double *) astMalloc( sizeof(double)*(size_t) nticks ); info[ j ]->start = starts; info[ j ]->length = lengths; /* Check that the pointers can be used. */ if( astOK ) { /* Loop round each of the major tick marks on axis "1-j". */ k = 0; i = 0; while( i < nticks ){ /* Record the start of the next section of the grid lines. */ starts[ k ] = ticks[ i++ ]; /* Tick marks should be regularly spaced by the values in "gap". Check each tick mark until a missing tick mark is found. The section ends at the start of the gap. */ while( i < nticks && ( ticks[ i ] - ticks[ i - 1 ] ) < 1.5*gap[ 1 - j ] ) i++; /* Record the length of the section. */ lengths[ k ] = ticks[ i - 1 ] - starts[ k ]; /* The section is extended at start and end by one gap in order to "cover up the joins". Limit this to the displayed range of the axis. */ starts[ k ] -= gap[ 1 - j]; lengths[ k ] += 2.0*gap[ 1 - j ]; /* Limit the start and end to the displayed range of the axis. */ end = starts[ k ] + lengths[ k ]; starts[ k ] = MIN( top, MAX( bot, starts[ k ] ) ); lengths[ k ] = MIN( top, MAX( bot, end ) ) - starts[ k ]; /* Increment the number of sections. */ k++; } /* Store the number of sections in the returned structure. */ info[j]->nsect = k; } } } /* Annull the current frame. */ fr = astAnnul( fr ); } /* If an error has occurred, clean up the returned TickInfo structures. */ if( !astOK ) info = CleanGrid( info, status ); /* Return. */ return info; } void astGrfAttrs_( AstPlot *this, int id, int set, int prim, const char *method, const char *class, int *status ){ /* *+ * Name: * astGrfAttrs * Purpose: * Establish values for the graphics attributes for a given object. * Type: * Protected function. * Synopsis: * #include "plot.h" * void astGrfAttrs( AstPlot *this, int id, int set, int prim, const char *method, const char *class ) * Class Membership: * Plot member function. * Description: * This function should be called with "set=1" to establish the correct * graphics attributes prior to drawing specific graphical objects. Once * the object has been drawn, it should be called again with "set=0" to * re-establish the original graphics attributes. * * NOTE, each type of graphical object identified by "id" should be * drawn entirely by calls to just one of GMark, GText or GLine * as indicated by argument "prim". * Parameters: * this * A pointer to the Plot. * id * An integer specifying the graphical object to be drawn. * set * If non-zero then the attributes for the specified object are set * to the values indicated by the corresponding Plot attributes, * and the current values are saved in a static array. If zero, then * the values are set to the values stored in the static array. * prim * Indicates the sort of graphics primative used to draw the * object. This must be one of (defined in grf.h) : * * GRF__LINE * GRF__MARK * GRF__TEXT * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * Notes: * - This function should always be called in pairs with set=1 on the * first call and set=0 on the second call. * - If a pair of calls is nested within another pair of calls, the * inner pair has no effect. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double *attr; /* Pointer to the next attribute value */ double dval; /* Floating point attribute value */ int ival; /* Integer attribute value */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Set up a pointer to the next element in "grfattrs_attrs". */ attr = grfattrs_attrs; /* If we are setting new values, increment the nesting level, otherwise decrement it. */ if( set ){ grfattrs_nesting++; } else { grfattrs_nesting--; } /* If we are changing any line attributes, ensure all lines are flushed to the graphics system. */ if( prim == GRF__LINE ) Fpoly( this, method, class, status ); /* First deal with cases where we are establishing new values for the graphics attributes by setting them to the values of the corresponding Plot attributes. Only do this if we are at nesting level one. */ if( set && grfattrs_nesting == 1 ){ /* See if a value has been set in the Plot for the line style attribute for the specified object, If so, use the value. */ if( TestUseStyle( this, id, status ) ) { ival = GetUseStyle( this, id, status ); /* Save the current value, and establish the new value. */ GAttr( this, GRF__STYLE, (double) ival, attr++, prim, method, class, status ); /* If no style was specified, retain the current value. Indicate that no new value has been established by setting the old value bad. */ } else { *(attr++) = AST__BAD; } /* Do the same for the line width attribute. */ if( TestUseWidth( this, id, status ) ){ dval = GetUseWidth( this, id, status ); GAttr( this, GRF__WIDTH, dval, attr++, prim, method, class, status ); } else { *(attr++) = AST__BAD; } /* Do the same for the character size attribute. */ if( TestUseSize( this, id, status ) ) { dval = GetUseSize( this, id, status ); GAttr( this, GRF__SIZE, dval, attr++, prim, method, class, status ); } else { *(attr++) = AST__BAD; } /* Do the same for the character font attribute. */ if( TestUseFont( this, id, status ) ){ ival = GetUseFont( this, id, status ); GAttr( this, GRF__FONT, (double) ival, attr++, prim, method, class, status ); } else { *(attr++) = AST__BAD; } /* Do the same for the colour attribute. */ if( TestUseColour( this, id, status ) ) { ival = GetUseColour( this, id, status ); GAttr( this, GRF__COLOUR, (double) ival, attr++, prim, method, class, status ); } else { *(attr++) = AST__BAD; } } /* Now deal with cases where we are re-establishing old values saved on a previous call to this function. Only do this if we are at nesting level zero. */ if( !set && !grfattrs_nesting ){ GAttr( this, GRF__STYLE, *(attr++), NULL, prim, method, class, status ); GAttr( this, GRF__WIDTH, *(attr++), NULL, prim, method, class, status ); GAttr( this, GRF__SIZE, *(attr++), NULL, prim, method, class, status ); GAttr( this, GRF__FONT, *(attr++), NULL, prim, method, class, status ); GAttr( this, GRF__COLOUR, *(attr++), NULL, prim, method, class, status ); } /* Return. */ return; } static int GVec( AstPlot *this, AstMapping *mapping, double *phy, int axis, double delta, AstPointSet **pset1, AstPointSet **pset2, double *gx, double *gy, double *dx, double *dy, int *flag, const char *method, const char *class, int *status ){ /* * Name: * GVec * Purpose: * Returns a unit vector parallel to a physical axis at a given point. * Type: * Private function. * Synopsis: * #include "plot.h" * int GVec( AstPlot *this, AstMapping *mapping, double *phy, * int axis, double delta, AstPointSet **pset1, * AstPointSet **pset2, double *gx, double *gy, * double *dx, double *dy, int *flag, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function returns a unit vector (in the graphics coordinate * system) in the positive direction of the specified physical axis, * at the given physical position. It works by transforming the given * physical position, together with another very close position, and * returning the vector between them. It is possible for a * discontinuity to occur between these two close positions, * resulting in a very large meaningless vector prior to * normalisation. For this reason two vectors are found, one joining * the given position to a close position higher up the axis, and one * joining a close position lower down the axis to the given position. * If these two vectors differ in magnitude by a large factor, then * the shorter of the two vectors is normalised and returned. * Otherwise, the vector which is closest in direction to the vector * supplied in [dx,dy] is returned. The returned vector is reversed if * necessary so that it always points in the positive direction of the * axis. * * If neither of the two vectors can be found (i.e. if the graphics * coordinates are bad, or coincident), then the vector supplied in * [dx,dy] is returned unchanged, and a function value of zero is * returned. Otherwise, a function value of one is returned. * Parameters: * this * Pointer to the Plot. * mapping * Pointer to the Mapping from the base Frame of the Plot ot the * current Frame. * phy * Pointer to an array holding the coordinates in the current Frame * of the Plot at which the tangent vector is required. * axis * The index of the axis within the current Frame for which the * tangent vector is required. * delta * The increment in the axis value to use between positions defining * the vectors. * pset1 * A pointer to a place at which to store a pointer to a PointSet * holding current Frame coordinates. This PointSet pointer should * be supplied as NULL on the first call to this function, resulting * in a new PointSet being created and a pointer to it returned. * Subsequent calls to this function shopuld retain the pointer * returned by the first call. The PointSet pointer should be * annulled using astAnnul when no longer needed. * pset2 * A pointer to a place at which to store a pointer to a PointSet * holding base Frame coordinates. This PointSet is managed in the * same way as "pset1". * gx * A pointer to a double in which to return the graphics X * coordinate of the position supplied by "phy". * gy * A pointer to a double in which to return the graphics Y * coordinate of the position supplied by "phy". * dx * A pointer to a double in which to return the X component * of the unit tangent vector. This should be supplied holding a * "default" unit vector which is left unchanged if no new vector * can be found. * dy * A pointer to a double in which to return the Y component * of the unit tangent vector. This should be supplied holding a * "default" unit vector which is left unchanged if no new vector * can be found. * flag * A pointer to an int in which to return a flag indicating which * of the two vectors was returned. Zero is returned if the vector * was estimated by moving in a positive direction along the axis * from the position supplied by "phy". One is returned if the vector * was estimated by moving in a negative direction along the axis * from the position supplied by "phy" (in this case the returned * vector will have been negated so that it refers to the positive * direction). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * One is returned if the vector was found succesfully, Zero is returned * if the vector could not be estimated for any reason. No error is * reported if the failure was due to the nature of the mapping. * Notes: * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned. */ /* Local Variables: */ double dd1; /* Length of positive vector */ double dd2; /* Length of negative vector */ double dx1; /* X component of positive vector */ double dx2; /* X component of negative vector */ double dy1; /* Y component of positive vector */ double dy2; /* Y component of negative vector */ double **ptr1; /* Pointers to physical coordinate data */ double **ptr2; /* Pointers to graphics coordinate data */ int i; /* Axis index */ int nphy; /* No. of axes in current (physical) Frame */ int ret; /* Was a vector estimated succesfully? */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ dx1 = 0.0; dx2 = 0.0; dy1 = 0.0; dy2 = 0.0; /* Initialise the returned value to indicate that the vector can not be found. */ ret = 0; /* Get the number of physical coordinates from the mapping. */ nphy = astGetNout( mapping ); /* If no PointSets have been supplied, create some now. PointSet 1 contains physical coordinates, PointSet 2 contains graphics coordinates. */ if( !(*pset1) ) *pset1 = astPointSet( 3, nphy, "", status ); if( !(*pset2) ) *pset2 = astPointSet( 3, 2, "", status ); /* Get pointers to the PointSet data. */ ptr1 = astGetPoints( *pset1 ); ptr2 = astGetPoints( *pset2 ); /* Check the PointSets can be used. */ if( astOK ){ /* Store the physical coordinates of three close points on a curve parallel to the given axis, with the centre point at the given position. */ for( i = 0; i < nphy; i++ ){ ptr1[ i ][ 0 ] = phy[ i ]; ptr1[ i ][ 1 ] = phy[ i ]; ptr1[ i ][ 2 ] = phy[ i ]; } if( phy[ axis ] != AST__BAD ){ ptr1[ axis ][ 0 ] = phy[ axis ] - delta; ptr1[ axis ][ 2 ] = phy[ axis ] + delta; } /* Find the corresponding graphics coordinates. */ (void) Trans( this, NULL, mapping, *pset1, 0, *pset2, 0, method, class, status ); /* Check the central position is OK. */ *gx = ptr2[ 0 ][ 1 ]; *gy = ptr2[ 1 ][ 1 ]; if( astOK && *gx != AST__BAD && *gy != AST__BAD ){ /* Get the unit vector between the central position and the position at the higher physical axis value. Also get the length of the vector joining the two positions. */ if( ptr2[ 0 ][ 2 ] != AST__BAD && ptr2[ 1 ][ 2 ] != AST__BAD ){ dx1 = ptr2[ 0 ][ 2 ] - *gx; dy1 = ptr2[ 1 ][ 2 ] - *gy; dd1 = dx1*dx1 + dy1*dy1; if( dd1 > 0.0 ) { dd1 = sqrt( dd1 ); dx1 /= dd1; dy1 /= dd1; } else { dd1 = AST__BAD; } } else { dd1 = AST__BAD; } /* Do the same for the position with lower physical axis value, reversing the direction of the vector so that it refers to the positive direction. */ if( ptr2[ 0 ][ 0 ] != AST__BAD && ptr2[ 1 ][ 0 ] != AST__BAD ){ dx2 = *gx - ptr2[ 0 ][ 0 ]; dy2 = *gy - ptr2[ 1 ][ 0 ]; dd2 = dx2*dx2 + dy2*dy2; if( dd2 > 0.0 ) { dd2 = sqrt( dd2 ); dx2 /= dd2; dy2 /= dd2; } else { dd2 = AST__BAD; } } else { dd2 = AST__BAD; } /* Only overwrite the supplied vector if at least one of the two tangent vectors was defined. */ if( dd1 != AST__BAD || dd2 != AST__BAD ){ /* If the first vector was not defined, return the second. */ if( dd1 == AST__BAD ){ *dx = dx2; *dy = dy2; *flag = 1; ret = 1; /* If the second vector was not defined, return the first. */ } else if( dd2 == AST__BAD ){ *dx = dx1; *dy = dy1; *flag = 0; ret = 1; /* If the first vector is much longer than the second, return the second. */ } else if( dd1 > 100.0*dd2 ){ *dx = dx2; *dy = dy2; *flag = 1; ret = 1; /* If the second vector is much longer than the first, return the first. */ } else if( dd2 > 100.0*dd1 ){ *dx = dx1; *dy = dy1; *flag = 0; ret = 1; /* If both vectors are defined and of comparable length, return the vector which is most nearly parallel to the supplied vector. Note, we assume that the supplied vector [dx,dy] is a unit vector. */ } else if( *dx != AST__BAD && *dx != AST__BAD ){ if( ( dx1*(*dx) + dy1*(*dy) )/dd1 > ( dx2*(*dx) + dy2*(*dy) )/dd2 ){ *dx = dx1; *dy = dy1; *flag = 0; ret = 1; } else { *dx = dx2; *dy = dy2; *flag = 1; ret = 1; } /* If no vector was supplied, return the shorter of the two vectors. */ } else if( dd1 < dd2 ){ *dx = dx1; *dy = dy1; *flag = 0; ret = 1; } else { *dx = dx2; *dy = dy2; *flag = 1; ret = 1; } } } } /* Return the answer. */ return ret; } static int HasEscapes( const char *text, int *status ) { /* * Name: * HasEscapes * Purpose: * Check if a text string contains any escape sequences. * Type: * Private function. * Synopsis: * #include "plot.h" * int HasEscapes( const char *text, int *status ) * Class Membership: * Plot member function. * Description: * This function checks if a text string contains any escape sequences * (see attribute Escape). * Parameters: * text * The text to check. * status * Pointer to the inherited status variable. * Returned: * Non-zero if any escape sequences are found in the text. Zero * otherwise. */ /* Local Variables: */ int result; int type; int value; int nc; /* Initialise. */ result = 0; /* Check the global error status and the supplied pointer. */ if ( !astOK || ! text ) return result; /* Does the string begin with an escape sequence? */ if( astFindEscape( text, &type, &value, &nc ) ){ result = 1; /* If not, there must be an escape sequence later in the string if the number of characters skipped by the above call to astFindEscape is less than the length of the string. */ } else if( nc < strlen( text ) ) { result = 1; } /* Return the result. */ return result; } static int IdFind( int id, int nax, int *id1, int *id2, int *id3, int *status ) { /* * Name: * IdFind * Purpose: * Find the numerical identifiers to use for a given identifier. * Type: * Private function. * Synopsis: * #include "plot.h" * int IdFind( int id, int nax, int *id1, int *id2, int *id3, int *status ) * Class Membership: * Plot member function. * Description: * The supplied integer should be a numerical identifier for a * graphical element of a plot (AST__MARKS_ID, AST__CURVES_ID, etc), or a * "psuedo-identifier" which represents two other genuine identifiers. * If the supplied value is a genuine identifier then it is returned * in *id1, and *id2 is returned equal to -1. If the supplied value * is a pseudo-identifier then the two corresponding genuine * identifiers are returned in *id1 and *id2 * For instance, if "id" is AST__AXIS1_ID (a genuine id), then *id1 is * returned equal to AST__AXIS1_ID and *id2 is returned equal to -1. If * "id" is AST__AXES_ID (a pseudo-identifier), then *id1 is returned equal * to AST__AXIS1_ID and *id2 is returned equal to AST__AXIS2_ID. * Genuine identifiers all have values which are less than the value * of AST__NPID. Pseudo-identifiers have values which are greater than * or equal to the value of AST__NPID. * Parameters: * id * The supplied identifier (genuine or pseudo). * nax * The number of axes spanning graphics space (2 or 3). * id1 * Pointer to the int at which to return the first genuine * identifier corresponding to "id". * id2 * Pointer to the int at which to return the second genuine * identifier corresponding to "id" (or -1 if "id" is a genuine * identifier). * id3 * Pointer to the int at which to return the third genuine * identifier corresponding to "id" (or -1 if "id" has no third * genuine identifier). * status * Pointer to the inherited status variable. * Returned Value: * The number of genuine identifiers corresponding to the supplied * (possibly Pseudo-) identifier. This will be in the range 1 to 3. */ /* Local Variables: */ int ret; /* Initialise returned values. */ *id1 = id; *id2 = -1; *id3 = -1; ret = 0; /* Check the local error status. */ if ( !astOK ) return ret; /* Assume a genuine identifier was supplied. */ ret = 1; /* Check against all known pseudo-identifier. */ if( id == AST__AXES_ID ) { ret = nax; *id1 = AST__AXIS1_ID; *id2 = AST__AXIS2_ID; if( nax == 3 ) *id3 = AST__AXIS3_ID; } else if( id == AST__GRIDLINE_ID ) { ret = nax; *id1 = AST__GRIDLINE1_ID; *id2 = AST__GRIDLINE2_ID; if( nax == 3 ) *id3 = AST__GRIDLINE3_ID; } else if( id == AST__NUMLABS_ID ) { ret = nax; *id1 = AST__NUMLAB1_ID; *id2 = AST__NUMLAB2_ID; if( nax == 3 ) *id3 = AST__NUMLAB3_ID; } else if( id == AST__TEXTLABS_ID ) { ret = nax; *id1 = AST__TEXTLAB1_ID; *id2 = AST__TEXTLAB2_ID; if( nax == 3 ) *id3 = AST__TEXTLAB3_ID; } else if( id == AST__TICKS_ID ) { ret = nax; *id1 = AST__TICKS1_ID; *id2 = AST__TICKS2_ID; if( nax == 3 ) *id3 = AST__TICKS3_ID; } else if( id >= AST__NPID ) { astError( AST__INTER, "AST internal programming error - " "function IdFind in class Plot does not yet support " "pseudo-identifier value %d", status, id ); } /* Return the answer. */ return ret; } void astInitPlotVtab_( AstPlotVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitPlotVtab * Purpose: * Initialise a virtual function table for a Plot. * Type: * Protected function. * Synopsis: * #include "plot.h" * void astInitPlotVtab( AstPlotVtab *vtab, const char *name ) * Class Membership: * Plot vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Plot class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrameSetVtab *fset; /* Pointer to FrameSet component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitFrameSetVtab( (AstFrameSetVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAPlot) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_init variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstFrameSetVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->BBuf = BBuf; vtab->Border = Border; vtab->BoundingBox = BoundingBox; vtab->ClearGrid = ClearGrid; vtab->ClearTol = ClearTol; vtab->Clip = Clip; vtab->CopyPlotDefaults = CopyPlotDefaults; vtab->Curve = Curve; vtab->CvBrk = CvBrk; vtab->EBuf = EBuf; vtab->GenCurve = GenCurve; vtab->GetDrawnTicks = GetDrawnTicks; vtab->GetGrid = GetGrid; vtab->GetTol = GetTol; vtab->GrfPop = GrfPop; vtab->GrfPush = GrfPush; vtab->GrfSet = GrfSet; vtab->GrfWrapper = GrfWrapper; vtab->Grid = Grid; vtab->GridLine = GridLine; vtab->Mark = Mark; vtab->Mirror = Mirror; vtab->PolyCurve = PolyCurve; vtab->SetGrid = SetGrid; vtab->SetTickValues = SetTickValues; vtab->SetTol = SetTol; vtab->TestGrid = TestGrid; vtab->TestTol = TestTol; vtab->Text = Text; vtab->ClearTickAll = ClearTickAll; vtab->SetTickAll = SetTickAll; vtab->GetTickAll = GetTickAll; vtab->TestTickAll = TestTickAll; vtab->ClearForceExterior = ClearForceExterior; vtab->SetForceExterior = SetForceExterior; vtab->GetForceExterior = GetForceExterior; vtab->TestForceExterior = TestForceExterior; vtab->ClearInvisible = ClearInvisible; vtab->SetInvisible = SetInvisible; vtab->GetInvisible = GetInvisible; vtab->TestInvisible = TestInvisible; vtab->ClearBorder = ClearBorder; vtab->SetBorder = SetBorder; vtab->GetBorder = GetBorder; vtab->TestBorder = TestBorder; vtab->ClearInk = ClearInk; vtab->SetInk = SetInk; vtab->GetInk = GetInk; vtab->TestInk = TestInk; vtab->ClearClipOp = ClearClipOp; vtab->SetClipOp = SetClipOp; vtab->GetClipOp = GetClipOp; vtab->TestClipOp = TestClipOp; vtab->ClearClip = ClearClip; vtab->SetClip = SetClip; vtab->GetClip = GetClip; vtab->TestClip = TestClip; vtab->ClearGrf = ClearGrf; vtab->SetGrf = SetGrf; vtab->GetGrf = GetGrf; vtab->TestGrf = TestGrf; vtab->ClearDrawTitle = ClearDrawTitle; vtab->SetDrawTitle = SetDrawTitle; vtab->GetDrawTitle = GetDrawTitle; vtab->TestDrawTitle = TestDrawTitle; vtab->ClearLabelUp = ClearLabelUp; vtab->SetLabelUp = SetLabelUp; vtab->GetLabelUp = GetLabelUp; vtab->TestLabelUp = TestLabelUp; vtab->ClearLogPlot = ClearLogPlot; vtab->SetLogPlot = SetLogPlot; vtab->GetLogPlot = GetLogPlot; vtab->TestLogPlot = TestLogPlot; vtab->ClearLogTicks = ClearLogTicks; vtab->SetLogTicks = SetLogTicks; vtab->GetLogTicks = GetLogTicks; vtab->TestLogTicks = TestLogTicks; vtab->ClearLogLabel = ClearLogLabel; vtab->SetLogLabel = SetLogLabel; vtab->GetLogLabel = GetLogLabel; vtab->TestLogLabel = TestLogLabel; vtab->ClearDrawAxes = ClearDrawAxes; vtab->SetDrawAxes = SetDrawAxes; vtab->GetDrawAxes = GetDrawAxes; vtab->TestDrawAxes = TestDrawAxes; vtab->ClearAbbrev = ClearAbbrev; vtab->SetAbbrev = SetAbbrev; vtab->GetAbbrev = GetAbbrev; vtab->TestAbbrev = TestAbbrev; vtab->ClearEscape = ClearEscape; vtab->SetEscape = SetEscape; vtab->GetEscape = GetEscape; vtab->TestEscape = TestEscape; vtab->ClearLabelling = ClearLabelling; vtab->SetLabelling = SetLabelling; vtab->GetLabelling = GetLabelling; vtab->TestLabelling = TestLabelling; vtab->ClearMajTickLen = ClearMajTickLen; vtab->SetMajTickLen = SetMajTickLen; vtab->GetMajTickLen = GetMajTickLen; vtab->TestMajTickLen = TestMajTickLen; vtab->ClearLogGap = ClearLogGap; vtab->SetLogGap = SetLogGap; vtab->GetLogGap = GetLogGap; vtab->TestLogGap = TestLogGap; vtab->ClearTitleGap = ClearTitleGap; vtab->SetTitleGap = SetTitleGap; vtab->GetTitleGap = GetTitleGap; vtab->TestTitleGap = TestTitleGap; vtab->ClearMinTickLen = ClearMinTickLen; vtab->SetMinTickLen = SetMinTickLen; vtab->GetMinTickLen = GetMinTickLen; vtab->TestMinTickLen = TestMinTickLen; vtab->ClearNumLabGap = ClearNumLabGap; vtab->SetNumLabGap = SetNumLabGap; vtab->GetNumLabGap = GetNumLabGap; vtab->TestNumLabGap = TestNumLabGap; vtab->ClearTextLabGap = ClearTextLabGap; vtab->SetTextLabGap = SetTextLabGap; vtab->GetTextLabGap = GetTextLabGap; vtab->TestTextLabGap = TestTextLabGap; vtab->ClearLabelAt = ClearLabelAt; vtab->SetLabelAt = SetLabelAt; vtab->GetLabelAt = GetLabelAt; vtab->TestLabelAt = TestLabelAt; vtab->ClearCentre = ClearCentre; vtab->SetCentre = SetCentre; vtab->GetCentre = GetCentre; vtab->TestCentre = TestCentre; vtab->ClearGap = ClearGap; vtab->SetGap = SetGap; vtab->GetGap = GetGap; vtab->TestGap = TestGap; vtab->ClearEdge = ClearEdge; vtab->SetEdge = SetEdge; vtab->GetEdge = GetEdge; vtab->TestEdge = TestEdge; vtab->ClearNumLab = ClearNumLab; vtab->SetNumLab = SetNumLab; vtab->GetNumLab = GetNumLab; vtab->TestNumLab = TestNumLab; vtab->ClearMinTick = ClearMinTick; vtab->SetMinTick = SetMinTick; vtab->GetMinTick = GetMinTick; vtab->TestMinTick = TestMinTick; vtab->ClearTextLab = ClearTextLab; vtab->SetTextLab = SetTextLab; vtab->GetTextLab = GetTextLab; vtab->TestTextLab = TestTextLab; vtab->ClearLabelUnits = ClearLabelUnits; vtab->SetLabelUnits = SetLabelUnits; vtab->GetLabelUnits = GetLabelUnits; vtab->TestLabelUnits = TestLabelUnits; vtab->ClearStyle = ClearStyle; vtab->SetStyle = SetStyle; vtab->GetStyle = GetStyle; vtab->TestStyle = TestStyle; vtab->ClearFont = ClearFont; vtab->SetFont = SetFont; vtab->GetFont = GetFont; vtab->TestFont = TestFont; vtab->ClearColour = ClearColour; vtab->SetColour = SetColour; vtab->GetColour = GetColour; vtab->TestColour = TestColour; vtab->ClearWidth = ClearWidth; vtab->SetWidth = SetWidth; vtab->GetWidth = GetWidth; vtab->TestWidth = TestWidth; vtab->ClearSize = ClearSize; vtab->SetSize = SetSize; vtab->GetSize = GetSize; vtab->TestSize = TestSize; vtab->GetGrfContext = GetGrfContext; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; fset = (AstFrameSetVtab *) vtab; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_transform = mapping->Transform; mapping->Transform = Transform; parent_removeframe = fset->RemoveFrame; fset->RemoveFrame = RemoveFrame; /* Declare the destructor and copy constructor. */ astSetDelete( (AstObjectVtab *) vtab, Delete ); astSetCopy( (AstObjectVtab *) vtab, Copy ); /* Declare the class dump function. */ astSetDump( vtab, Dump, "Plot", "Provide facilities for 2D graphical output" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int Inside( int n, float *cx, float *cy, float x, float y, int *status ){ /* * Name: * Inside * Purpose: * See if a given point is inside a 2-d polygon. * Type: * Private function. * Synopsis: * #include "plot.h" * int Inside( int n, float *cx, float *cy, float x, float y, int *status ) * Class Membership: * Plot member function. * Description: * This function determines if the position given by x and y, is inside * or outside the polygon specified by the vertices given in arrays cx * and cy. * Parameters: * n * The number of vertices in the polygon. * cx * A pointer to an array holding the x coordinates at the "n" vertices. * cy * A pointer to an array holding the y coordinates at the "n" vertices. * x * The x coordinate of the test point. * y * The y coordinate of the test point. * status * Pointer to the inherited status variable. * Returned Value: * A boolean flag indicating if the test point is inside the polygon. * Notes: * - The algorithm used only works for convex polygons. * - The polygon is closed by joining the last vertex to the first * vertex. * - Zero is returned if an error has occurred. */ /* Local Variables: */ int i; /* Index of the current vertex */ int j; /* Index of the next vertex */ int ret; /* Is the test point inside the polygon? */ int sgn; /* Which side of the first edge is the test point? */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise the returned value to indicate that the point is inside the box. */ ret = 1; /* Get the sign of the angle between the vector joining vertex 1 to vertex 0, and the vector joining the test point to vertex zero. */ if( ( cx[ 1 ] - cx[ 0 ] )*( y - cy[ 0 ] ) > ( x - cx[ 0 ] )*( cy[ 1 ] - cy[ 0 ] ) ){ sgn = 1; } else { sgn = -1; } /* Check that the remaining test point is on the same side of the remaining sides. */ for( i = 1; i < n; i++ ){ /* Get the index of the next vertex, joining the last vertex up with vertex zero. */ j = i + 1; if( j >= n ) j -= n; /* Get the sign of the angle between the vector joining vertex j to vertex i, and the vector joining the test point to vertex i. If the sign is opposite to that found for vertex zero, then the test point is outside the polygon. Break out of the loop if this is the case. */ if( ( cx[ j ] - cx[ i ] )*( y - cy[ i ] ) > ( x - cx[ i ] )*( cy[ j ] - cy[ i ] ) ){ if( sgn == -1 ) { ret = 0; break; } } else { if( sgn == 1 ) { ret = 0; break; } } } /* Return the answer. */ return ret; } static void InterpEscape( AstPlot *this, int type, double value, float *x, float *y, float ux, float uy, float rx, float ry, const char *just, float *rise, double nsize, double nstyle, double nwidth, double ncol, double nfont, const char *method, const char *class, int *status ){ /* * Name: * InterpEscape * Purpose: * Prepare things for drawing the next part of a string which includes * graphics escape sequences. * Synopsis: * #include "plot.h" * void InterpEscape( AstPlot *this, int type, double value, float *x, * float *y, float ux, float uy, float rx, float ry, * const char *just, float *rise, double nsize, * double nstyle, double nwidth, double ncol, * double nfont, const char *method, const char *class, int *status ) * Description: * This function modifies the current graphics attributes, the supplied * reference position, in preparation for drawing another sub-string * from a string containing graphics escape sequences. The type and * value of an escape sequence preceding the substring is supplied. * Note, this function ignored escape sequences which represent an * escaped percent sign. Such escape sequences are drawn as normal * text by the claling function. * Parameters: * this * The plot. * type * The type of escape sequence. Each type is identified by a symbolic * constant defined in grf.h. * value * The value associated with the escape sequence. All usable values * will be positive. A value of -1 shold be supplied if the attribute * identified by "type" should be reset to its "normal" value (as * established using the astGAttr function, etc). * x * Pointer to a double holding the x coordinate at the concatenation * point. This will be modified on exit if the escape sequence * requires it. * y * Pointer to a double holding the y coordinate at the concatenation * point. This will be modified on exit if the escape sequence * requires it. * ux * The x component of the up-vector for the text, in graphics coords. * The length of this vector should be equal to the height of normal * text drawn with this up-vector. * uy * The y component of the up-vector for the text. See "ux". * rx * The x component of the right-vector for the text. The length of this * vector should be equal to the height of normal text drawn with the * supplied up-vector. * ry * The y component of the right-vector for the text. see "rx". * just * The justification being used for each substring. * rise * Pointer to a float holding the height of the current baseline * above the normal baseline, given as a percentage of the height of * normal text. May be negative for sub-scripts. May be modified on * exit if the escape sequence effects the height of the baseline. * nsize * The size of normal text. * nstyle * The style of normal text. * nwidth * The width of normal text. * ncol * The colour of normal text. * nfont * The font of normal text. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ float new_rise; float t1, t2; /* Check the global error status. */ if ( !astOK ) return; /* Type GRF__ESSUP: Move the concatenation point in the up direction, and update the current baseline height. If the value is -1, then reset the baseline to its normal height. */ if( type == GRF__ESSUP ) { if( value > 0 ) { *x += 0.01*ux*( value - *rise ); *y += 0.01*uy*( value - *rise ); *rise = value; } else { *x -= 0.01*ux*(*rise); *y -= 0.01*uy*(*rise); *rise = 0; } /* Type GRF__ESSUB: Move the concatenation point in the down direction, and update the current baseline height. If the value is -1, then reset the baseline to its normal height. */ } else if( type == GRF__ESSUB ) { if( value > 0 ) { *x -= 0.01*ux*( value + *rise ); *y -= 0.01*uy*( value + *rise ); *rise = -value; } else { *x -= 0.01*ux*(*rise); *y -= 0.01*uy*(*rise); *rise = 0; } /* Type GRF__ESGAP: Move the concatenation point to the right. */ } else if( type == GRF__ESGAP ) { *x += 0.01*rx*value; *y += 0.01*ry*value; /* Type GRF__ESBAC: Move the concatenation point to the left. */ } else if( type == GRF__ESBAC ) { *x -= 0.01*rx*value; *y -= 0.01*ry*value; /* Remember the current horizontal position. */ } else if( type == GRF__ESH ) { this->hmarkx = *x; this->hmarky = *y; /* Go to the previously stored horizontal position. */ } else if( type == GRF__ESG ) { if( this->hmarkx != FLT_MAX && this->hmarky != FLT_MAX ) { t1 = ( *x - this->hmarkx )*rx + ( *y - this->hmarky )*ry; t2 = rx*rx + ry*ry; *x -= rx*t1/t2; *y -= ry*t1/t2; } /* Type GRF__ESSIZ: Change the text size. */ } else if( type == GRF__ESSIZ ) { if( value < 0 ) value = 100.0; GAttr( this, GRF__SIZE, 0.01*value*nsize, NULL, GRF__TEXT, method, class, status ); /* Type GRF__ESWID: Change the text width. */ } else if( type == GRF__ESWID ) { if( value < 0 ) value = 100.0; GAttr( this, GRF__WIDTH, 0.01*value*nwidth, NULL, GRF__TEXT, method, class, status ); /* Type GRF__ESFON: Change the text font. */ } else if( type == GRF__ESFON ) { if( value < 0 ) value = nfont; GAttr( this, GRF__FONT, value, NULL, GRF__TEXT, method, class, status ); /* Type GRF__ESCOL: Change the text colour. */ } else if( type == GRF__ESCOL ) { if( value < 0 ) value = ncol; GAttr( this, GRF__COLOUR, value, NULL, GRF__TEXT, method, class, status ); /* Type GRF__ESSTY: Change the text style. */ } else if( type == GRF__ESSTY ) { if( value < 0 ) value = nstyle; GAttr( this, GRF__STYLE, value, NULL, GRF__TEXT, method, class, status ); /* Type GRF__ESPSH: Push current attributes onto a stack. */ } else if( type == GRF__ESPSH ) { PushGat( this, *rise, method, class, status ); /* Type GRF__ESSTY: Reset everything to normal. */ } else if( type == GRF__ESPOP ) { if( !PopGat( this, &new_rise, method, class, status ) ) { new_rise = 0.0; GAttr( this, GRF__SIZE, nsize, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__WIDTH, nwidth, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__COLOUR, ncol, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__FONT, nfont, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__STYLE, nstyle, NULL, GRF__TEXT, method, class, status ); } *x -= 0.01*ux*( *rise - new_rise ); *y -= 0.01*uy*( *rise - new_rise ); *rise = new_rise; } } static int IsASkyAxis( AstFrame *frm, int axis, int *status ) { /* * Name: * IsASkyAxis * Purpose: * Checks if a specified axis of the supplied Frame is a SkyAxis. * Type: * Private function. * Synopsis: * #include "plot.h" * int IsASkyAxis( AstFrame *frm, int axis, int *status ) * Class Membership: * Plot member function. * Description: * This function checks if if a specified axis of the supplied Frame is * a SkyAxis. * Parameters: * frm * The Frame. * axis * The zero-based axis index. * status * Pointer to the inherited status variable. * Returned Value: * A boolean flag indicating if the axis is a SkyAxis. */ /* Local Variables: */ int ret; AstAxis *ax; /* initialise */ ret = 0; /* Check the global status. */ if( !astOK ) return ret; /* Extract the required axis from the Frame and test if it is a SkyAxis. Then free the axis memory. */ ax = astGetAxis( frm, axis ); ret = astIsASkyAxis( ax ); ax = astAnnul( ax ); /* Return the answer. */ return ret; } static int IsASkyFrame( AstObject *obj, int *status ) { /* * Name: * IsASkyFrame * Purpose: * Checks if the supplied Object ca be treated as a SkyFrame. * Type: * Private function. * Synopsis: * #include "plot.h" * int IsASkyFrame( AstObject *obj, int *status ) * Class Membership: * Plot member function. * Description: * This function checks if the supplied Object is a SkyFrame or a * FrameSet which has a SkyFrame as its current Frame. * Parameters: * obj * The object. * status * Pointer to the inherited status variable. * Returned Value: * A boolean flag indicating if the Object can be treated as SkyFrame. */ /* Local Variables: */ int ret; AstFrame *frm; /* initialise */ ret = 0; /* Check the global status. */ if( !astOK ) return ret; /* If the Object is a SkyFrame, return 1. */ if( astIsASkyFrame( obj ) ) { ret = 1; /* If the Object is a FrameSet, check its current Frame recursively, using this method. */ } else if( astIsAFrameSet( obj ) ) { frm = astGetFrame( (AstFrameSet *) obj, AST__CURRENT ); ret = IsASkyFrame( (AstObject *) frm, status ); frm = astAnnul( frm ); } /* Return the answer. */ return ret; } static const char *JustMB( AstPlot *this, int esc, const char *text, float *x, float *y, float upx, float upy, const char *just, float uxu, float uyu, float rxu, float ryu, float *x0, float *y0, const char *method, const char *class, int *status ){ /* * Name: * JustMB * Purpose: * Modifies a "M" vertical reference point to be a "B" reference point, * if necessary. * Synopsis: * #include "plot.h" * const char *JustMB( AstPlot *this, int esc, const char *text, float *x, * float *y, float upx, float upy, const char *just, * float uxu, float uyu, float rxu, float ryu, * float *x0, float *y0, const char *method, * const char *class, int *status ) * Description: * This function is used to modify the reference point and justification * of a string by converting the vertical "M" justification option (which * indicates that the reference point refers to the bottom of the * bounding box) into a corresponding "B" option (which indicates that * the reference point refers to the text baseline). The reference * point is modified accordingly. * * This is only done if the grf module does not support "M" * justification. Otherwise, the supplied justification string and * reference point coordinates are returned unchanged. * Parameters: * this * The plot. * esc * Should escape sequences be interpreted? They will be printed * literally otherwise. * text * Pointer to a null-terminated character string to be displayed. * x * Pointer to a double holding the x coordinate at the reference * point. This is modified on exit if the supplied "just" string * indicates that the supplied value refers to the bottom of the * bounding box, and the grf module does not support such * justification. In this case, the returned value is a point on * the baseline of the text which would result in the bottom of * the bounding box being at the supplied position. * y * Pointer to a double holding the y coordinate at the reference * point. This is modified on exit if the supplied "just" string * indicates that the supplied value refers to the bottom of the * bounding box, and the grf module does not support such * justification. In this case, the returned value is a point on * the baseline of the text which would result in the bottom of * the bounding box being at the supplied position. * upx * The x component of the up-vector for the text. Positive values * always refer to displacements from left to right on the screen, * even if the graphics x axis increases in the opposite sense. * upy * The y component of the up-vector for the text. Positive values * always refer to displacements from left to right on the screen, * even if the graphics y axis increases in the opposite sense. * 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,and "M" * corresponds to the bottom of the bounding box. Some characters * (eg "y", "g", "p", etc) and sub-scripts 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. * uxu * X component of normalised up-vector, in graphics coords. * uyu * Y component of normalised up-vector, in graphics coords. * rxu * X component of normalised right-vector, in graphics coords. * ryu * Y component of normalised right-vector, in graphics coords. * x0 * Address of a float at which to return the x coordinate at the * left end of the baseline of the whole string. * y0 * Address of a float at which to return the y coordinate at the * left end of the baseline of the whole string. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated string which contains the * justification to use in future. This pointer should be freed using * astFree when no longer needed. This string will contain a full * upper-case justification string which can be used by the current * grf module. * Notes; * - NULL is returned if an error has occurred. */ /* Local Variables: */ char cc; float drop; float dx; float dy; float f; float height; float width; float xbn[ 4 ]; float ybn[ 4 ]; int called; char *result; /* Check inherited status */ if( !astOK ) return NULL; /* Allocate memory for the returned string. */ result = astMalloc( sizeof( char )*3 ); if( astOK ) { /* Fill in any missing parts of the justification string. */ if( just ){ cc = toupper( just[ 0 ] ); result[ 0 ] = ( cc == 'T' || cc == 'C' || cc == 'B' || cc == 'M' ) ? cc : 'C'; cc = toupper( just[ 1 ] ); result[ 1 ] = ( cc == 'L' || cc == 'C' || cc == 'R' ) ? cc : 'C'; } else { result[ 0 ] = 'C'; result[ 1 ] = 'C'; } result[ 2 ] = 0; /* Indicate that DrawText has not been called. */ called = 0; /* The justfication need not be changed unless the requested vertical justification is "bottom" (m), AND the grf module does not support "M" justification. */ if( ( result[ 0 ] == 'M' ) && !GCap( this, GRF__MJUST, 1, status ) ){ /* Find the bounding box which would result from putting the left end of the baseline at the specified position. */ DrawText( this, 0, esc, text, *x, *y, "BL", upx, upy, xbn, ybn, &drop, method, class, status ); /* Indicate that DrawText has not been called. */ called = 1; /* Get the vector from the bottom left corner of the bounding box to the reference point (on the base-line), and add this vector on to the reference point. */ *x += *x - xbn[ 0 ]; *y += *y - ybn[ 0 ]; /* Modified the returned justification string. */ result[ 0 ] = 'B'; } /* If the returned justification is "BL", then the left end of the baseline is just the returned reference point. */ if( result[ 0 ] == 'B' && result[ 1 ] == 'L' ) { *x0 = *x; *y0 = *y; /* Otherwise, we work out the coords of the left end of the baseline from the values returned by DrawText above. Call DrawText now if it was not called above. */ } else { if( ! called ) { DrawText( this, 0, esc, text, *x, *y, "BL", upx, upy, xbn, ybn, &drop, method, class, status ); } /* Find the height and width of the bounding box. */ dx = xbn[ 0 ] - xbn[ 3 ]; dy = ybn[ 0 ] - ybn[ 3 ]; width = sqrt( dx*dx + dy*dy ); dx = xbn[ 0 ] - xbn[ 1 ]; dy = ybn[ 0 ] - ybn[ 1 ]; height = sqrt( dx*dx + dy*dy ); /* For "C" and "R" horizontal justification we first need to move the returned reference point left by 0.5 or 1.0 times the width of the whole string respectively. */ if( result[ 1 ] == 'C' ) { f = 0.5; } else if( result[ 1 ] == 'R' ) { f = 1.0; } else { f = 0.0; } f *= width; *x0 = *x - f*rxu; *y0 = *y - f*ryu; /* Unless the vertical justification is "B", we also need to move the concatenation point vertically to put it on the baseline. */ if( result[ 0 ] == 'T' ) { f = height - drop; } else if( result[ 0 ] == 'C' ) { f = 0.5*height - drop; } else if( result[ 0 ] == 'M' ) { f = -drop; } else { f = 0.0; } *x0 -= f*uxu; *y0 -= f*uyu; } } /* Return the result. */ return result; } static int Labelat( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, double *labelat, const char *method, const char *class, int *status ){ /* * * Name: * Labelat * Purpose: * Determine the other axis value at which to place interior labels * and tick marks. * Type: * Private function. * Synopsis: * #include "plot.h" * int Labelat( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, * double *labelat, const char *method, const char *class ) * Class Membership: * Plot member function. * Description: * If tick marks and labels are to be placed within the plotting area, * the tick values stored in "grid" determine their position on one * axis, and their position on the other axis is determined by this * function. If a value has been set for the "LabelAt" attribute, then * it is used, otherwise the "other axis" value on the longest curve * parallel to the "other axis" is used (although the curve "other axis * = zero" is used if it passes through the plotting area and is not too * short). The effective length assigned to each curve is reduced in * proportion to the number of tick marks which are close to the edge * of the plotting area. * * A flag is returned indicating if the two axes appear to be * independent, in which case there is nothing to be gained by using * interior labelling. * Parameters: * this * A pointer to the Plot. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick values on the axis. See function GridLines. * cdata * A pointer to an array of two AstPlotCurveData pointers (one for each axis), * each pointing to an array of AstPlotCurveData structure (one for each * major tick value on the axis), holding information about breaks * in the curves drawn to mark the major tick values. See function * DrawGrid. * labelat * A pointer to a 2 element array in which to store the constant axis * values at which tick marks are put. Element 0 is returned holding * the axis 1 value at which tick marks for axis 0 are placed. Element * 1 is returned holding the axis 0 value at which tick marks for axis * 1 are placed. * flags * A pointer to a 2 element array. Each element is a flag which is * returned non-zero if the corresponding axis * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * Returned Value: * Zero if and only if the lines of constant axis value are all the * same length for all tick marks on either axis. If this is so, using * interior labelling will not enable any more major ticks to be * drawn, and so there is no reason to switch to interior labelling (unless * the user has specifically requested interior labelling). * Notes: * - This function assumes the current Frame of the Plot is 2 * dimensional, and it should not be called if this is not the case. */ /* Local Variables: */ AstMapping *mapping; /* Mapping from graphics to physical coords */ AstPointSet *pset2; /* Pointset for graphical tick positions */ AstPointSet *pset[ 2 ];/* Pointsets for physical tick positions */ AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ double **ptr2; /* Pointers to graphics pointset data */ double *ptr1[ 2 ]; /* Pointers to physical pointset data */ double *tvals[ 2 ]; /* Pointers to arrays of other axis values */ double *value; /* Current tick value */ double efflen; /* Effective length of current curve */ double lim; /* Largest insignificant axis value */ double margin; /* Width of margin around plotting area */ double maxlen; /* Effective length of longest curve */ double minlen; /* Effective length of shortest (non-zero) curve */ double x; /* Tick X value */ double xhi; /* Upper limit on acceptable X range */ double xlo; /* Lower limit on acceptable X range */ double y; /* Tick Y value */ double yhi; /* Upper limit on acceptable Y range */ double ylo; /* Lower limit on acceptable Y range */ double zerolen; /* Effective length of curve for other axis = 0.0 */ int axis; /* Current axis index */ int i; /* Tick index for this axis */ int nin; /* No. of counted ticks */ int result; /* Does interior labelling allow more ticks to be drawn? */ int tick; /* Tick index */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise */ result = 1; /* Create two PointSets to hold a set of tick mark positions along each axis. The values on "axis" will be taken from the info structure. For each axis create an array to hold values for the "other" axis. */ for( axis = 0; axis < 2; axis++ ){ info = grid[ axis ]; pset[ axis ] = astPointSet( info->nmajor, 2, "", status ); tvals[ axis ] = (double *) astMalloc( sizeof(double)*(size_t)(info->nmajor) ); } /* Get the mapping from Base (graphics) frame the Current (physical) */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Get the bounds of the area in which tick marks must occur to be counted. This is the total plotting area minus a 5% margin at each edge. */ margin = 0.05*( this->xhi - this->xlo ); xlo = this->xlo + margin; xhi = this->xhi - margin; margin = 0.05*( this->yhi - this->ylo ); ylo = this->ylo + margin; yhi = this->yhi - margin; /* Do each axis. */ for( axis = 0; axis < 2 && astOK; axis++ ){ /* Find the longest and shortest curves parallel to the axis being labelled. Also find the length of the curve which passes through the origin of the other axis which is within the plotting area. We need to do this even if LabelAt has been set since we need to calculate the returned flag. */ /* Store pointers to the arrays holding tick mark physical coordinates, and set these in the PointSet. */ ptr1[ axis ] = grid[ axis ]->ticks; ptr1[ 1 - axis ] = tvals[ axis ]; astSetPoints( pset[ axis ], ptr1 ); /* Get a pointer to the structure containing information describing the positions of the major tick marks along the other axis. */ info = grid[ 1 - axis ]; /* Get a pointer to the other axis value at the first other axis major tick mark. */ value = info->ticks; /* Get a limit on absolute magnitude for an axis value to be consider equal to zero. */ lim = 1.0E-6*fabs( value[ 1 ] - value [ 0 ] ); /* Get a pointer to the structure containing information describing the breaks in the curve which passes through the first major tick mark. */ cdt = cdata[ 1 - axis ]; /* Initialise the effective length of the longest and shortest curves, and the curve passing through the origin. */ maxlen = -1.0; minlen = DBL_MAX; zerolen = 0.0; labelat[ axis ] = AST__BAD; /* Loop round each of the major tick marks on the other axis. */ for( tick = 0; tick < info->nmajor && astOK; tick++ ){ /* Fill the array of other axis values with the current other axis value. */ for( i = 0; i < grid[ axis ]->nmajor; i++ ){ tvals[ axis ][ i ] = *value; } /* Transform the tick positions from the current frame (i.e. physical coordinates) to the base frame (i.e. graphics coordinates) using the inverse Mapping. */ pset2 = Trans( this, NULL, mapping, pset[ axis ], 0, NULL, 0, method, class, status ); /* Get pointers to the graphics coordinates. */ ptr2 = astGetPoints( pset2 ); if( astOK ) { /* Count the number of graphics positions which are well within the plotting area. */ nin = 0; for( i = 0; i < grid[ axis ]->nmajor; i++ ){ x = ptr2[ 0 ][ i ]; y = ptr2[ 1 ][ i ]; if( x != AST__BAD && x > xlo && x < xhi && y != AST__BAD && y > ylo && y < yhi ) nin++; } /* Find the effective length of this curve.*/ efflen = sqrt( (float) nin )*cdt->length; /* If the curve through this tick mark has a greater effective length than any other found so far, record it. */ if( efflen > maxlen ){ maxlen = efflen; labelat[ axis ] = *value; } /* If the curve through this tick mark has a smaller non-zero effective length than any other found so far, record it. */ if( efflen < minlen && efflen > 0.0 ) minlen = efflen; /* If this tick mark is at the origin, note the effective length. */ if( fabs( *value ) <= lim ) zerolen = efflen; /* Get a pointer to the curve through the next major tick mark. */ cdt++; /* Get a pointer to the axis value at the next major tick mark. */ value++; } /* Free resources. */ pset2 = astAnnul( pset2 ); } /* Use the curve through the origin unless it is significantly shorter than the longest curve. */ if( zerolen > 0.4*maxlen ) labelat[ axis ] = 0.0; /* Return a flag if the lengths of the shortest and longest curves are nearly equal. */ if( ( maxlen - minlen )/( maxlen + minlen ) < 1.0E-5 ) result = 0; /* If the LabelAt attribute has been set, use it in preference to the value found above. */ if( astTestLabelAt( this, axis ) ){ labelat[ axis ] = astGetLabelAt( this, axis ); } } /* Release resources. */ for( axis = 0; axis < 2; axis++ ){ if( pset[ axis ] ) pset[ axis ] = astAnnul( pset[ axis ] ); if( tvals[ axis ] ) tvals[ axis ] = (double *) astFree( (void *) tvals[ axis ] ); } mapping = astAnnul( mapping ); /* Return. */ return result; } static void Labels( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, double *gap, double *labelat, const char *method, const char *class, int *status ){ /* * * Name: * Labels * Purpose: * Draw numerical axis labels for a 2-D annotated coordinate grid. * Type: * Private function. * Synopsis: * #include "plot.h" * void Labels( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, * double *gap, double *labelat, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * The policy for placing labels for the major tick values is broadly as * follows: if possible, labels for a given physical axis are placed on * one edge of the plotting area, at the place where the curve for a * major tick value crosses the edge. If very few of the curves cross * the edge, then the label for a curve is placed at the intersection * of that curve with the longest of the curves representing the major * tick values on the other axis. * Parameters: * this * A pointer to the Plot. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick values on the axis. See function GridLines. * cdata * A pointer to an array of two AstPlotCurveData pointers (one for each axis), * each pointing to an array of AstPlotCurveData structure (one for each * major tick value on the axis), holding information about breaks * in the curves drawn to mark the major tick values. See function * DrawGrid. * gap * Pointer to array of two values holding the gap between major * tick values on the two axes. * labelat * A pointer to a 2 element array holding the constant axis * values at which tick marks are put. Element 0 should hold * the axis 1 value at which tick marks for axis 0 are placed. Element * 1 should hold the axis 0 value at which tick marks for axis * 1 are placed. If labels are to be placed round the edges of the * plotting zone instead of within the plotting zone, then values of * AST__BAD should be supplied. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This function assumes the current Frame of the Plot is 2 * dimensional, and it should not be called if this is not the case. */ /* Local Variables: */ AstFrame *frame; /* Pointer to current Frame */ AstMapping *mapping; /* Pointer to graphics->physical Mapping */ AstPointSet *pset1; /* Pointer to PointSet holding physical coords. */ AstPointSet *pset2; /* Pointer to PointSet holding graphics coords. */ AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ LabelList *labellist; /* Pointer to list of labels to be plotted */ LabelList *ll; /* Pointer to next label to be plotted */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ char just_buf[3]; /* Buffer to hold a justification string */ const char *just; /* Justification string */ const char *text; /* Pointer to label text */ double *used; /* Pointer to list of used label values */ double *value; /* Current tick value */ double diff; /* Difference between adjacent major tick marks */ double dx; /* Text base-line X component */ double dy; /* Text base-line Y component */ double gx; /* Reference position graphics X coord. */ double gy; /* Reference position graphics Y coord. */ double mindim; /* Shortest dimension of plotting area */ double offx; /* X component of offset vector */ double offy; /* Y component of offset vector */ double rlen; /* Length of perpendicular vector */ double rx; /* X comp of vector perpendicular to (dx,dy) */ double ry; /* Y comp of vector perpendicular to (dx,dy) */ double sin45; /* Sine of 45 degrees */ double txtgap; /* Absolute gap between labels and edges */ double upx; /* Text up-vector X component */ double upy; /* Text up-vector Y component */ double val[ 2 ]; /* Physical coordinates */ float *box; /* Pointer to array of label bounding boxes */ float alpha; /* Factor to convert graphics X to equal scaled X */ float beta; /* Factor to convert graphics Y to equal scaled Y */ int axis; /* Current axis index */ int esc; /* Interpret escape sequences? */ int flag; /* Flag indicating which way the base-vector points */ int iused; /* Index into list of used axis values */ int last; /* The index of the last tick to use */ int logticks; /* ARe major ticks spaced logarithmically? */ int nlab; /* The number of labels to be plotted */ int nused; /* Number of used axis values */ int t0; /* Index of central tick */ int tick; /* Current tick index */ int tinc; /* Increment between ticks */ int upfree; /* Are we free to change the up-vector? */ int gelid; /* ID for next graphical element to be drawn */ /* Check the global status. */ if( !astOK ) return; /* See if escape sequences in text strings are to be interpreted */ esc = astGetEscape( this ); /* Empty the list of bounding boxes kept by the Overlap function. */ (void) Overlap( this, 0, 0, NULL, 0.0, 0.0, NULL, 0.0, 0.0, NULL, method, class, status ); /* If required, draw the labels around the edges of the plotting area. */ if( labelat[ 0 ] == AST__BAD || labelat[ 1 ] == AST__BAD ){ (void) EdgeLabels( this, 1, grid, cdata, 1, method, class, status ); /* Otherwise, draw labels within the interior of the plotting area. */ } else { /* Find the scale factors for the two axes which scale graphics coordinates into a "standard" equal scaled coordinate system in which: 1) the axes have equal scale in terms of (for instance) millimetres per unit distance, 2) X values increase from left to right, 3) Y values increase from bottom to top. */ GScales( this, &alpha, &beta, method, class, status ); /* Get the minimum dimension of the plotting area in equal scaled coords. */ mindim = MIN( fabs( alpha*(this->xhi - this->xlo) ), fabs( beta*(this->yhi - this->ylo) ) ); /* Store a value for the sine of 45 degrees. */ sin45 = 1.0/sqrt( 2.0 ); /* Initialise the pointer to the memory holding the bounding boxes for all labels (used by function Overlap). */ box = NULL; /* Get a pointer to the current Frame in the Plot. */ frame = astGetFrame( this, AST__CURRENT ); /* Get a pointer to the mapping form the base Frame to the current Frame in the Plot. */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Initialize the id value for graphical element being drawn. */ gelid = AST__NUMLAB1_ID; /* Do each axis. */ for( axis = 0; axis < 2; axis++ ){ /* See of major ticks are spaced logarithmically on this axis. */ logticks = astGetLogTicks( this, axis ); /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); /* Get a pointer to the structure containing information describing the positions of the major tick marks along this axis. */ info = grid[ axis ]; /* Only progress if there are some labels stored within the structure. */ if( info->labels ) { /* Initialise the pointer to the list of text strings to be drawn. */ labellist = NULL; nlab = 0; /* See if numerical labels are always to be drawn horizontal. If so, set a flag and initialise a vertical up-vector. */ if( astGetLabelUp( this, axis ) ){ upfree = 0; upx = 0.0; upy = 1.0; /* Otherwise, clear the flag and indicate that we do not yet have an up-vector. */ } else { upfree = 1; upx = AST__BAD; upy = AST__BAD; } /* Indicate that the tangent vector to the other axis is not yet known. */ dx = AST__BAD; dy = AST__BAD; gx = AST__BAD; gy = AST__BAD; /* Store the gap to put next to the label text. This is in equal scaled coords, not graphics coords. */ txtgap = astGetNumLabGap( this, axis )*mindim; /* Get a pointer to the structure containing information describing the breaks in the curve which passes through the first major tick mark. */ cdt = cdata[ axis ]; /* Get a pointer to the axis value at the first major tick mark. */ value = info->ticks; /* Initialise pointers to two PointSets which will be created and used within function GVec. */ pset1 = NULL; pset2 = NULL; /* Get memory to hold the axis values at which labels have been put. */ used = (double *) astMalloc( sizeof(double)*(size_t)info->nmajor ); nused = 0; /* The tick marks are done in two batches, each batch working out from the middle. This is done because there may be extra tick marks outside the normal ranges at the extremes, and these should not be given the priority caused by doing them first. Store the mid-tick index, the current tick index, and the increment between ticks. The ticks from the middle up to the highest index are done first. */ t0 = info->nmajor/2; tick = t0 - 1; tinc = 1; /* Loop round until all ticks have been done. */ last = info->nmajor - 1; while( (tick += tinc) >= 0 && astOK ){ /* If we have done the highest tick index, start again at the tick just below middle, and work done towards index zero. */ if( tick == info->nmajor ){ tick = t0 - 1; tinc = -1; } /* Store the reference position for the label . */ val[ axis ] = value[ tick ]; val[ 1 - axis ] = labelat[ axis ]; /* Store the difference between this tick and the next. */ if( logticks ) { diff = value[ tick ]*( gap[ axis ] - 1.0 ); } else { diff = gap[ axis ]; } /* See if this axis value has already been used. */ for( iused = 0; iused < nused; iused++ ){ if( fabs( val[ axis ] - used[ iused ] ) < 1.0E-3*diff ) break; } /* If the axis value has already been used, don't use it again. */ if( iused >= nused || nused == 0 ){ used[ nused++ ] = val[ axis ]; /* We now need to decide where to put the reference point for the text string, and what justification to use. Assuming that NumLabGap is +ve, the labels are drawn on the left hand side of the axis as seen by someone moving along the axis in the positive direction, with an up-vector which is normal to the axis tangent. First, find the graphics coordinates at the point being labelled, and the unit tangent-vector parallel to the axis being labelled. If the tangent vector is not defined, then the tangent vector used for the previous label is re-used. This unit tangent vector is expressed in graphics coords. */ GVec( this, mapping, val, axis, 0.01*diff, &pset1, &pset2, &gx, &gy, &dx, &dy, &flag, method, class, status ); /* If we now have a tangent vector and good graphics coordinates for the label's reference position... */ if( dx != AST__BAD && dy != AST__BAD && gx != AST__BAD && gy != AST__BAD ){ /* Convert the unit tangent vector from graphics coords to equal-scaled coords. */ dx *= alpha; dy *= beta; /* Rotate through 90 degrees to get a vector perpendicular to the axis in equal scaled coords. This vector points to the left as you move along the physical axis in the positive direction. Find its length. */ rx = -dy; ry = dx; rlen = sqrt( rx*rx + ry*ry ); /* The reference position for the text is displaced away from the reference position normal to the axis on the left hand side by the "txtgap" value. */ offx = rx*txtgap/rlen; offy = ry*txtgap/rlen; gx += offx/alpha; gy += offy/beta; /* The up-vector and justification for the text depends on whether or not the up-vector is free to rotate. If it is free, the up-vector is chosen so that the text is not upside-down. Note, the up-vector is specified in the equally scaled coordinate system. */ if( upfree ){ if( dx < -0.01*fabs( alpha ) ){ upx = -rx; upy = -ry; just = ( txtgap < 0.0 )? "BC" : "TC"; } else { upx = rx; upy = ry; just = ( txtgap < 0.0 )? "TC" : "BC"; } if( txtgap == 0.0 ) just = "CC"; /* If the up vector is required to be vertical, a system is used which tries to put the centre of the text string on or near the offset vector. */ } else { upx = 0.0; upy = 1.0; if( offy > fabs(txtgap)*sin45 ){ just_buf[0] = 'B'; } else if( offy < -fabs(txtgap)*sin45 ){ just_buf[0] = 'T'; } else { just_buf[0] = 'C'; } if( txtgap == 0.0 ) just_buf[0] = 'C'; if( offx < -fabs(txtgap)*sin45 ){ just_buf[1] = 'R'; } else if( offx > fabs(txtgap)*sin45 ){ just_buf[1] = 'L'; } else { just_buf[1] = 'C'; } if( txtgap == 0.0 ) just_buf[1] = 'C'; just_buf[2] = 0; just = just_buf; } /* Get the label text. */ text = (info->labels)[ tick ]; if( text ){ /* Check that the reference position is within the plotting area. If so, add it to the list of labels to be drawn. */ if( gx >= this->xlo && gx <= this->xhi && gy >= this->ylo && gy <= this->yhi ){ labellist = (LabelList *) astGrow( (void *) labellist, nlab + 1, sizeof(LabelList) ); if ( astOK ) { (labellist + nlab)->index = tick; (labellist + nlab)->text = (char *) astStore( NULL, (void *) text, strlen(text) + 1 ); (labellist + nlab)->x = gx; (labellist + nlab)->y = gy; (labellist + nlab)->just = (char *) astStore( NULL, (void *) just, strlen(just) + 1 ); (labellist + nlab)->upx = upx; (labellist + nlab)->upy = upy; (labellist + nlab)->val = val[ axis ]; nlab++; } else { break; } } } } } } /* If any labels were stored, draw the text strings, and then release the memory used to hold the text, etc. */ if( nlab > 0 ) { PlotLabels( this, esc, frame, axis, labellist, info->fmt, nlab, &box, method, class, status ); ll = labellist; for( tick = 0; tick < nlab; tick ++ ) { ll->text = (char *) astFree( (void *) ll->text ); ll->just = (char *) astFree( (void *) ll->just ); ll++; } labellist = (LabelList *) astFree( (void *) labellist ); } /* Free the memory used to hold the axis values at which labels have been put. */ used = (double *) astFree( (void *) used ); /* Annul the PointSets (if used). */ if( pset1 ) pset1 = astAnnul( pset1 ); if( pset2 ) pset2 = astAnnul( pset2 ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); /* Set up the id for the next graphical element to be drawn. */ gelid = AST__NUMLAB2_ID; } } /* Free the memory used to hold the bounding boxes. */ box = (float *) astFree( (void *) box ); /* Annul the pointers to the Frame and the Mapping. */ mapping = astAnnul( mapping ); frame = astAnnul( frame ); } /* Return. */ return; } static void LinePlot( AstPlot *this, double xa, double ya, double xb, double yb, int ink, AstPlotCurveData *cdata, const char *method, const char *class, int *status ){ /* * * Name: * LinePlot * Purpose: * Draws a straight line omitting bad regions. * Type: * Private function. * Synopsis: * #include "plot.h" * void LinePlot( AstPlot *this, double xa, double ya, double xb, * double yb, int ink, AstPlotCurveData *cdata, * const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function draws a straight line between two positions in graphics * coordinates but leaves gaps in the line where it passes through * regions which have no corresponding physical coordinates. * Parameters: * this * Pointer to the Plot. * xa * The graphics X coordinate at the start of the line. * ya * The graphics Y coordinate at the start of the line. * xb * The graphics X coordinate at the end of the line. * yb * The graphics Y coordinate at the end of the line. * ink * If zero, the line is not actually drawn, but information about * the breaks is still returned. If non-zero, the line is also drawn. * cdata * A pointer to a structure in which to return information about the * breaks in the line. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - No curve is draw if any of the start or end positions are bad * (i.e. equal to AST__BAD), or if a NULL pointer is supplied for "cdata". * No errors are reported in these cases. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ double tol; /* Absolute tolerance value */ int i; /* Loop count */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Check the supplied values are usable. */ if( xa == AST__BAD || ya == AST__BAD || xb == AST__BAD || yb == AST__BAD || !cdata ) return; /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Set up the external variables used by the Crv and CrvLine function (see their prologues for details). */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_ux0 = AST__BAD; Crv_limit = 0.5*tol*tol; Crv_tol = tol; Crv_map = Map2; Crv_ink = ink; Crv_len = 0.0F; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_out = 1; Crv_xbrk = cdata->xbrk; Crv_ybrk = cdata->ybrk; Crv_vxbrk = cdata->vxbrk; Crv_vybrk = cdata->vybrk; Crv_clip = astGetClip( this ) & 1; /* Create a set of evenly spaced values between 0.0 and 1.0. These are the offsets the edge of the plotting zone at which the mapping is tested. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Now set up the externals used to communicate with the Map2 function. Map2 transforms a set of offsets between zero and one into a set of corresponding graphics coordinates, with bad values substituted for any offsets which correspond to points outside the domain of the mapping. */ /* The number of axes in the physical coordinate system (i.e. the current Frame). */ Map2_ncoord = astGetNout( this ); /* A pointer to the mapping from graphics world cordinates to physical coordinates. */ Map2_plot = this; Map2_map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* The graphics coordinates corresponding to an offset of zero (i.e. the start of the line). */ Map2_x0 = xa; Map2_y0 = ya; /* The increments in X and Y between offset zero (the start of the line) and offset 1 (the end of the line). */ Map2_deltax = xb - xa; Map2_deltay = yb - ya; /* Get the graphics coordinates corresponding to the initial set of offsets. */ Map2( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map2 to draw the intersection of the straight line with the region containing valid physical coordinates. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* End the current poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map2. */ Map2( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* If no part of the curve could be drawn, set the number of breaks and the length of the drawn curve to zero. */ if( Crv_out ) { Crv_nbrk = 0; Crv_len = 0.0F; /* Otherwise, add an extra break to the returned structure at the position of the last point to be plotted. */ } else { Crv_nbrk++; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; } } /* Store extra information about the curve in the returned structure, and purge any zero length sections. */ if( cdata ){ cdata->length = Crv_len; cdata->out = Crv_out; cdata->nbrk = Crv_nbrk; PurgeCdata( cdata, status ); } /* Annul the Mapping. */ Map2_map = astAnnul( Map2_map ); /* Return. */ return; } static double **MakeGrid( AstPlot *this, AstFrame *frm, AstMapping *map, int disk, int dim, double xlo, double xhi, double ylo, double yhi, int nphy, AstPointSet **pset1, AstPointSet **pset2, int norm, const char *method, const char *class, int *status ){ /* * Name: * MakeGrid * Purpose: * Create a square grid of graphics coordinates and the corresponding * physical coordinates. * Type: * Private function. * Synopsis: * #include "plot.h" * double **MakeGrid( AstPlot *this, AstFrame *frm, AstMapping *map, * int disk, int dim, double xlo, double xhi, double ylo, * double yhi, int nphy, AstPointSet **pset1, * AstPointSet **pset2, int norm, const char *method, * const char *class, int *status ){ * Class Membership: * Plot member function. * Description: * This function creates two PointSets, one holding a square grid of * graphics coordinates covering the supplied area, and the other * holding the corresponding physical coordinates. The points are * stored row by row in the returned PointSets, i.e. if the cell size * for the grid is (dx,dy), the first point is (xmin,ymin), followed * by (xmin+dx,ymin), (xmin+2*dx,ymin), up to (xmin+(dim-1)*dx,ymin), * followed by the next row (xmin,ymin+dy), (xmin+dx,ymin+dy), etc. * Parameters: * this * The Plot. * frm * A pointer to the Current Frame in the Plot. If this is supplied * NULL, then a pointer is found within this function if required (i.e. * if "norm" is non-zero). * map * The Mapping from graphics to physical coordinates, extracted from * the Plot. * disk * If non-zero, the corners of the grid are omitted form the * returned PointSets, resulting in a grid that is more disk like than * rectangular. * dim * The number of samples along each edge of the grid. * xlo * The lower bound on the first axis of the region to be covered * by the grid. * xhi * The upper bound on the first axis of the region to be covered * by the grid. * ylo * The lower bound on the second axis of the region to be covered * by the grid. * yhi * The upper bound on the second axis of the region to be covered * by the grid. * nphy * The number of axes in the physical cooridinate system. * pset1 * A pointer to a location at which to store a pointer to the * PointSet holding the graphics coordinates. * pset2 * A pointer to a location at which to store a pointer to the * PointSet holding the physical coordinates. * norm * If non-zero the physical cooridnates are normalised using the * Plot's astNorm method. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the physical coordinate data stored in the PointSet * "pset2". * Notes: * - The returned PointSets should be annulled when no longer needed, * using astAnnul. * - NULL pointers are returned if an error has already occurred, or * if this function should fail for any reason. */ /* Local Variables: */ double **ptr1; /* Pointers to graphics axis values */ double **ptr2; /* Pointers to physical axis values */ int size; /* No. of points in the grid */ /* Initialise the returned pointers. */ *pset1 = NULL; *pset2 = NULL; /* Check the global error status. */ if ( !astOK ) return NULL; /* Create two PointSets. We assume for the moment that they cover the full grid, including corners. */ size = dim*dim; *pset1 = astPointSet( size, 2, "", status ); *pset2 = astPointSet( size, nphy, "", status ); /* Get pointers to the data arrays for the two PointSets. */ ptr1 = astGetPoints( *pset1 ); ptr2 = astGetPoints( *pset2 ); /* Create a grid covering the supplied area. */ size = GraphGrid( dim, disk, xlo, xhi, ylo, yhi, ptr1, status ); /* If the corners are being omitted, reduce the number of points in the two PointSets. */ if( disk ) { astSetNpoint( *pset1, size ); astSetNpoint( *pset2, size ); } /* Transform these graphics positions to physical coordinates. */ Trans( this, frm, map, *pset1, 1, *pset2, norm, method, class, status ); /* If an error has occurred, annul the two pointsets. */ if( !astOK ){ *pset1 = astAnnul( *pset1 ); *pset2 = astAnnul( *pset2 ); ptr2 = NULL; } /* Return. */ return ptr2; } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * Plot member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstPlot *this; /* Pointer to Plot structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the Plot structure. */ this = (AstPlot *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* If defined, ensure the grfcontext KeyMap contained within the Plot is locked, unlocked or checked. */ if( this->grfcontext ) { if( !result ) result = astManageLock( this->grfcontext, mode, extra, fail ); /* Also lock or unlock the associated object handle. */ if( mode == AST__LOCK ) { if( !result ) astLock( this->grfcontextID, extra ); } else if( mode == AST__UNLOCK ) { if( !result ) astUnlock( this->grfcontextID, 0 ); } } return result; } #endif static void Map1( int n, double *dist, double *x, double *y, const char *method, const char *class, int *status GLOBALS_ARG ){ /* * Name: * Map1 * Purpose: * Find graphics coordinates at given distances along a curve * parallel to a physical axis. * Type: * Private function. * Synopsis: * #include "plot.h" * void Map1( int n, double *dist, double *x, double *y, * const char *method, const char *class, * int *status [,AstGlobals *AST__GLOBALS] ) * Class Membership: * Plot member function. * Description: * The supplied distances are converted into physical coordinates * using the scalings described by various external variables, and then * these physical coordinates are mapped into graphics coordinates. * Parameters: * n * The number of points to map. Static resources are released but * no points are mapped if zero is supplied. * dist * A pointer to an array holding "n" distances. A "dist" value of * zero corresponds to the starting position supplied in external * variable Map1_origin. A "dist" value of one corresponds to the * finishing position which is a distance Map1_length away from * Map1_origin, moving in the positive direction of the axis given * by Map1_axis. "dist" values can be either linearly or * logarithmically related to axis values (see Map1_log). * x * A pointer to an array in which to store the "n" graphics X * coordinate values corresponding to the positions in "dist". * y * A pointer to an array in which to store the "n" graphics Y * coordinate values corresponding to the positions in "dist". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * AST__GLOBALS * Only present if compiled with -DTHREAD_SAFE. It is a pointer to * the structure holding the global data for the executing thread. * It is passed as a function parameter, rather than being accessed * within this function using the astGET_GLOBALS(NULL) macro (as * other Object-less functions do) in order to avoid the time * overheads of calling astGET_GLOBALS(NULL) . This function is * time-critical. * External Variables: * Map1_log = int (Read) * If zero, then "dist" in learly related to axis value. Otherwise * it is linearly related to log10(axis value). * Map1_ncoord = int (Read) * The number of axes in the physical coordinate system. * Map1_axis = int (Read) * The zero-based index of the axis which the curve follows (i.e. * the axis which changes value along the curve). * Map1_statics = Map1Statics * (Read and Write) * Pointer to a structure holding other static data used by Map1. * Map1_origin = const double * (Read) * A pointer to an array holding the physical coordinate value on * each axis at the start of the curve (i.e. at dist = 0.0). * Map1_length = double (Read) * The scale factor to convert "dist" values into increments * along the physical axis given by Map1_axis. * Map1_plot = AstPlot * (Read) * A pointer to the Plot defining the mapping from graphics cordinates * to physical coordinates. * Map1_map = AstMapping * (Read) * A pointer to the mapping from graphics cordinates to physical * coordinates extracted from the Plot. * Map1_frame = AstFrame * (Read) * A pointer to the Current Frame in the Plot. * Map1_norm = int (Read) * A flag indicating if physical coordinate values which are not in * the normal ranges of the corresponding axes should be considered * bad. * Notes: * - On the first call, this function allocates static resources which * are used by subsequent invocation. These resources should be freed before * calling this function with new values for any of the external variables, * or when no longer needed, by calling this function with "n" supplied as * zero. * - If an error has already occurred, this runction returns without * action ,except that if "n" is supplied as zero then static resources * are released even if an error has already occurred. */ /* Local Constants: */ Map1Statics *statics; /* Pointer to structure holding static data */ double *p; /* Pointer to next value */ double axval; /* Axis origin value */ int i, j; /* Loop counts */ /* Convert the global "void *" pointer to a Map1Statics pointer */ statics = (Map1Statics *) Map1_statics; /* If zero points were supplied, release static resources and return. */ if( n == 0 ){ if( statics ) { if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); if( statics->work1 ) statics->work1 = (double *) astFree( (void *) statics->work1 ); if( statics->work2 ) statics->work2 = (double *) astFree( (void *) statics->work2 ); Map1_statics = astFree( statics ); } return; } /* Otherwise, check the inherited global status. */ if( !astOK ) return; /* Create and initialise a structure to hold extra static information if this has not already been done. */ if( !statics ) { statics = astMalloc( sizeof( Map1Statics ) ); if( statics ) { statics->pset1 = NULL; statics->pset2 = NULL; statics->ptr1 = NULL; statics->pax = NULL; statics->ptr2[ 0 ] = NULL; statics->ptr2[ 1 ] = NULL; statics->work1 = NULL; statics->work2 = NULL; statics->nl = 0; Map1_statics = statics; } } /* If the number of points to be mapped is different to last time, set up some PointSets to store the specified number of points. */ if( n != statics->nl ){ statics->nl = n; /* Create a PointSet to hold the physical coordinates corresponding to the supplied offsets. First annul any existing PointSet. */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); statics->pset1 = astPointSet( n, Map1_ncoord, "", status ); statics->ptr1 = astGetPoints( statics->pset1 ); /* Create a PointSet to hold the corresponding graphics coordinates. The supplied "x" and "y" arrays will be used to store the data so we do not need to get pointers to the data using astGetPoints. First annul any existing PointSet. */ if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); statics->pset2 = astPointSet( n, 2, "", status ); /* Get work space to hold two positions. */ statics->work1 = (double *) astRealloc( (void *) statics->work1, sizeof(double)*(size_t)Map1_ncoord ); statics->work2 = (double *) astRealloc( (void *) statics->work2, sizeof(double)*(size_t)Map1_ncoord ); /* Check the pointer can be used. */ if( astOK ){ /* Store a pointer to the start of the memory which will be used to store the physical data for the axis being drawn. */ statics->pax = statics->ptr1[ Map1_axis ]; /* Fill the PointSet which is used to hold physical data with the physical coordinates at the start of the curve. */ for( i = 0; i < Map1_ncoord; i++ ){ axval = Map1_origin[ i ]; p = statics->ptr1[ i ]; for( j = 0; j < n; j++ ) *(p++) = axval; } /* Store the scale and offset to apply to the "dist" values. If Map1_log is zero (linear axes) then applying these values gives axis value directly. If Map1_log is non-zero (log axes) then applying these values gives log10( axis value). */ if( Map1_log ) { statics->neg = ( Map1_origin[ Map1_axis ] < 0 ); statics->axorig = log10( fabs( Map1_origin[ Map1_axis ] ) ); statics->axscale = log10( fabs( Map1_origin[ Map1_axis ] + Map1_length ) ) - statics->axorig; } else { statics->axorig = Map1_origin[ Map1_axis ]; statics->axscale = Map1_length; } } } /* Check the initialisation went OK (if done). */ if( astOK ){ /* Loop round each offset along the curve, converting the normalised offset in the range [0,1] to a physical coordinate and storing in PointSet 1. */ p = statics->pax; for( i = 0; i < n; i++){ *(p++) = statics->axorig + statics->axscale*dist[ i ]; } if( Map1_log ) { p = statics->pax; for( i = 0; i < n; i++,p++ ){ *p = statics->neg ? -pow( 10.0, *p ) : pow( 10.0, *p ); } } /* Store pointers to the results arrays in PointSet 2. */ statics->ptr2[ 0 ] = x; statics->ptr2[ 1 ] = y; astSetPoints( statics->pset2, statics->ptr2 ); /* Map all the positions into graphics coordinates. */ (void) Trans( Map1_plot, NULL, Map1_map, statics->pset1, 0, statics->pset2, 1, method, class, status ); /* If points not in their normal ranges are to be set bad... */ if( Map1_norm ) { /* The following code simply normalizes the physical position, and if this produces any change, the graphics positions are set bad. */ for( i = 0; i < n; i++){ for( j = 0; j < Map1_ncoord; j++) statics->work1[j] = statics->ptr1[j][i]; astNorm( Map1_frame, statics->work1 ); for( j = 0; j < Map1_ncoord; j++) { if( !EQUAL( statics->work1[j], statics->ptr1[j][i] ) ) { statics->ptr2[0][i] = AST__BAD; statics->ptr2[1][i] = AST__BAD; break; } } } } } /* Return. */ return; } static void Map2( int n, double *dist, double *x, double *y, const char *method, const char *class, int *status GLOBALS_ARG ){ /* * Name: * Map2 * Purpose: * Find which graphics coordinates have good physical coordinates * at given distances along a straight line. * Type: * Private function. * Synopsis: * #include "plot.h" * void Map2( int n, double *dist, double *x, double *y, * const char *method, const char *class, * int *status [,AstGlobals *AST__GLOBALS] ) * Class Membership: * Plot member function. * Description: * The supplied distances refer to the distance along a straight line * in the graphics coordinate system. The returned graphics coordinates * correspond to the supplied distances, except that any position for * which there are no defined physical coordinates is returned bad. * Parameters: * n * The number of points to map. Static resources are released but * no points are mapped if zero is supplied. * dist * A pointer to an array holding "n" distances. A "dist" value of * zero corresponds to the graphics position supplied in external * variables (Map2_x0, Map2_y0). A "dist" value of one corresponds to * the graphics position which is offset from the start by the vector * (Map2_deltax, Map2_deltay). * x * A pointer to an array in which to store the "n" graphics X * coordinate values corresponding to the positions in "dist", * except that any which have no corresponding physical coordinates * are set to AST__BAD. * y * A pointer to an array in which to store the "n" graphics Y * coordinate values corresponding to the positions in "dist", * except that any which have no corresponding physical coordinates * are set to AST__BAD. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * AST__GLOBALS * Only present if compiled with -DTHREAD_SAFE. It is a pointer to * the structure holding the global data for the executing thread. * It is passed as a function parameter, rather than being accessed * within this function using the astGET_GLOBALS(NULL) macro (as * other Object-less functions do) in order to avoid the time * overheads of calling astGET_GLOBALS(NULL) . This function is * time-critical. * External Variables: * Map2_ncoord = int (Read) * The number of axes in the physical coordinate system. * Map2_x0 = double (Read) * The graphics X coordinate at the start of the line (i.e. at dist * = 0.0). * Map2_y0 = double (Read) * The graphics Y coordinate at the start of the line (i.e. at dist * = 0.0). * Map2_deltax = double (Read) * The increment along the graphics X axis between the start and * end of the line. * Map2_deltay = double (Read) * The increment along the graphics Y axis between the start and * end of the line. * Map2_plot = AstPlot * (Read) * A pointer to the Plot defining the mapping from graphics cordinates * to physical coordinates. * Map2_map = AstMapping * (Read) * A pointer to the mapping from graphics cordinates to physical * coordinates, extracted from the Plot. * Map2_statics = Map2Statics * (Read and Write) * Pointer to a structure holding other static data used by Map2. * Notes: * - On the first call, this function allocates static resources which * are used by subsequent invocation. These resources should be freed before * calling this function with new values for any of the external variables, * or when no longer needed, by calling this function with "n" supplied as * zero. * - If an error has already occurred, this runction returns without * action ,except that if "n" is supplied as zero then static resources * are released even if an error has already occurred. */ /* Local Constants: */ Map2Statics *statics; /* Pointer to structure holding static data */ int i, j; /* Loop counts */ double *p; /* Pointer to next physical value */ double *px; /* Pointer to next x graphics value */ double *py; /* Pointer to next y graphics value */ /* Convert the global "void *" pointer to a Map2Statics pointer */ statics = (Map2Statics *) Map2_statics; /* If zero points were supplied, release static resources and return. */ if( n == 0 ){ if( statics ) { if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); Map2_statics = astFree( statics ); } return; } /* Otherwise, check the inherited global status. */ if( !astOK ) return; /* Create and initialise a structure to hold extra static information if this has not already been done. */ if( !statics ) { statics = astMalloc( sizeof( Map2Statics ) ); if( statics ) { statics->pset1 = NULL; statics->pset2 = NULL; statics->ptr2 = NULL; statics->ptr1[ 0 ] = NULL; statics->ptr1[ 1 ] = NULL; statics->nl = 0; Map2_statics = statics; } } /* If the number of points to be mapped is different to last time, set up some PointSets to store the specified number of points. */ if( n != statics->nl ){ statics->nl = n; /* Create a PointSet to hold the graphics coordinates corresponding to the supplied offsets. The supplied arrays will be used to hold the data for this PointSet, and so astGetPoints is not called. */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); statics->pset1 = astPointSet( n, 2, "", status ); /* Create a PointSet to hold the corresponding physical coordinates, and get pointers to the associated axis values. */ if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); statics->pset2 = astPointSet( n, Map2_ncoord, "", status ); statics->ptr2 = astGetPoints( statics->pset2 ); } /* Check the initialisation went OK (if done). */ if( astOK ){ /* Store pointers to the results arrays in PointSet 1. */ statics->ptr1[ 0 ] = x; statics->ptr1[ 1 ] = y; astSetPoints( statics->pset1, statics->ptr1 ); /* Loop round each offset along the curve, converting the normalised offset in the range [0,1] to graphics coordinate and storing in PointSet 1. */ px = x; py = y; for( i = 0; i < n; i++){ *(px++) = Map2_x0 + Map2_deltax*dist[ i ]; *(py++) = Map2_y0 + Map2_deltay*dist[ i ]; } /* Map all the positions into physical coordinates. */ (void) Trans( Map2_plot, NULL, Map2_map, statics->pset1, 1, statics->pset2, 0, method, class, status ); /* Check the physical coordinates for bad values, setting the corresponding graphics coordinates bad. */ for( j = 0; j < Map2_ncoord; j++ ){ p = statics->ptr2[ j ]; px = x; py = y; for( i = 0; i < n; i++){ if( *(p++) == AST__BAD ){ *(px++) = AST__BAD; *(py++) = AST__BAD; } else { px++; py++; } } } } /* Return. */ return; } static void Map3( int n, double *dist, double *x, double *y, const char *method, const char *class, int *status GLOBALS_ARG ){ /* * Name: * Map3 * Purpose: * Find graphics coordinates at given distances along a geodesic curve * between two physical coordinate positions. * Type: * Private function. * Synopsis: * #include "plot.h" * void Map3( int n, double *dist, double *x, double *y, * const char *method, const char *class, * int *status [,AstGlobals *AST__GLOBALS] ) * Class Membership: * Plot member function. * Description: * The supplied distances are converted into physical offsets along the * geodesic curve joining the starting and finishing points given by * externals Map3_origin and Map3_end. The physical coordinates at these * offsets are found, and transformed into graphics coordinates. * Parameters: * n * The number of points to map. Static resources are released but * no points are mapped if zero is supplied. * dist * A pointer to an array holding "n" distances. A "dist" value of * zero corresponds to the starting position supplied in external * variable Map3_origin. A "dist" value of one corresponds to the * finishing position given by Map3_end. * x * A pointer to an array in which to store the "n" graphics X * coordinate values corresponding to the positions in "dist". * y * A pointer to an array in which to store the "n" graphics Y * coordinate values corresponding to the positions in "dist". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * AST__GLOBALS * Only present if compiled with -DTHREAD_SAFE. It is a pointer to * the structure holding the global data for the executing thread. * It is passed as a function parameter, rather than being accessed * within this function using the astGET_GLOBALS(NULL) macro (as * other Object-less functions do) in order to avoid the time * overheads of calling astGET_GLOBALS(NULL) . This function is * time-critical. * External Variables: * Map3_ncoord = int (Read) * The number of axes in the physical coordinate system. * Map3_origin = const double * (Read) * A pointer to an array holding the physical coordinate value on * each axis at the start of the curve (i.e. at dist = 0.0). * Map3_end = const double * (Read) * A pointer to an array holding the physical coordinate value on * each axis at the end of the curve (i.e. at dist = 1.0). * Map3_scale = double (Read) * The scale factor to convert "dist" values into physical offsets * along the geodesic curve. * Map3_statics = Map3Statics * (Read and Write) * Pointer to a structure holding other static data used by Map3. * Map3_plot = AstPlot * (Read) * A pointer to the Plot defining the mapping from graphics cordinates * to physical coordinates. * Map3_map = AstMapping * (Read) * A pointer to the mapping from graphics cordinates to physical * coordinates extracted from the Plot. * Map3_frame = AstFrame * (Read) * A pointer to the Current Frame in the Plot. * Notes: * - On the first call, this function allocates static resources which * are used by subsequent invocation. These resources should be freed before * calling this function with new values for any of the external variables, * or when no longer needed, by calling this function with "n" supplied as * zero. * - If an error has already occurred, this runction returns without * action ,except that if "n" is supplied as zero then static resources * are released even if an error has already occurred. */ /* Local Constants: */ Map3Statics *statics; /* Pointer to structure holding static data */ int i, j; /* Loop counts */ /* Convert the global "void *" pointer to a Map3Statics pointer */ statics = (Map3Statics *) Map3_statics; /* If zero points were supplied, release static resources and return. */ if( n == 0 ){ if( statics ) { if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); if( statics->pos ) statics->pos = (double *) astFree( (void *) statics->pos ); Map3_statics = astFree( statics ); } return; } /* Otherwise, check the inherited global status. */ if( !astOK ) return; /* Create and initialise a structure to hold extra static information if this has not already been done. */ if( !statics ) { statics = astMalloc( sizeof( Map3Statics ) ); if( statics ) { statics->pset1 = NULL; statics->pset2 = NULL; statics->ptr1 = NULL; statics->ptr2[ 0 ] = NULL; statics->ptr2[ 1 ] = NULL; statics->nc = 0; statics->nl = 0; statics->pos = NULL; Map3_statics = statics; } } /* If the number of points to be mapped is different to last time, set up some PointSets to store the specified number of points. */ if( n != statics->nl ){ statics->nl = n; /* Create a PointSet to hold the physical coordinates corresponding to the supplied offsets. First annul any existing PointSet. */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); statics->pset1 = astPointSet( n, Map3_ncoord, "", status ); statics->ptr1 = astGetPoints( statics->pset1 ); /* Create a PointSet to hold the corresponding graphics coordinates. The supplied "x" and "y" arrays will be used to store the data so we do not need to get pointers to the data using astGetPoints. First annul any existing PointSet. */ if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); statics->pset2 = astPointSet( n, 2, "", status ); } /* If the number of physical axes is different to last time, allocate memory to hold a single physical position. */ if( statics->nc != Map3_ncoord ){ statics->nc = Map3_ncoord; statics->pos = (double *) astMalloc( sizeof(double)*(size_t)Map3_ncoord ); } /* Check the initialisation went OK (if done). */ if( astOK ){ /* Loop round each offset along the curve, converting the normalised offset in the range [0,1] to a physical offset, and then into a physical position, and store in PointSet 1. */ for( i = 0; i < n; i++){ astOffset( Map3_frame, Map3_origin, Map3_end, Map3_scale*dist[ i ], statics->pos ); for( j = 0; j < Map3_ncoord; j++ ){ statics->ptr1[ j ][ i ] = statics->pos[ j ]; } } /* Store pointers to the results arrays in PointSet 2. */ statics->ptr2[ 0 ] = x; statics->ptr2[ 1 ] = y; astSetPoints( statics->pset2, statics->ptr2 ); /* Map all the positions into graphics coordinates. */ (void) Trans( Map3_plot, NULL, Map3_map, statics->pset1, 0, statics->pset2, 1, method, class, status ); } /* Return. */ return; } static void Map4( int n, double *dist, double *x, double *y, const char *method, const char *class, int *status GLOBALS_ARG ){ /* * Name: * Map4 * Purpose: * Find graphics coordinates at given distances along a user * specified curve. * Type: * Private function. * Synopsis: * #include "plot.h" * void Map4( int n, double *dist, double *x, double *y, * const char *method, const char *class, * int *status [,AstGlobals *AST__GLOBALS] ) * Class Membership: * Plot member function. * Description: * The supplied distances are converted into physical coordinates using * the Mapping Map4_umap. These physical coordinates are transformed into * graphics coordinates. * Parameters: * n * The number of points to map. Static resources are released but * no points are mapped if zero is supplied. * dist * A pointer to an array holding "n" distances. A "dist" value of * zero corresponds to the starting position supplied in external * variable Map3_origin. A "dist" value of one corresponds to the * finishing position given by Map3_end. * x * A pointer to an array in which to store the "n" graphics X * coordinate values corresponding to the positions in "dist". * y * A pointer to an array in which to store the "n" graphics Y * coordinate values corresponding to the positions in "dist". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * AST__GLOBALS * Only present if compiled with -DTHREAD_SAFE. It is a pointer to * the structure holding the global data for the executing thread. * It is passed as a function parameter, rather than being accessed * within this function using the astGET_GLOBALS(NULL) macro (as * other Object-less functions do) in order to avoid the time * overheads of calling astGET_GLOBALS(NULL) . This function is * time-critical. * External Variables: * Map4_ncoord = int (Read) * The number of axes in the physical coordinate system. * Map4_plot = AstPlot * (Read) * A pointer to the Plot defining the mapping from graphics cordinates * to physical coordinates. * Map4_map = AstMapping * (Read) * A pointer to the mapping from graphics cordinates to physical * coordinates extracted from the Plot. * Map4_statics = Map4Statics * (Read and Write) * Pointer to a structure holding other static data used by Map4. * Map4_umap = AstMapping * (Read) * A pointer to the mapping from distance along the curve to physical * coordinates. * Notes: * - On the first call, this function allocates static resources which * are used by subsequent invocation. These resources should be freed before * calling this function with new values for any of the external variables, * or when no longer needed, by calling this function with "n" supplied as * zero. * - If an error has already occurred, this runction returns without * action ,except that if "n" is supplied as zero then static resources * are released even if an error has already occurred. */ /* Local Variables: */ Map4Statics *statics; /* Pointer to structure holding static data */ double *ptr1[ 1 ]; /* Pointer to distances data */ double *ptr3[ 2 ]; /* Pointers to graphics coord data */ /* Convert the global "void *" pointer to a Map4Statics pointer */ statics = (Map4Statics *) Map4_statics; /* If zero points were supplied, release static resources and return. */ if( n == 0 ){ if( statics ) { if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); if( statics->pset3 ) statics->pset3 = astAnnul( statics->pset3 ); Map4_statics = astFree( statics ); } return; } /* Otherwise, check the inherited global status. */ if( !astOK ) return; /* Create and initialise a structure to hold extra static information if this has not already been done. */ if( !statics ) { statics = astMalloc( sizeof( Map4Statics ) ); if( statics ) { statics->pset1 = NULL; statics->pset2 = NULL; statics->pset3 = NULL; statics->nl = 0; Map4_statics = statics; } } /* If the number of points to be mapped is different to last time, set up some PointSets to store the specified number of points. */ if( n != statics->nl ){ statics->nl = n; /* Create a PointSet to hold the distances along the curve. First annul any existing PointSet. */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); statics->pset1 = astPointSet( n, 1, "", status ); /* Create a PointSet to hold the physical coordinates corresponding to the supplied distances. First annul any existing PointSet. */ if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); statics->pset2 = astPointSet( n, Map4_ncoord, "", status ); /* Create a PointSet to hold the corresponding graphics coordinates. First annul any existing PointSet. */ if( statics->pset3 ) statics->pset3 = astAnnul( statics->pset3 ); statics->pset3 = astPointSet( n, 2, "", status ); } /* Check the initialisation went OK (if done). */ if( astOK ){ /* Use Map4_umap to convert the supplied distances into physical coords (i.e. coords in the current Frame of the Plot). */ ptr1[ 0 ] = dist; astSetPoints( statics->pset1, ptr1 ); (void) astTransform( Map4_umap, statics->pset1, 1, statics->pset2 ); /* Store pointers to the results arrays in PointSet 2. */ ptr3[ 0 ] = x; ptr3[ 1 ] = y; astSetPoints( statics->pset3, ptr3 ); /* Now transform these physical coords into graphical coords, incorporating clipping. */ (void) Trans( Map4_plot, NULL, Map4_map, statics->pset2, 0, statics->pset3, 1, method, class, status ); } /* Return. */ return; } static void Map5( int n, double *dist, double *x, double *y, const char *method, const char *class, int *status GLOBALS_ARG ){ /* * Name: * Map5 * Purpose: * Find graphics coordinates at given distances along the boundary of * a Region. * Type: * Private function. * Synopsis: * #include "plot.h" * void Map5( int n, double *dist, double *x, double *y, * const char *method, const char *class, * int *status [,AstGlobals *AST__GLOBALS] ) * Class Membership: * Plot member function. * Description: * The supplied distances are converted into physical coordinates * using the Region specified by an external variable, and then * these physical coordinates are mapped into graphics coordinates. * Parameters: * n * The number of points to map. Static resources are released but * no points are mapped if zero is supplied. * dist * A pointer to an array holding "n" distances. A "dist" value of * zero corresponds to the starting position supplied in external * variable Map1_origin. A "dist" value of one corresponds to the * finishing position which is a distance Map1_length away from * Map1_origin, moving in the positive direction of the axis given * by Map1_axis. "dist" values can be either linearly or * logarithmically related to axis values (see Map1_log). * x * A pointer to an array in which to store the "n" graphics X * coordinate values corresponding to the positions in "dist". * y * A pointer to an array in which to store the "n" graphics Y * coordinate values corresponding to the positions in "dist". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * AST__GLOBALS * Only present if compiled with -DTHREAD_SAFE. It is a pointer to * the structure holding the global data for the executing thread. * It is passed as a function parameter, rather than being accessed * within this function using the astGET_GLOBALS(NULL) macro (as * other Object-less functions do) in order to avoid the time * overheads of calling astGET_GLOBALS(NULL) . This function is * time-critical. * External Variables: * Map1_log = int (Read) * If zero, then "dist" in learly related to axis value. Otherwise * it is linearly related to log10(axis value). * Map1_ncoord = int (Read) * The number of axes in the physical coordinate system. * Map1_axis = int (Read) * The zero-based index of the axis which the curve follows (i.e. * the axis which changes value along the curve). * Map1_statics = Map1Statics * (Read and Write) * Pointer to a structure holding other static data used by Map1. * Map1_origin = const double * (Read) * A pointer to an array holding the physical coordinate value on * each axis at the start of the curve (i.e. at dist = 0.0). * Map1_length = double (Read) * The scale factor to convert "dist" values into increments * along the physical axis given by Map1_axis. * Map1_plot = AstPlot * (Read) * A pointer to the Plot defining the mapping from graphics cordinates * to physical coordinates. * Map1_map = AstMapping * (Read) * A pointer to the mapping from graphics cordinates to physical * coordinates extracted from the Plot. * Map1_frame = AstFrame * (Read) * A pointer to the Current Frame in the Plot. * Map1_norm = int (Read) * A flag indicating if physical coordinate values which are not in * the normal ranges of the corresponding axes should be considered * bad. * Notes: * - On the first call, this function allocates static resources which * are used by subsequent invocation. These resources should be freed before * calling this function with new values for any of the external variables, * or when no longer needed, by calling this function with "n" supplied as * zero. * - If an error has already occurred, this runction returns without * action ,except that if "n" is supplied as zero then static resources * are released even if an error has already occurred. */ /* Local Constants: */ Map5Statics *statics; /* Pointer to structure holding static data */ /* Convert the global "void *" pointer to a Map5Statics pointer */ statics = (Map5Statics *) Map5_statics; /* If zero points were supplied, release static resources and return. */ if( n == 0 ){ if( statics ) { if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); Map5_statics = astFree( statics ); } return; } /* Otherwise, check the inherited global status. */ if( !astOK ) return; /* Create and initialise a structure to hold extra static information if this has not already been done. */ if( !statics ) { statics = astMalloc( sizeof( Map3Statics ) ); if( statics ) { statics->pset1 = NULL; statics->pset2 = NULL; statics->ptr1 = NULL; statics->ptr2[ 0 ] = NULL; statics->ptr2[ 1 ] = NULL; statics->nl = 0; Map5_statics = statics; } } /* If the number of points to be mapped is different to last time, set up some PointSets to store the specified number of points. */ if( n != statics->nl ){ statics->nl = n; /* Create a PointSet to hold the physical coordinates corresponding to the supplied offsets. First annul any existing PointSet. */ if( statics->pset1 ) statics->pset1 = astAnnul( statics->pset1 ); statics->pset1 = astPointSet( n, Map5_ncoord, "", status ); statics->ptr1 = astGetPoints( statics->pset1 ); /* Create a PointSet to hold the corresponding graphics coordinates. The supplied "x" and "y" arrays will be used to store the data so we do not need to get pointers to the data using astGetPoints. First annul any existing PointSet. */ if( statics->pset2 ) statics->pset2 = astAnnul( statics->pset2 ); statics->pset2 = astPointSet( n, 2, "", status ); } /* Get the physical coords at the required positions along the Region border. */ astRegTrace( Map5_region, n, dist, statics->ptr1 ); /* Store pointers to the results arrays in PointSet 2. */ statics->ptr2[ 0 ] = x; statics->ptr2[ 1 ] = y; astSetPoints( statics->pset2, statics->ptr2 ); /* Map all the positions into graphics coordinates. */ (void) Trans( Map5_plot, NULL, Map5_map, statics->pset1, 0, statics->pset2, 1, method, class, status ); /* Return. */ return; } static void Mark( AstPlot *this, int nmark, int ncoord, int indim, const double *in, int type, int *status ){ /* *++ * Name: c astMark f AST_MARK * Purpose: * Draw a set of markers for a Plot. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astMark( AstPlot *this, int nmark, int ncoord, int indim, c const double *in, int type ) f CALL AST_MARK( THIS, NMARK, NCOORD, INDIM, IN, TYPE, STATUS ) * Class Membership: * Plot method. * Description: c This function draws a set of markers (symbols) at positions f This routine draws a set of markers (symbols) at positions * specified in the physical coordinate system of a Plot. The * positions are transformed into graphical coordinates to * determine where the markers should appear within the plotting * area. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c nmark f NMARK = INTEGER (Given) * The number of markers to draw. This may be zero, in which * case nothing will be drawn. c ncoord f NCOORD = INTEGER (Given) * The number of coordinates being supplied for each mark * (i.e. the number of axes in the current Frame of the Plot, as * given by its Naxes attribute). c indim f INDIM = INTEGER (Given) c The number of elements along the second dimension of the "in" f The number of elements along the first dimension of the IN * array (which contains the marker coordinates). This value is * required so that the coordinate values can be correctly * located if they do not entirely fill this array. The value c given should not be less than "nmark". f given should not be less than NMARK. c in f IN( INDIM, NCOORD ) = DOUBLE PRECISION (Given) c The address of the first element of a 2-dimensional array of c shape "[ncoord][indim]" giving the c physical coordinates of the points where markers are to be c drawn. These should be stored such that the value of c coordinate number "coord" for input mark number "mark" is c found in element "in[coord][mark]". f A 2-dimensional array giving the physical coordinates of the f points where markers are to be drawn. These should be f stored such that the value of coordinate number COORD for f input mark number MARK is found in element IN(MARK,COORD). c type f TYPE = INTEGER (Given) * A value specifying the type (e.g. shape) of marker to be * drawn. The set of values which may be used (and the shapes * that will result) is determined by the underlying graphics * system. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Markers are not drawn at positions which have any coordinate * equal to the value AST__BAD (or where the transformation into * graphical coordinates yields coordinates containing the value * AST__BAD). c - If any marker position is clipped (see astClip), then the f - If any marker position is clipped (see AST_CLIP), then the * entire marker is not drawn. * - An error results if the base Frame of the Plot is not 2-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMapping *mapping; /* Pointer to graphics->physical mapping */ AstPointSet *pset1; /* PointSet holding physical positions */ AstPointSet *pset2; /* PointSet holding graphics positions */ const char *class; /* Object class */ const char *method; /* Current method */ const double **ptr1; /* Pointer to physical positions */ double **ptr2; /* Pointer to graphics positions */ double *xpd; /* Pointer to next double precision x value */ double *ypd; /* Pointer to next double precision y value */ double xx; /* X axis value */ double yy; /* Y axis value */ float *x; /* Pointer to single precision x values */ float *xpf; /* Pointer to next single precision x value */ float *y; /* Pointer to single precision y values */ float *ypf; /* Pointer to next single precision y value */ int axis; /* Axis index */ int clip; /* Clips marks at plot boundary? */ int i; /* Loop count */ int naxes; /* No. of axes in the base Frame */ int nn; /* Number of good marker positions */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method and class for inclusion in error messages generated by lower level functions. */ method = "astMark"; class = astClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Also validate the input array dimension argument. */ if ( astOK && ( indim < nmark ) ) { astError( AST__DIMIN, "%s(%s): The input array dimension value " "(%d) is invalid.", status, method, class, indim ); astError( AST__DIMIN, "This should not be less than the number of " "markers being drawn (%d).", status, nmark ); } /* Initialise the bounding box for primatives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__MARKS_ID, 1, GRF__MARK, method, class ); /* Create a PointSet to hold the supplied physical coordinates. */ pset1 = astPointSet( nmark, ncoord, "", status ); /* Allocate memory to hold pointers to the first value on each axis. */ ptr1 = (const double **) astMalloc( sizeof( const double * )* (size_t)( ncoord )); /* Check the pointer can be used, then store pointers to the first value on each axis. */ if( astOK ){ for( axis = 0; axis < ncoord; axis++ ){ ptr1[ axis ] = in + axis*indim; } } /* Store these pointers in the PointSet. */ astSetPoints( pset1, (double **) ptr1 ); /* Transform the supplied data from the current frame (i.e. physical coordinates) to the base frame (i.e. graphics coordinates) using the inverse Mapping defined by the Plot. */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); pset2 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); mapping = astAnnul( mapping ); /* Get pointers to the graphics coordinates. */ ptr2 = astGetPoints( pset2 ); /* Allocate memory to hold single precision versions of the graphics coordinates. */ x = (float *) astMalloc( sizeof( float )*(size_t) nmark ); y = (float *) astMalloc( sizeof( float )*(size_t) nmark ); /* Check the pointers can be used. */ if( astOK ){ /* Store pointers to the next single and double precision x and y values. */ xpf = x; ypf = y; xpd = ptr2[ 0 ]; ypd = ptr2[ 1 ]; /* Convert the double precision values to single precision, rejecting any bad marker positions. If clipping is switched on, also clip any markers with centres outside the plotting area. */ clip = astGetClip( this ) & 2; nn = 0; for( i = 0; i < nmark; i++ ){ if( *xpd != AST__BAD && *ypd != AST__BAD ){ xx = *(xpd++); yy = *(ypd++); if( !clip || ( xx >= this->xlo && xx <= this->xhi && yy >= this->ylo && yy <= this->yhi ) ) { nn++; *(xpf++) = (float) xx; *(ypf++) = (float) yy; } } else { xpd++; ypd++; } } /* Draw the remaining markers. */ GMark( this, nn, x, y, type, method, class, status ); } /* Free the memory used to store single precision graphics coordinates. */ x = (float *) astFree( (void *) x ); y = (float *) astFree( (void *) y ); /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Free the memory holding the pointers to the first value on each axis. */ ptr1 = (const double **) astFree( (void *) ptr1 ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__MARKS_ID, 0, GRF__MARK, method, class ); /* Return */ return; } static void Mirror( AstPlot *this, int axis, int *status ){ /* *+ * Name: * astMirror * Purpose: * Flip a graphics axis of a Plot. * Type: * Protected virtual function. * Synopsis: * #include "plot.h" * void astMirror( AstPlot *this, int axis ) * Class Membership: * Plot method. * Description: * This function referses the direction of a specified graphics axis * in the Plot. * Parameters: * this * Pointer to a Plot. * axis * The zero-based axis of the axis to mirror. *- */ /* Check the global status. */ if( !astOK ) return; if( axis == 0 ) { this->xrev = ( this->xrev == 0 ); } else if( axis == 1 ){ this->yrev = ( this->yrev == 0 ); } else { astError( AST__INTER, "astMirror(%s): Illegal axis index (%d) " "supplied (internal AST programming error).", status, astGetClass( this ), axis ); } } static void Norm1( AstMapping *map, int axis, int nv, double *vals, double refval, double width, int *status ){ /* * Name: * Norm1 * Purpose: * Use a Mapping to normalize an array of axis values. * Type: * Private function. * Synopsis: * #include "plot.h" * void Norm1( AstMapping *map, int axis, int nv, double *vals, * double refval, double width, int *status ) * Class Membership: * Plot member function. * Description: * The normalization of a position in physical space has two parts; * firstly, the Mapping may determine a form of normalization; * secondly, the Frame may provide an additional normalizion by the * astNorm method. This function implements normalization using a * Mapping, by transforming the physical position into Graphics position, * and then back into a physical position. For instance, if the Mapping * represents a mapping of Cartesian graphics axes onto a 2D polar * coordinate system, a physical theta value of 3.PI will be normalized by * the Mapping into a theta value of 1.PI (probably, but it depends on * the Mapping). In this case, the Mapping normalization may well be the * only normalization available, since the 2D polar coord. system will * probably use a simple Frame to represent the (radius,theta) system, * and a simple Frame defines no normalization (i.e. the astNorm method * returns the supplied position unchanged). * * Complications arise though because it is not possible to normalise * a single axis value - you can only normalize a complete position. * Therefore some value must be supplied for the other axis. We * should use the LabelAt value, but we do not yet know what the LabelAt * value will be. Instead, we try first using the supplied "refval" * which should be close to the mode of the other aixs values. Usually * the value used is not very important. However, for some complex * projections (such as quad-cubes, TSC, etc) the choice can be more * critical since some positions on the ksy correspond to undefined * graphics positions (e.g the face edges in a TSC projection). * Therefore, if the supplied refval results in any positions being * undefined we refine the process by transforming the undefined * positaons again using a different refval. We do this twice to bump * up the likelihood of finding a suitable reference value. * Parameters: * mapping * The Mapping from Graphics Frame to the current Frame. * axis * The index of the axis for which values are supplied in "vals". * nv * The number of values supplied in "vals". * vals * Pointer to an array of axis values. On exit they are normalized. * refval * The preffered constant value to use for the other axis when * normalizing the values in "vals". * width * The range of used values for the other axis. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPointSet *pset1; /* PointSet holding physical coords */ AstPointSet *pset2; /* PointSet holding graphics coords */ double **ptr1; /* Pointer to physical coords data */ double *a; /* Pointer to next axis value */ double *b; /* Pointer to next axis value */ int i; /* Loop count */ int itry; /* Loop count for re-try loop */ int nbad; /* No. of bad values found after transformation */ int *flags; /* Pointer to flags array */ /* Check the inherited global status. */ if( !astOK ) return; /* Store the supplied positions in a PointSet. */ pset1 = astPointSet( nv, 2, "", status ); ptr1 = astGetPoints( pset1 ); if( astOK ) { a = ptr1[ axis ]; b = ptr1[ 1 - axis ]; for( i = 0; i < nv; i++){ *(a++) = vals[ i ]; *(b++) = refval; } } /* Transform the supplied positions into the Base Frame. */ pset2 = astTransform( map, pset1, 0, NULL ); /* Transform the Base Frame positions back into the Current Frame. */ (void) astTransform( map, pset2, 1, pset1 ); /* Allocate memory to hold a flag for each position which is non-zero if we currently have a good axis value to return for the position. */ flags = (int *) astMalloc( sizeof(int)* (size_t) nv ); /* If good, store these values back in the supplied array. If the transformed values are bad, retain the original good values for the moment in "vals", and also copy the good values back into pset1. So at the end, pset1 will contain the original good values at any points which produced bad values after the above transformation - the other points in pset1 will be bad. */ nbad = 0; if( astOK ) { a = ptr1[ axis ]; for( i = 0; i < nv; i++, a++ ){ if( *a != AST__BAD ) { vals[ i ] = *a; *a = AST__BAD; flags[ i ] = 1; } else if( vals[ i ] != AST__BAD ) { nbad++; *a = vals[ i ]; flags[ i ] = 0; } else { flags[ i ] = 1; } } } /* We now try normalising any remaining bad positions using different values for the other axis. This may result in some or all of the remaining points being normalised succesfully. */ for( itry = 0; itry < 10; itry++ ) { /* If the above transformation produced any bad values, try again with a different value on the other axis. */ if( astOK && nbad > 0 ) { b = ptr1[ 1 - axis ]; for( i = 0; i < nv; i++){ *(b++) = refval + 0.1*( itry + 1 )*width; } /* Transform to graphics coords and back to world coords. */ (void) astTransform( map, pset1, 0, pset2 ); (void) astTransform( map, pset2, 1, pset1 ); /* Copy any good positions back into the returned vals array. Count remaining bad positions. */ a = ptr1[ axis ]; nbad = 0; for( i = 0; i < nv; i++, a++ ){ if( *a != AST__BAD ) { vals[ i ] = *a; flags[ i ] = 1; *a = AST__BAD; } else if( !flags[ i ] ) { nbad++; *a = vals[ i ]; } } } /* If the above transformation produced any bad values, try again with a different value on the other axis. */ if( astOK && nbad > 0 ) { b = ptr1[ 1 - axis ]; for( i = 0; i < nv; i++){ *(b++) = refval - 0.1*( itry + 1 )*width; } /* Transform to graphics coords and back to world coords. */ (void) astTransform( map, pset1, 0, pset2 ); (void) astTransform( map, pset2, 1, pset1 ); /* Copy any good positions back into the returned vals array. Count remaining bad positions. */ a = ptr1[ axis ]; nbad = 0; for( i = 0; i < nv; i++, a++ ){ if( *a != AST__BAD ) { vals[ i ] = *a; flags[ i ] = 1; *a = AST__BAD; } else if( !flags[ i ] ) { nbad++; *a = vals[ i ]; } } } } /* Free resources. */ flags = (int *) astFree( flags ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); } static void Opoly( AstPlot *this, int *status ){ /* * Name: * Opoly * Purpose: * Draws the current poly line. * Type: * Private function. * Synopsis: * #include "plot.h" * void Opoly( AstPlot *this, int *status ) * Class Membership: * Plot member function. * Description: * This function draws the current poly line, and empties the buffer. * Parameters: * this * Pointer to the Plot. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int ipoly; /* Index of new polyline */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Draw the poly-line if needed. */ if( Poly_n > 0 ) { /* Extend the global arrays that hold pointers to the polylines already drawn. */ ipoly = Poly_npoly++; astBeginPM; Poly_xp = astGrow( Poly_xp, Poly_npoly, sizeof(float*) ); Poly_yp = astGrow( Poly_yp, Poly_npoly, sizeof(float*) ); Poly_np = astGrow( Poly_np, Poly_npoly, sizeof(int) ); astEndPM; if( astOK ) { /* Add pointers to the new polyline to the end of the above extended arrays. */ Poly_xp[ ipoly ] = Poly_x; Poly_yp[ ipoly ] = Poly_y; Poly_np[ ipoly ] = Poly_n; /* Indicate that the current polyline is now empty. */ Poly_x = NULL; Poly_y = NULL; Poly_n = 0; } } } static int Overlap( AstPlot *this, int mode, int esc, const char *text, float x, float y, const char *just, float upx, float upy, float **work, const char *method, const char *class, int *status ){ /* * Name: * Overlap * Purpose: * See if a major tick value label would overlap any of the previously * drawn labels. * Type: * Private function. * Synopsis: * #include "plot.h" * int Overlap( AstPlot *this, int mode, int esc, const char *text, float x, * float y, const char *just, float upx, float upy, * float **work, const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * The operation of this function is determined by the "mode" parameter. * A record is kept of the bounding boxes enclosing all the displayed * labels. If the bounding box of the new label defined by the given * parameter values would overlap any of the old bounding boxes, 0 is * returned. Otherwise 1 is returned and the bounding box for the new * label is added to the list of old bounding boxes. * This function also updates the external variables Box_lbnd and * Box_ubnd which hold the lower and upper bounds of the area enclosing * all used labels. * Parameters: * this * A pointer to the Plot. * mode * - If -1, find the bounding box of the supplied label, add it * to the list of stored bounding box, and return 1 if it overlaps * any previously stored bounding boxes. * - If -2, leave the bounding boxes unchanged and return the * number of bounding boxes currently stored. No other action is taken * and all other arguments are ignored. * - Otherwise, reset the number of stored bounding boxes to the * value of mode, and return the new number of bounding boxes. No * action is taken if mode is less than zero or greater than the current * number of stored boxes. No other action is taken and all other * arguments are ignored. * esc * Should escape sequences in the text be interpreted? * text * A pointer to the label text string. * x * The graphics X coordinate of the label's reference point. * y * The graphics Y coordinate of the label's reference point. * 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. 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. * upx * The x component of the up-vector for the text. * upy * The y component of the up-vector for the text. * work * A pointer to a place at which to store a pointer to an array of * floats holding the old bounding boxes. Memory to hold this array * is allocated automatically within this function. The pointer to * the array should be supplied as NULL on the first call to this * function, and the array should be freed using astFree when no * longer needed. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * See parameter "mode." * Notes: * - Zero is returned if an error has occurred, or if this function * should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int nbox = 0; /* Number of boxes stored in "work" */ int ret; /* Does the new label overlap a previous label? */ int i; /* Box index */ float *cx; /* Pointer to next corner's X value */ float *cy; /* Pointer to next corner's Y value */ float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Initialise the returned value to indicate no overlap has been found. */ ret = 0; /* Get the number of bounding boxes in the supplied work array. */ if( work && *work ) { nbox = (*work)[ 0 ]; } else { nbox = 0; } /* If required, return the number of bounding boxes currently stored. */ if( mode == -2 ) return nbox; /* If required, reset the number of bounding boxes currently stored, and return the new number. */ if( mode >= 0 ) { if( mode < nbox && work && *work ) { nbox = mode; (*work)[ 0 ] = nbox; } return nbox; } /* If no work array has been supplied, allocate one now with room for 10 boxes. Each box requires 8 floats, 2 for each of the 4 corners. The X graphics coordinates at the 4 corners are stored in the first 4 floats, and the corresponding Y graphics coordinates in the second group of 4 floats. */ if( work && !(*work) ) { *work = (float *) astMalloc( 81*sizeof(float) ); if( astOK ) { nbox = 0; (*work)[ 0 ] = 0; } } /* Check the global status. */ if( !astOK ) return ret; /* Get the bounds of the box containing the new label. */ DrawText( this, 0, esc, text, x, y, just, upx, upy, xbn, ybn, NULL, method, class, status ); /* If the bounding box was obtained succesfully... */ if( astOK ) { /* Check for an overlap between the box and each of the previous boxes. */ cx = *work + 1; cy = cx + 4; for( i = 0; i < nbox; i++ ){ if( BoxCheck( xbn, ybn, cx, cy, status ) ) { ret = 1; break; } /* Increment the pointers to the next box. */ cx += 8; cy += 8; } /* If no overlap was found, add the new box to the list. */ if( !ret ){ *work = (float *) astGrow( (void *) *work, 8*nbox + 9, sizeof(float) ); cx = *work + 1 + 8*nbox; cy = cx + 4; for( i = 0; i < 4; i++ ){ cx[ i ] = xbn[ i ]; cy[ i ] = ybn[ i ]; } (*work)[ 0 ]++; /* Extend the bounds of the global bounding box held externally to include the new box. */ for( i = 0; i < 4; i++ ){ Box_lbnd[ 0 ] = MIN( xbn[ i ], Box_lbnd[ 0 ] ); Box_ubnd[ 0 ] = MAX( xbn[ i ], Box_ubnd[ 0 ] ); Box_lbnd[ 1 ] = MIN( ybn[ i ], Box_lbnd[ 1 ] ); Box_ubnd[ 1 ] = MAX( ybn[ i ], Box_ubnd[ 1 ] ); } } } /* If an error has occur, return a value of 0. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static void PlotLabels( AstPlot *this, int esc, AstFrame *frame, int axis, LabelList *list, char *fmt, int nlab, float **box, const char *method, const char *class, int *status ) { /* * * Name: * PlotLabels * Purpose: * Draws the numerical labels which have been selected for display. * Type: * Private function. * Synopsis: * #include "plot.h" * void PlotLabels( AstPlot *this, int esc, AstFrame *frame, int axis, * LabelList *list, char *fmt, int nlab, float **box, * const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function displays the numerical labels supplied in the * structure pointed to by "list". Overlapping labels are omitted, * and redundant leading fields are removed from adjacent labels. * Nothing is plotted if the NumLab attribute for the axis is false. * Parameters: * this * A pointer to the Plot. * esc * Interpret escape sequences in labels? * frame * A pointer to the current Frame of the Plot. * axis * The axis index (0 or 1). * list * A pointer to the LabelList structure holding information about * the selected numerical labels. * fmt * A pointer to a null terminated string holding the format * specification used to create the labels. * nlab * The number of labels described by "list". * box * A pointer to a place at which to store a pointer to an array of * floats holding the bounding boxes of displayed labels. Memory to * hold this array is allocated automatically within this function. * The pointer to the array should be supplied as NULL on the first * call to this function, and the array should be freed using astFree * when no longer needed. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ LabelList *ll; /* Pointer to next label structure */ LabelList *llhi; /* Pointer to higher neighbouring label structure */ LabelList *lllo; /* Pointer to lower neighbouring label structure */ char *text; /* Pointer to label text */ const char *latext; /* Axis label at previous label */ const char *texthi; /* Pointer to text abbreviated with higher neighbour */ const char *textlo; /* Pointer to text abbreviated with lower neighbour */ float tolx; /* Min allowed X interval between labels */ float toly; /* Min allowed Y interval between labels */ float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ int abb; /* Abbreviate leading fields? */ int dp; /* Number of decimal places */ int found; /* Non-zero digit found? */ int hilen; /* Length of texthi */ int i; /* Label index */ int j; /* Label index offset */ int jgap; /* Gap in index between rejected labels */ int lab0; /* Index of middle label */ int lolen; /* Length of textlo */ int mxdp; /* Maximum number of decimal places */ int nbox; /* The number of boinding boxes supplied */ int nexti; /* Index of next label to retain */ int nleft; /* No. of labels left */ int nz; /* Number of trailing zeros in this label */ int nzmax; /* Max. number of trailing zeros */ int odd; /* DO we have a strange axis? */ int olap; /* Any overlap found? */ int prio; /* Current priority */ int root; /* Index of unabbreviated label */ int root_found; /* Has the root label been decided on? */ int rootoff; /* Distance from middle to root label */ int split; /* Indicates whether to split labels into 2 lines */ /* Return without action if an error has occurred, or there are no labels to draw. */ if( !astOK || nlab == 0 || !list || !astGetNumLab( this, axis ) ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ rootoff = 0; /* Get the number of bounding boxes describing the labels already drawn (this will be non-zero only if this is the second axis to be labelled). */ nbox = Overlap( this, -2, 0, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, method, class, status ); /* Ensure the labels are sorted into increasing index order. */ qsort( (void *) list, (size_t) nlab, sizeof(LabelList), Compare_LL ); /* Complex curves can have multiple edge crossings very close together. This means that the same label can sometimes be included more than once in the supplied list at the same (x,y) position. Purge duplicate labels by setting their priority to -1. Initialise the priority of the remaining labels to zero. */ tolx = 0.02*fabs( this->xhi - this->xlo ); toly = 0.02*fabs( this->yhi - this->ylo ); ll = list; ll->priority = 0; ll->saved_prio = 0; for( i = 1; i < nlab; i++ ) { ll++; ll->priority = 0; ll->saved_prio = 0; for( j = 0; j < i; j++ ){ if( !strcmp( ll->text, list[ j ].text ) ) { if( fabs( ll->x - list[ j ].x ) < tolx && fabs( ll->y - list[ j ].y ) < toly ) { ll->priority = -1; ll->saved_prio = -1; break; } } } } /* Find the maximum number of decimal places in any label. */ mxdp = 0; ll = list - 1; for( i = 0; i < nlab; i++ ) { ll++; FindDPTZ( frame, axis, fmt, ll->text, &dp, &nz, status ); if( dp > mxdp ) mxdp = dp; } /* Indicate that we do not yet know whether SplitValue should split labels into two lines or not. */ split = 0; /* Find the highest priority label (the "root" label). This label is never abbreviated to remove leading fields, and is never omitted due to overlaps with other labels. To find this label, each label is assigned a priority equal to the number of trailing zeros in the label text. If the text has fewer than the maximum number of decimal places, pretend the text is padded with trailing zeros to bring the number of decimal places up to the maximum. The root label is the highest priority label, giving preference to labels which occur in the middle of the index order. At the same time, initialize the abbreviated text for each label to be equal to the unabbreviated text. */ lab0 = nlab/2; nzmax = -1; ll = list - 1; root = -1; root_found = 0; for( i = 0; i < nlab; i++ ) { ll++; if( ll->priority > -1 ) { text = ll->text; /* Find the number of decimal places and the number of trailing zeros in this label. Note if a non-zero digit was found in the label. */ found = FindDPTZ( frame, axis, fmt, text, &dp, &nz, status ); /* Add on some extra trailing zeros to make the number of decimal places up to the maximum value. */ nz += mxdp - dp; /* Store the priority for this label. */ ll->priority = nz; ll->saved_prio = nz; /* Note the highest priority of any label. */ if( nz > nzmax ) nzmax = nz; /* We will use this label as the root label if: - We have not already found the root label AND - It does not overlap any labels drawn for a previous axis AND - We do not currently have a candidate root label, or - The priority for this label is higher than the priority of the current root label, or - The priority for this label is equal to the priority of the current root label and this label is closer to the centre of the axis, or - The label value is zero. */ if( root == -1 || nz > list[ root ].priority || ( nz == list[ root ].priority && abs( i - lab0 ) < rootoff ) || !found ) { if( !root_found ) { if( axis == 0 || !Overlap( this, -1, esc, SplitValue( this, ll->text, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, box, method, class, status ) ) { root = i; rootoff = abs( i - lab0 ); /* If the label value was zero, we will use label as the root label, regardless of the priorities of later labels. */ if( !found ) root_found = 1; } /* Reset the list of bounding boxes to exclude any box added above. */ Overlap( this, nbox, esc, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, method, class, status ); } } /* Initialise the abbreviated text to be the same as the full text. */ ll->atext = ll->text; } } /* If all the labels overlapped labels on a previous axis, arbitrarily use the middle label as the root label (this should never happen but is included to avoid segmentation violations occurring in error conditions such as the txExt function being buggy and cuasing spurious overlaps). */ if( root == -1 ) root = nlab/2; /* Assign a priority higher than any other priority to the root label. */ list[ root ].priority = nzmax + 1; list[ root ].saved_prio = nzmax + 1; /* See if leading fields are to be abbreviated */ abb = astGetAbbrev( this, axis ); /* The following process may have removed some labels which define the missing fields in neighbouring abbreviated fields, so that the user would not be able to tell what value the abbvreviated leading fields should have. We therefore loop back and perform the abbreviation process again, omitting the removed labels this time. Continue doing this until no further labels are removed. */ jgap = 1; olap = 1; odd = 0; while( olap && !odd ) { /* We now attempt to abbreviate the remaining labels (i.e. those which have not been rejected on an earlier pass through this loop). Labels are abbreviated in order of their priority. Higher priority labels are abbreviated first (except that the root label, which has the highest priority, is never abbreviated). Each label is abbreviated by comparing it with the nearest label with a higher priority. */ /* Loop through all the priority values, starting with the highest priority (excluding the root label so that the root label is never abbreviated), and working downwards to finish with zero priority. */ prio = nzmax + 1; while( prio-- > 0 ) { /* Look for labels which have the current priority. */ ll = list - 1; for( i = 0; i < nlab; i++ ) { ll++; if( ll->priority == prio ) { /* Find the closest label to this one on the high index side which has a higher priority. */ llhi = NULL; for( j = i + 1; j < nlab; j++ ) { if( list[ j ].priority > prio ) { llhi = list + j; break; } } /* If no higher priority neighbour was found on the high index side, use the nearest label with the current priority on the high index side. */ if( !llhi ) { for( j = i + 1; j < nlab; j++ ) { if( list[ j ].priority == prio ) { llhi = list + j; break; } } } /* Find the closest label to this one on the low index side which has a higher priority. */ lllo = NULL; for( j = i - 1; j >= 0; j-- ) { if( list[ j ].priority > prio ) { lllo = list + j; break; } } /* If no higher priority neighbour was found on the low index side, use the nearest label with the current priority on the low index side. */ if( !lllo ) { for( j = i - 1; j >= 0; j-- ) { if( list[ j ].priority == prio ) { lllo = list + j; break; } } } /* If we are not abbreviating, use the full text as the abbreviated text.*/ if( !abb ) { ll->atext = ll->text; /* Otherwise, if only one of these two neighbouring labels was found, we abbreviate the current label by comparing it with the one found neighbouring label. If they are identical, we use the last field as the abbreviated text. */ } else if( !lllo ) { ll->atext = astAbbrev( frame, axis, fmt, llhi->text, ll->text ); } else if( !llhi ) { ll->atext = astAbbrev( frame, axis, fmt, lllo->text, ll->text ); /* If two neighbouring labels were found, we abbreviate the current label by comparing it with both neighbouring labels, and choosing the shorter abbreviation. */ } else { textlo = abb ? astAbbrev( frame, axis, fmt, lllo->text, ll->text ) : ll->text; texthi = abb ? astAbbrev( frame, axis, fmt, llhi->text, ll->text ) : ll->text; lolen = strlen( textlo ); hilen = strlen( texthi ); if( lolen > 0 && lolen < hilen ) { ll->atext = textlo; } else { ll->atext = texthi; } } /* If the two fields are identical, the abbreviated text returned by astAbbrev will be a null string. In this case, find the start of the last field in the formatted value (using astAbbrev again), and use that as the abbreviated text. */ if( !(ll->atext)[0] ) { ll->atext = astAbbrev( frame, axis, fmt, NULL, ll->text ); } } } } /* Find the bounding box of the root label and add it to the list of bounding boxes. */ nleft = 1; ll = list + root; olap = Overlap( this, -1, esc, SplitValue( this, ll->atext, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, box, method, class, status ); /* Now look for labels which would overlap. First, check labels above the root label. Do not count overlaps where the two abbreviated labels have the same text. */ ll = list + root; latext = ll->atext; for( i = root + 1; i < nlab; i++ ) { ll++; if( ll->priority >= 0 ) { if( strcmp( ll->atext, latext ) ) { if( Overlap( this, -1, esc, SplitValue( this, ll->atext, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, box, method, class, status ) ){ olap++; } else { nleft++; } } latext = ll->atext; } } /* Now check the labels below the root label. */ ll = list + root; latext = ll->atext; for( i = root - 1; i >= 0; i-- ) { ll--; if( ll->priority >= 0 ) { if( strcmp( ll->atext, latext ) ) { if( Overlap( this, -1, esc, SplitValue( this, ll->atext, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, box, method, class, status ) ){ olap++; } else { nleft++; } } latext = ll->atext; } } /* If only one overlap was found, and this is the second axis, ignore it since it is probably caused by the crossing of the two axes. */ if( axis == 1 && olap == 1 ) olap = 0; /* If we are now only plotting every 3rd label, or if there are less than 3 labels left, and there are still overlapping labels, then we must have a very odd axis (such as logarithmically spaced ticks on a linearly mapped axis). In this case, we will re-instate the orignal label priorities and then leave this loop so that we attempt to plot all labels. Also retain original priorities if the axis is mapped logarithmically onto the screen. */ if( olap && ( jgap == 3 || nleft < 3 || astGetLogPlot( this, axis ) ) ){ jgap = 0; odd = 1; } else { odd = 0; } /* If any labels overlapped, re-instate the priority of all previously excluded labels (using the copy of the label's real priority stored in "saved_prio"), and then remove labels (by setting their priorities negative) to increase the gap between labels, and try again. */ if( olap ) { jgap++; nexti = root + jgap; for( i = root + 1; i < nlab; i++ ) { if( i == nexti ) { nexti += jgap; list[ i ].priority = list[ i ].saved_prio; } else { list[ i ].priority = -1; } } nexti = root - jgap; for( i = root - 1; i >= 0; i-- ) { if( i == nexti ) { nexti -= jgap; list[ i ].priority = list[ i ].saved_prio; } else { list[ i ].priority = -1; } } /* Reset the abbreviated text to be the full text. */ for( i = 0; i < nlab - 1; i++ ) list[ i ].atext = list[ i ].text; } /* Rest the list of bounding boxes to exclude the boxes added above. */ Overlap( this, nbox, esc, NULL, 0.0, 0.0, NULL, 0.0, 0.0, box, method, class, status ); } /* We can now draw the abbreviated labels (ignoring rejected labels). */ ll = list-1; for( i = 0; i < nlab; i++ ) { ll++; if( ll->priority >= 0 ) { /* Check that this label does not overlap any labels drawn for previous axes (we know from the above processing that it will not overlap any other label on the current axis). */ if( !Overlap( this, -1, esc, SplitValue( this, ll->atext, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, box, method, class, status ) ) { /* Draw the abbreviated label text, and get the bounds of the box containing the new label, splitting long formatted values (such as produced by TimeFrames) into two lines. */ DrawText( this, 1, esc, SplitValue( this, ll->atext, axis, &split, status ), (float) ll->x, (float) ll->y, ll->just, (float) ll->upx, (float) ll->upy, xbn, ybn, NULL, method, class, status ); } } } } static void PolyCurve( AstPlot *this, int npoint, int ncoord, int indim, const double *in, int *status ){ /* *++ * Name: c astPolyCurve f AST_POLYCURVE * Purpose: * Draw a series of connected geodesic curves. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astPolyCurve( AstPlot *this, int npoint, int ncoord, int indim, c const double *in ) f CALL AST_POLYCURVE( THIS, NPOINT, NCOORD, INDIM, IN, STATUS ) * Class Membership: * Plot method. * Description: c This function joins a series of points specified in the physical c coordinate system of a Plot by drawing a sequence of geodesic c curves. It is equivalent to making repeated use of the astCurve c function (q.v.), except that astPolyCurve will generally be more c efficient when drawing many geodesic curves end-to-end. A c typical application of this might be in drawing contour lines. f This routine joins a series of points specified in the physical f coordinate system of a Plot by drawing a sequence of geodesic f curves. It is equivalent to making repeated calls to the f AST_CURVE routine (q.v.), except that AST_POLYCURVE will f generally be more efficient when drawing many geodesic curves f end-to-end. A typical application of this might be in drawing f contour lines. * c As with astCurve, full account is taken of the Mapping between c physical and graphical coordinate systems. This includes any c discontinuities and clipping established using astClip. f As with AST_CURVE, full account is taken of the Mapping between f physical and graphical coordinate systems. This includes any f discontinuities and clipping established using AST_CLIP. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c npoint f NPOINT = INTEGER (Given) * The number of points between which geodesic curves are to be drawn. c ncoord f NCOORD = INTEGER (Given) * The number of coordinates being supplied for each point (i.e. * the number of axes in the current Frame of the Plot, as given * by its Naxes attribute). c indim f INDIM = INTEGER (Given) c The number of elements along the second dimension of the "in" f The number of elements along the first dimension of the IN * array (which contains the input coordinates). This value is * required so that the coordinate values can be correctly * located if they do not entirely fill this array. The value c given should not be less than "npoint". f given should not be less than NPOINT. c in f IN( INDIM, NCOORD ) = DOUBLE PRECISION (Given) c The address of the first element in a 2-dimensional array of shape c "[ncoord][indim]" giving the c physical coordinates of the points which are to be joined in c sequence by geodesic curves. These should be stored such that c the value of coordinate number "coord" for point number c "point" is found in element "in[coord][point]". f A 2-dimensional array giving the physical coordinates of the f points which are to be joined in sequence by geodesic f curves. These should be stored such that the value of f coordinate number COORD for input point number POINT is found f in element IN(POINT,COORD). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - No curve is drawn on either side of any point which has any * coordinate equal to the value AST__BAD. * - An error results if the base Frame of the Plot is not * 2-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ const char *class; /* Object class */ const char *method; /* Current method */ const double **in_ptr; /* Pointer to array of data pointers */ double *finish; /* Pointer to array holding segment end position */ double *start; /* Pointer to array holding segment start position */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double tol; /* Absolute tolerance value */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ int coord; /* Loop counter for coordinates */ int i; /* Loop count */ int naxes; /* No. of Frame axes */ int ok; /* Are all start and end coords good? */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astPolyCurve"; class = astGetClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Initialise the bounding box for primatives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Check the current Frame of the Plot has ncoord axes. */ naxes = astGetNout( this ); if( naxes != ncoord && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the current " "Frame of the supplied %s is invalid - this number should " "be %d (possible programming error).", status, method, class, naxes, class, ncoord ); } /* Check the array dimension argument. */ if ( astOK && ( indim < npoint ) ) { astError( AST__DIMIN, "%s(%s): The array dimension value " "(%d) is invalid.", status, method, class, indim ); astError( AST__DIMIN, "This should not be less than the number of " "points being drawn (%d).", status, npoint ); } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Allocate memory to hold the array of data pointers, the start position, and the end position. */ if ( astOK ) { in_ptr = (const double **) astMalloc( sizeof( const double * ) * (size_t) ncoord ); start = (double *) astMalloc( sizeof( double ) * (size_t) ncoord ); finish = (double *) astMalloc( sizeof( double ) * (size_t) ncoord ); /* Set up externals used to communicate with the Map3 function... The number of axes in the physical coordinate system (i.e. the current Frame). */ Map3_ncoord = ncoord; /* A pointer to the Plot, the Current Frame, and and Mapping. */ Map3_plot = this; Map3_frame = astGetFrame( this, AST__CURRENT ); Map3_map = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Now set up the external variables used by the Crv and CrvLine function. */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_tol = tol; Crv_limit = 0.5*tol*tol; Crv_map = Map3; Crv_ink = 1; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_clip = astGetClip( this ) & 1; /* Set up a list of points spread evenly over each curve segment. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Initialise the data pointers to locate the coordinate data in the "in" array. */ if ( astOK ) { for ( coord = 0; coord < ncoord; coord++ ) { in_ptr[ coord ] = in + coord * indim; } /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__CURVE_ID, 1, GRF__LINE, method, class ); /* Loop round each curve segment. */ for( i = 1 ; i < npoint; i++ ) { /* Store the start position and check it for bad values. Increment the pointers to the next position on each axis, so that they refer to the finish point of the current curve segment. */ ok = 1; for( coord = 0; coord < ncoord; coord++ ) { if( *( in_ptr[coord] ) == AST__BAD ){ ok = 0; } else { start[ coord ] = *( in_ptr[coord] ); } ( in_ptr[coord] )++; } /* Store the end position and check it for bad values. Do not increment the axis pointers. This means that they will refer to the start position of the next curve segment on the next pass through this loop. */ for( coord = 0; coord < ncoord; coord++ ) { if( *( in_ptr[coord] ) == AST__BAD ){ ok = 0; } else { finish[ coord ] = *( in_ptr[coord] ); } } /* Pass on to the next curve segment if either the start or finish position was bad. */ if( ok ) { /* Set up the remaining externals used to communicate with the Map3 function... */ /* The physical coordinates at the start of the curve. */ Map3_origin = start; /* The physical coordinates at the end of the curve. */ Map3_end = finish; /* The scale factor to convert "dist" values into physical offset values. */ Map3_scale = astDistance( Map3_frame, start, finish ); /* Now set up the remaining external variables used by the Crv and CrvLine function. */ Crv_ux0 = AST__BAD; Crv_out = 1; Crv_xbrk = Curve_data.xbrk; Crv_ybrk = Curve_data.ybrk; Crv_vxbrk = Curve_data.vxbrk; Crv_vybrk = Curve_data.vybrk; /* Map the evenly spread distances between "start" and "finish" into graphics coordinates. */ Map3( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map3 to draw the curve segment. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* If no part of the curve could be drawn, set the number of breaks and the length of the drawn curve to zero. */ if( Crv_out ) { Crv_nbrk = 0; Crv_len = 0.0F; /* Otherwise, add an extra break to the returned structure at the position of the last point to be plotted. */ } else { Crv_nbrk++; if( Crv_nbrk > AST__PLOT_CRV_MXBRK ){ astError( AST__CVBRK, "%s(%s): Number of breaks in curve " "exceeds %d.", status, method, class, AST__PLOT_CRV_MXBRK ); } else { *(Crv_xbrk++) = (float) Crv_xl; *(Crv_ybrk++) = (float) Crv_yl; *(Crv_vxbrk++) = (float) -Crv_vxl; *(Crv_vybrk++) = (float) -Crv_vyl; } } /* Store extra information about the curve in the returned structure, and purge any zero length sections. */ Curve_data.length = Crv_len; Curve_data.out = Crv_out; Curve_data.nbrk = Crv_nbrk; PurgeCdata( &Curve_data, status ); } } /* End the last poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map3. */ Map3( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* Ensure all lines are flushed to the graphics system. */ Fpoly( this, method, class, status ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__CURVE_ID, 0, GRF__LINE, method, class ); } /* Annul the Frame and Mapping. */ Map3_frame = astAnnul( Map3_frame ); Map3_map = astAnnul( Map3_map ); /* Free the memory used for the data pointers, and start and end positions. */ in_ptr = (const double **) astFree( (void *) in_ptr ); start = (double *) astFree( (void *) start ); finish = (double *) astFree( (void *) finish ); } } static int PopGat( AstPlot *this, float *rise, const char *method, const char *class, int *status ) { /* * Name: * PopGat * Purpose: * Pop current graphical attributes for text from a stack. * Type: * Private function. * Synopsis: * #include "plot.h" * int PopGat( AstPlot *this, float *rise, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function restores the current graphical attributes for text * from the values on a stack. Current attributes are left unchanged if * the stack is empty. * Parameters: * this * Pointer to the Plot. * rise * Pointer to a location at which to return thhe height of the baseline * above the normal baseline, expressed as a percentage of the normal * character height. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Returns zero if the stack is empty, and 1 otherwise. */ /* Local Variables: */ AstGat *gat; int result; /* Initialise */ result = 0; /* Check inherited status */ if( !astOK ) return result; /* Check there is at least one AstGat structure on the stack. */ if( this->ngat ) { /* Decrement the number of entries in the stack, and get a pointer to the AstGat structure. Nullify the pointer on the stack. */ gat = (this->gat)[ --(this->ngat) ]; (this->gat)[ this->ngat ] = NULL; /* Restore the values in the AstGat structure */ *rise = gat->rise; GAttr( this, GRF__SIZE, gat->size, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__WIDTH, gat->width, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__COLOUR, gat->col, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__FONT, gat->font, NULL, GRF__TEXT, method, class, status ); GAttr( this, GRF__STYLE, gat->style, NULL, GRF__TEXT, method, class, status ); /* Free the AstGat structure. */ gat = astFree( gat ); /* Indicate success.*/ result = 1; } /* Return the result. */ return result; } static void PurgeCdata( AstPlotCurveData *cdata, int *status ){ /* * * Name: * AstPlotCurveData * Purpose: * Remove any zero length sections from the description of a curve. * Type: * Private function. * Synopsis: * #include "plot.h" * void PurgeCdata( AstPlotCurveData *cdata ) * Class Membership: * Plot member function. * Description: * This function removes any zero length sections from the supplied * AstPlotCurveData struture, which describes a multi-section curve. * Parameters: * cdata * A pointer to the structure containing information about the * breaks in a curve. */ /* Local Variables: */ int brk; /*Break index */ int i; /*Break index */ /* Check the global error status. */ if ( !astOK || !cdata ) return; /* Loop round all breaks. */ brk = 0; while( brk < cdata->nbrk ) { /* If this break and the next one are co-incident, remove both breaks. */ if( cdata->xbrk[ brk ] == cdata->xbrk[ brk + 1 ] && cdata->ybrk[ brk ] == cdata->ybrk[ brk + 1 ] ) { /* Shuffle down the higher elements of all the arrays in the curve data. */ for( i = brk + 2; i < cdata->nbrk; i++ ){ cdata->xbrk[ i - 2 ] = cdata->xbrk[ i ]; cdata->ybrk[ i - 2 ] = cdata->ybrk[ i ]; cdata->vxbrk[ i - 2 ] = cdata->vxbrk[ i ]; cdata->vybrk[ i - 2 ] = cdata->vybrk[ i ]; } /* Decrement the number of breaks in the curve data. */ cdata->nbrk -= 2; /* If the section is not zero length, move on to the next pair of breaks. */ } else { brk += 2; } } } static void PushGat( AstPlot *this, float rise, const char *method, const char *class, int *status ) { /* * Name: * PushGat * Purpose: * Push current graphical attributes for text onto a stack. * Type: * Private function. * Synopsis: * #include "plot.h" * void PushGat( AstPlot *this, float rise, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function stores the current graphical attributes for text * on a stack. * Parameters: * this * Pointer to the Plot. * rise * The height of the baseline above the normal baseline, expressed * as a percentage of the normal character height. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstGat *new_gat; /* Check inherited status */ if( !astOK ) return; /* Allocate memory for a new AstGat structure to store the graphical attributes. */ new_gat = astMalloc( sizeof( AstGat ) ); if( astOK ) { /* Store the height of the current baseline above the normal baseline, expressed as a percentage of a normal character height. */ new_gat->rise = rise; /* Store the current graphical attribute values. */ GAttr( this, GRF__SIZE, AST__BAD, &(new_gat->size), GRF__TEXT, method, class, status ); GAttr( this, GRF__WIDTH, AST__BAD, &(new_gat->width), GRF__TEXT, method, class, status ); GAttr( this, GRF__FONT, AST__BAD, &(new_gat->font), GRF__TEXT, method, class, status ); GAttr( this, GRF__STYLE, AST__BAD, &(new_gat->style), GRF__TEXT, method, class, status ); GAttr( this, GRF__COLOUR, AST__BAD, &(new_gat->col), GRF__TEXT, method, class, status ); /* Increment the number of AstGat structures on the stack.*/ this->ngat++; /* Extend the array of AstGat pointers in the Plot structure so that there is room for the new one. */ this->gat = (AstGat **) astGrow( this->gat, this->ngat, sizeof( AstGat * ) ); if( astOK ) { /* Store the new pointer. */ (this->gat)[ this->ngat - 1 ] = new_gat; } } } static int RegionOutline( AstPlot *this, AstFrame *frm, const char *method, const char *class, int *status ){ /* * * Name: * RegionOutline * Purpose: * Draw the outline of a Region. * Type: * Private function. * Synopsis: * #include "plot.h" * int RegionOutline( AstPlot *this, AstFrame *frm, const char *method, * const char *class, int *status ) * Class Membership: * Plot member function. * Description: * If the current Frame in the supplied Plot is a Region, this function * draws a curve marking the outline of the Region. It returns without * action otherwise. * Parameters: * this * Pointer to the Plot. * frm * Pointer to the current Frame in the Plot (possibly a Region). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if and only if a Region outline was drawn. */ /* Local Variables: */ AstMapping *map; /* Mapping with Region masking included */ AstPlotCurveData cdata; /* Stores information about curve breaks */ AstRegion **comps; /* List of component Regions */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ double d[ CRV_NPNT ]; /* Offsets to evenly spaced points along curve */ double tol; /* Absolute tolerance value */ double x[ CRV_NPNT ]; /* X coords at evenly spaced points along curve */ double y[ CRV_NPNT ]; /* Y coords at evenly spaced points along curve */ int i; /* Loop count */ int icomp; /* Index of component Region */ int ncomp; /* Number of component Regions */ int result; /* The returned value */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Check the current Frame is a Region, and is of a class that implements the astRegTrace method. */ if( astIsARegion( frm ) && astRegTrace( (AstRegion *) frm, 0, NULL, NULL ) ){ /* Set up the externals used to communicate with the Map5 function... The number of axes in the physical coordinate system (i.e. the Region). */ Map5_ncoord = astGetNaxes( frm ); /* A pointer to the Plot, the Region, and the Mapping. */ Map5_plot = this; Map5_region = (AstRegion *) frm; /* Also store a pointer to the Mapping, ensuring that the Mapping does not contain any masking effects from the Region. */ map = astGetMapping( this, AST__BASE, AST__CURRENT ); Map5_map = astRemoveRegions( map ); map = astAnnul( map ); /* Convert the tolerance from relative to absolute graphics coordinates. */ tol = astGetTol( this )*MAX( this->xhi - this->xlo, this->yhi - this->ylo ); /* Ensure the globals holding the scaling from graphics coords to equally scaled coords are available. */ GScales( this, NULL, NULL, method, class, status ); /* Now set up the external variables used by the Crv and CrvLine function. */ Crv_scerr = ( astGetLogPlot( this, 0 ) || astGetLogPlot( this, 1 ) ) ? 100.0 : 1.5; Crv_ux0 = AST__BAD; Crv_tol = tol; Crv_limit = 0.5*tol*tol; Crv_map = Map5; Crv_ink = 1; Crv_xlo = this->xlo; Crv_xhi = this->xhi; Crv_ylo = this->ylo; Crv_yhi = this->yhi; Crv_out = 1; Crv_xbrk = cdata.xbrk; Crv_ybrk = cdata.ybrk; Crv_vxbrk = cdata.vxbrk; Crv_vybrk = cdata.vybrk; Crv_clip = astGetClip( this ) & 1; /* Attempt to split the Region into a set of disjoint component Regions. */ comps = astRegSplit( (AstRegion *) frm, &ncomp ); /* Draw each one. */ for( icomp = 0; icomp < ncomp; icomp++ ) { /* A pointer to the Region. */ Map5_region = comps[ icomp ]; /* Set up a list of points spread evenly over the curve. */ for( i = 0; i < CRV_NPNT; i++ ){ d[ i ] = ( (double) i)/( (double) CRV_NSEG ); } /* Map these points into graphics coordinates. */ Map5( CRV_NPNT, d, x, y, method, class, status GLOBALS_NAME ); /* Use Crv and Map5 to draw the curve. */ Crv( this, d, x, y, 0, NULL, NULL, method, class, status ); /* End the current poly line. */ Opoly( this, status ); /* Tidy up the static data used by Map5. */ Map5( 0, NULL, NULL, NULL, method, class, status GLOBALS_NAME ); /* Annul the component Region pointer. */ comps[ icomp ] = astAnnul( Map5_region ); } /* Free the memory holding the list of component Region pointers. */ comps = astFree( comps ); /* Annul the Mapping. */ Map5_map = astAnnul( Map5_map ); /* Indicate the outline was drawn. */ result = 1; } /* Return. */ return result; } static void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status ) { /* * Name: * RemoveFrame * Purpose: * Remove a Frame from a Plot. * Type: * Public virtual function. * Synopsis: * #include "plot.h" * void RemoveFrame( AstFrameSet *this_fset, int iframe, int *status ) * Class Membership: * Plot member function (over-rides the astRemoveFrame public * method inherited from the FrameSet class). * Description: * This function removes a Frame from a Plot. All other Frames * in the Plot have their indices re-numbered from one (if * necessary), but are otherwise unchanged. * * If the index of the clipping Frame is changed, the index value * stored in the Plot is updated. If the clipping Frame itself is * removed, all clipping information is removed from the Plot. * Parameters: * this_fset * Pointer to the FrameSet component of the Plot. * iframe * The index within the Plot of the Frame to be removed. * This value should lie in the range from 1 to the number of * Frames in the Plot (as given by its Nframe attribute). * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPlot *this; /* Pointer to Plot structure */ int ifrm; /* Validated frame index */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_fset; /* Validate the frame index. */ ifrm = astValidateFrameIndex( this_fset, iframe, "astRemoveFrame" ); /* Invoke the parent astRemoveFrame method to remove the Frame. */ (*parent_removeframe)( this_fset, iframe, status ); /* If the index of the removed Frame is smaller than the clipping Frame index, then decrement the clipping Frame index so that the same Frame will be used in future. */ if( astOK ){ if( ifrm < this->clip_frame ){ (this->clip_frame)--; /* If the clipping fgrame itself has been removed, indicate that no clipping should nbow be performed. */ } else if( ifrm == this->clip_frame ){ astClip( this, AST__NOFRAME, NULL, NULL ); } } } static void RightVector( AstPlot *this, float *ux, float *uy, float *rx, float *ry, const char *method, const char *class, int *status ){ /* * Name: * RightVector * Purpose: * Return a vector in the direction of the base line of normal text. * Synopsis: * #include "plot.h" * void RightVector( AstPlot *this, float *ux, float *uy, float *rx, * float *ry, const char *method, const char *class, int *status ) * Description: * This function returns a vector which points from left to right along * the text baseline, taking account of any difference in the scales of * the x and y axes. It also scales the supplied up vector so that it has * a length equal to the height of normal text, and scales the returned * right vector to have the same length (on the screen) as the up vector. * Parameters: * this * The plot. * ux * Pointer to a float holding the x component of the up-vector for the * text, in graphics coords. Scaled on exit so that the up vector has * length equal to the height of normal text. * uy * Pointer to a float holding the y component of the up-vector for the * text, in graphics coords. Scaled on exit so that the up vector has * length equal to the height of normal text. * rx * Pointer to a double in which will be put the x component of a * vector parallel to the baseline of normal text. * ry * Pointer to a double in which will be put the y component of a * vector parallel to the baseline of normal text. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ float alpha; /* Scale factor for X axis */ float beta; /* Scale factor for Y axis */ float chv; float chh; float l; /* Normalisation constant */ float a; float b; float nl; /* Character height in standard coordinates */ /* Check inherited status */ if( !astOK ) return; /* Find the scale factors for the two axes which scale graphics coordinates into a "standard" coordinate system in which: 1) the axes have equal scale in terms of (for instance) millimetres per unit distance, 2) X values increase from left to right, 3) Y values increase from bottom to top. */ GScales( this, &alpha, &beta, method, class, status ); /* Convert the up-vector into "standard" system in which the axes have equal scales, and increase left-to-right, bottom-to-top. */ *ux *= alpha; *uy *= beta; /* Normalise this up-vector. */ l = sqrt( (*ux)*(*ux) + (*uy)*(*uy) ); if( l <= 0.0 ) { *ux = 0.0; *uy = 1.0; } else { *ux /= l; *uy /= l; } /* Find the height in "standard" coordinates of "normal" text draw with the requested up-vector. */ GQch( this, &chv, &chh, method, class, status ); a = (*ux)/(chv*alpha); b = (*uy)/(chh*beta); nl = 1.0/sqrt( a*a + b*b ); /* Scale the up-vector so that is has length equal to the height of "normal" text with the specified up-vector. */ *ux *= nl; *uy *= nl; /* Get the vector along the base-line of the text, by rotating the up-vector by 90 degrees clockwise. */ *rx = *uy; *ry = -*ux; /* Convert both vectors back from standard coords to normal world coords */ *ux /= alpha; *uy /= beta; *rx /= alpha; *ry /= beta; } static void SaveTick( AstPlot *this, int axis, double gx, double gy, int major, int *status ){ /* * Name: * SaveTick * Purpose: * Save info about a drawn tick in the Plot structure. * Type: * Private function. * Synopsis: * #include "plot.h" * void SaveTick( AstPlot *this, int axis, double gx, double gy, * int major, int *status ) * Class Membership: * Plot member function. * Description: * This function stores the start position and type of each drawn * tick in the given Plot. * Parameters: * this * Pointer to the Plot. * axis * The zero-based axis index to which the tick refers. If a * negative value is specified then all information about drawn ticks * curently stored in the Plot is erased. * gx * The graphics X position at the start of the tick mark. * gy * The graphics Y position at the start of the tick mark. * major * Non-zero if the tick mark is a major tick. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; int *count; double *tickgx; double *tickgy; /* Free the tick info in the supplied Plot if required. Do this before checking the error status. */ if( axis < 0 ) { for( i = 0; i < 3; i++ ) { this->majtickgx[ i ] = astFree( this->majtickgx[ i ] ); this->majtickgy[ i ] = astFree( this->majtickgy[ i ] ); this->mintickgx[ i ] = astFree( this->mintickgx[ i ] ); this->mintickgy[ i ] = astFree( this->mintickgy[ i ] ); this->mintickcount[ i ] = 0; this->majtickcount[ i ] = 0; } return; } /* Check the global error status. */ if ( !astOK ) return; /* Get pointers to the arrays to use, and ensure the arrays are big enough to hold the new tick. */ if( major ) { count = this->majtickcount + axis; tickgx = this->majtickgx[ axis ]; tickgy = this->majtickgy[ axis ]; } else { count = this->mintickcount + axis; tickgx = this->mintickgx[ axis ]; tickgy = this->mintickgy[ axis ]; } /* Ensure the arrays are big enough to hold the new tick. */ i = *count; tickgx = astGrow( tickgx, i + 1, sizeof( double ) ); tickgy = astGrow( tickgy, i + 1, sizeof( double ) ); /* If memory was allocated succesfully, store the new tick information in the expanded arrays. */ if( astOK ) { tickgx[ i ] = gx; tickgy[ i ] = gy; *count = i + 1; /* Store the potentially updated array pointers. */ if( major ) { this->majtickgx[ axis ] = tickgx; this->majtickgy[ axis ] = tickgy; } else { this->mintickgx[ axis ] = tickgx; this->mintickgy[ axis ] = tickgy; } } } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a Plot. * Type: * Private function. * Synopsis: * #include "plot.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * Plot member function (over-rides the astSetAttrib protected * method inherited from the FrameSet class). * Description: * This function assigns an attribute value for a Plot, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the Plot. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPlot *this; /* Pointer to the Plot structure */ char label[21]; /* Graphics item label */ const char *class; /* Pointer to class string */ double dval; /* Double attribute value */ int axis; /* Index for the axis */ int edge; /* Index of edge within list */ int id1; /* Plot object id */ int id2; /* Plot object id */ int id; /* Plot object id */ int ival; /* Int attribute value */ int len; /* Length of setting string */ int nax; /* Number of graphics frame axes */ int nc; /* Number of characters read by astSscanf */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_object; /* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ nax = astGetNin( this ); /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* Tol. */ /* ---- */ if ( nc = 0, ( 1 == astSscanf( setting, "tol= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetTol( this, dval ); /* Grid. */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "grid= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetGrid( this, ival ); /* TickAll. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "tickall= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetTickAll( this, ival ); /* ForceExterior */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "forceexterior= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetForceExterior( this, ival ); /* Invisible. */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "invisible= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetInvisible( this, ival ); /* Border. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "border= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetBorder( this, ival ); /* ClipOp. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "clipop= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetClipOp( this, ival ); /* Clip. */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "clip= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetClip( this, ival ); /* Grf. */ /* ---- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "grf= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetGrf( this, ival ); /* DrawTitle. */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "drawtitle= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetDrawTitle( this, ival ); /* DrawAxes. */ /* --------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "drawaxes= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetDrawAxes( this, axis, ival ); /* DrawAxes(axis). */ /* --------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "drawaxes(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetDrawAxes( this, axis - 1, ival ); /* Abbrev. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "abbrev= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetAbbrev( this, axis, ival ); /* Abbrev(axis). */ /* --------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "abbrev(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetAbbrev( this, axis - 1, ival ); /* Escape. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "escape= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetEscape( this, ival ); /* Edge(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "edge(%d)= %n%*s %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { edge = FullForm( "left right top bottom", setting + ival, setting, "astSet", astGetClass( this ), status ); if( edge == 0 ) { astSetEdge( this, axis - 1, LEFT ); } else if( edge == 1 ) { astSetEdge( this, axis - 1, RIGHT ); } else if( edge == 2 ) { astSetEdge( this, axis - 1, TOP ); } else if( edge == 3 ) { astSetEdge( this, axis - 1, BOTTOM ); } /* LabelAt (axis). */ /* --------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "labelat(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetLabelAt( this, axis - 1, dval ); /* Centre(axis). */ /* ------------ */ } else if ( nc = 0, ( 2 == astSscanf( setting, "centre(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetCentre( this, axis - 1, dval ); /* Gap. */ /* ---- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "gap= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetGap( this, axis, dval ); /* Gap(axis). */ /* ---------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "gap(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetGap( this, axis - 1, dval ); /* LogGap. */ /* ---- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "loggap= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLogGap( this, axis, dval ); /* LogGap(axis). */ /* ---------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "loggap(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetLogGap( this, axis - 1, dval ); /* NumLabGap. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "numlabgap= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetNumLabGap( this, axis, dval ); /* NumLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "numlabgap(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetNumLabGap( this, axis - 1, dval ); /* TextLabGap. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "textlabgap= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetTextLabGap( this, axis, dval ); /* TextLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "textlabgap(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetTextLabGap( this, axis - 1, dval ); /* LabelUp. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "labelup= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLabelUp( this, axis, ival ); /* LabelUp(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "labelup(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetLabelUp( this, axis - 1, ival ); /* LogPlot. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "logplot= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLogPlot( this, axis, ival ); /* LogPlot(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "logplot(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetLogPlot( this, axis - 1, ival ); /* LogTicks. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "logticks= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLogTicks( this, axis, ival ); /* LogTicks(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "logticks(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetLogTicks( this, axis - 1, ival ); /* LogLabel. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "loglabel= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLogLabel( this, axis, ival ); /* LogLabel(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "loglabel(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetLogLabel( this, axis - 1, ival ); /* NumLab. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "numlab= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetNumLab( this, axis, ival ); /* NumLab(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "numlab(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetNumLab( this, axis - 1, ival ); /* MinTick. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "mintick= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetMinTick( this, axis, ival ); /* MinTick(axis). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "mintick(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetMinTick( this, axis - 1, ival ); /* TextLab. */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "textlab= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetTextLab( this, axis, ival ); /* TextLab(axis). */ /* ---------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "textlab(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetTextLab( this, axis - 1, ival ); /* LabelUnits. */ /* --------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "labelunits= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetLabelUnits( this, axis, ival ); /* LabelUnits(axis). */ /* ---------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "labelunits(%d)= %d %n", &axis, &ival, &nc ) ) && ( nc >= len ) ) { astSetLabelUnits( this, axis - 1, ival ); /* Style. */ /* ------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "style= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetStyle( this, id, ival ); /* Style(label). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "style(%20[^()])= %d %n", label, &ival, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Style", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetStyle( this, id1, ival ); if( nid > 1 ) astSetStyle( this, id2, ival ); if( nid > 2 ) astSetStyle( this, id3, ival ); /* Font. */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "font= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetFont( this, id, ival ); /* Font(label). */ /* ------------ */ } else if ( nc = 0, ( 2 == astSscanf( setting, "font(%20[^()])= %d %n", label, &ival, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Font", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetFont( this, id1, ival ); if( nid > 1 ) astSetFont( this, id2, ival ); if( nid > 2 ) astSetFont( this, id3, ival ); /* Colour. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "colour= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetColour( this, id, ival ); /* Colour(label). */ /* -------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "colour(%20[^()])= %d %n", label, &ival, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Colour", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetColour( this, id1, ival ); if( nid > 1 ) astSetColour( this, id2, ival ); if( nid > 2 ) astSetColour( this, id3, ival ); /* Color. */ /* ------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "color= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetColour( this, id, ival ); /* Color(label). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "color(%20[^()])= %d %n", label, &ival, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Color", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetColour( this, id1, ival ); if( nid > 1 ) astSetColour( this, id2, ival ); if( nid > 2 ) astSetColour( this, id3, ival ); /* Width. */ /* ------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "width= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetWidth( this, id, dval ); /* Width(label). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "width(%20[^()])= %lg %n", label, &dval, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Width", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetWidth( this, id1, dval ); if( nid > 1 ) astSetWidth( this, id2, dval ); if( nid > 2 ) astSetWidth( this, id3, dval ); /* Size. */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "size= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( id = 0; id < AST__NPID; id++ ) astSetSize( this, id, dval ); /* Size(label). */ /* ------------ */ } else if ( nc = 0, ( 2 == astSscanf( setting, "size(%20[^()])= %lg %n", label, &dval, &nc ) ) && ( nc >= len ) ) { class = astGetClass( this ); nid = IdFind( FullForm( GrfLabels, label, "Size", "astSet", class, status ), nax, &id1, &id2, &id3, status ); astSetSize( this, id1, dval ); if( nid > 1 ) astSetSize( this, id2, dval ); if( nid > 2 ) astSetSize( this, id3, dval ); /* TitleGap. */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "titlegap= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetTitleGap( this, dval ); /* MajTickLen. */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "majticklen= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetMajTickLen( this, axis, dval ); /* MajTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "majticklen(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetMajTickLen( this, axis - 1, dval ); /* MinTickLen. */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "minticklen= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { for( axis = 0; axis < nax; axis++ ) astSetMinTickLen( this, axis, dval ); /* MinTickLen(axis). */ /* ----------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "minticklen(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetMinTickLen( this, axis - 1, dval ); /* Labelling. */ /* -------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "labelling= %n%*s %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetLabelling( this, FullForm( "exterior interior", setting + ival, setting, "astSet", astGetClass( this ), status ) ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } /* Undefine macros local to this function. */ #undef MATCH } static void SetLogPlot( AstPlot *this, int axis, int ival, int *status ){ /* * * Name: * SetLogPlot * Purpose: * Set a new value for a LogPlot attribute * Type: * Private function. * Synopsis: * #include "plot.h" * void SetLogPlot( AstPlot *this, int axis, int ival, int *status ) * Class Membership: * Plot member function * Description: * Assigns a new value to the LogPlot attribute of the specified axis, * and also re-maps the base Frame of the Plot if necessary. * Parameters: * this * The Plot. * axis * Zero based axis index. * ival * The new value for the ogPlot attribute. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int oldval; /* Original attribute value */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the axis index. */ if( axis < 0 || axis >= 2 ){ astError( AST__AXIIN, "astSetLogPlot(%s): Index (%d) is invalid for " "attribute LogPlot - it should be in the range 1 to 2.", status, astGetClass( this ), axis + 1 ); /* If the axis index is OK, store the original attribute value. We use astGetLogPlot to get the value rather than directly accessing "this->logplot" in order to get the any default value in the case of no value having been set. */ } else { oldval = astGetLogPlot( this, axis ); /* If the current attribute value will change, attempt to re-map the plot axis. If the attempt succeeds, toggle the current attribute value. */ if( ( ival != 0 ) != ( oldval != 0 ) ){ if( ToggleLogLin( this, axis, oldval, "astSetLogPlot", status ) ){ this->logplot[ axis ] = ( !oldval ); } /* If the current attribute value will not change, just store the supplied value (this is not redundant because it may cause a previously defaulted value to become an explicitly set value ). */ } else { this->logplot[ axis ] = oldval; } } } static void SetTickValues( AstPlot *this, int axis, int nmajor, double *major, int nminor, double *minor, int *status ){ /* *+ * Name: * astSetTickValues * Purpose: * Store the tick mark values to use for a given Plot axis. * Type: * Protected virtual function. * Synopsis: * #include "plot.h" * void astSetTickValues( AstPlot *this, int axis, int nmajor, * double *major, int nminor, double *minor ) * Class Membership: * Plot method. * Description: * This function stores a set of tick mark values that should be used by * subsequent calls to astGrid. * Parameters: * this * Pointer to a Plot. * axis * The zero-based index of the axis for which tick marks values * have been supplied. * nmajor * The number of major tick mark values. If zero is supplied then * the other parameters are ignored, and subsequent calls to * astGrid will itself determine the tick values to be used. * major * Pointer to an array holding "nmajor" values for axis "axis" in * the current Frame of the suppled Plot. Major tick marks will be * drawn at these values. * nminor * The number of minor tick mark values. * minor * Pointer to an array holding "nminor" values for axis "axis" in * the current Frame of the suppled Plot. Minor tick marks will be * drawn at these values. *- */ /* Check the global status. */ if( !astOK ) return; /* Report an error if the supplied axis value is incorrect. */ if( axis < 0 || axis >= astGetNin( this ) ) { astError( AST__INTER, "astSetTickValues(Plot): Supplied \"axis\" " "value is %d - should in the range 0 to %d (internal AST " "programming error).", status, axis, astGetNin( this ) - 1 ); /* Otherwise store or clear the values. */ } else if( nmajor > 0 ){ this->nmajtickval[ axis ] = nmajor; this->majtickval[ axis ] = astStore( this->majtickval[ axis ], major, sizeof( double )*nmajor ); this->nmintickval[ axis ] = nminor; this->mintickval[ axis ] = astStore( this->mintickval[ axis ], minor, sizeof( double )*nminor ); /* Sort them into increasing order. */ qsort( (void *) this->majtickval[ axis ], (size_t) nmajor, sizeof(double), Compared ); qsort( (void *) this->mintickval[ axis ], (size_t) nminor, sizeof(double), Compared ); } else { this->nmajtickval[ axis ] = 0; this->majtickval[ axis ] = astFree( this->majtickval[ axis ] ); this->nmintickval[ axis ] = 0; this->mintickval[ axis ] = astFree( this->mintickval[ axis ] ); } } const char *astStripEscapes_( const char *text, int *status ) { /* *++ * Name: c astStripEscapes f AST_STRIPESCAPES * Purpose: * Remove AST escape sequences from a string. * Type: * Public function. * Synopsis: c #include "plot.h" c const char *astStripEscapes( const char *text ) f RESULT = AST_STRIPESCAPES( TEXT ) * Description: * This function removes AST escape sequences from a supplied string, * returning the resulting text as the function value. The behaviour * of this function can be controlled by invoking the c astEscapes function, f AST_ESCAPES routine, * which can be used to supress or enable the removal of escape * sequences by this function. * * AST escape sequences are used by the Plot class to modify the * appearance and position of sub-strings within a plotted text string. * See the "Escape" attribute for further information. * Parameters: c text c Pointer to the string to be checked. f TEXT f The string to be checked. * Returned Value: c astStripEscapes() f AST_STRIPESCAPES = CHARACTER c Pointer to the modified string. If no escape sequences were found c in the supplied string, then a copy of the supplied pointer is c returned. Otherwise, the pointer will point to a static buffer c holding the modified text. This text will be over-written by c subsequent invocations of this function. If the astEscapes function f The modified string. If the AST_ESCAPES routine * has been called indicating that escape sequences should not be * stripped, then the supplied string is returned without change. *-- */ /* Local Variables: */ astDECLARE_GLOBALS const char *a; char *b; int nc; int ncc; int type; int value; const char *result; /* Initialise */ result= text; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check inherited status and supplied pointer. Also return if the string contains no escape sequences or if stripping of escapes has been supressed. */ if( !astOK || astEscapes( -1 ) || !text || !HasEscapes( text, status ) ) return result; /* Initialise a pointer to the next character to be read from the supplied string. */ a = text; /* Initialise a pointer to the next character to be written to the returned string. */ b = stripescapes_buff; /* Note the available space left in the buffer. */ ncc = AST__PLOT_STRIPESCAPES_BUFF_LEN; /* Loop until all the string has been read, or the buffer is full. */ while( *a && ncc > 0 ){ /* If the remaining string starts with an escape sequence, increment the read point by the length of the escape sequence, but leave the write pointer where it is. */ if( astFindEscape( a, &type, &value, &nc ) ) { a += nc; /* If the remaining string does not start with an escape sequence, copy the following text from the read position to the write position. */ } else { if( nc > ncc ) nc = ncc; memcpy( b, a, sizeof( char )*nc ); a += nc; b += nc; ncc -= nc; } } /* Terminate the returned string. */ *b = 0; /* Return the result.*/ return stripescapes_buff; } static int swapEdges( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, int *status ) { /* * Name: * swapEdges * Purpose: * Determine if edges for text labels should be swapped. * Type: * Private function. * Synopsis: * #include "plot.h" * int swapEdges( AstPlot *this, TickInfo **grid, AstPlotCurveData **cdata, int *status ) * Class Membership: * Plot member function. * Description: * This function returns a boolean result (0 or 1) to indicate whether * or not it is necessary to swap the Edges(0) and Edges(1) attributes * in order to place textual labels on appropriate edges. This should * only be used if the attributes have not explicitly been set, and if * interior labelling is being used. The sides are determines by * looking at the bounding box of tick marks on axis 0, in graphics * coordinates. The returned value causes the label for axis 0 to be * placed on the edge parallel to the longest side of this bounding box. * The label for axis 1 is placed parallel to the shortest side of this * bounding box. * Parameters: * this * A pointer to the Plot. * grid * A pointer to an array of two TickInfo pointers (one for each axis), * each pointing to a TickInfo structure holding information about * tick marks on the axis. See function GridLines. * cdata * A pointer to an array of two AstPlotCurveData pointers (one for each axis), * each pointing to an array of AstPlotCurveData structure (one for each * major tick value on the axis), holding information about breaks * in the curves drawn to mark the major tick values. See function * DrawGrid. * status * Pointer to the inherited status variable. * Returned Value: * One if the edges should be swapped, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstPlotCurveData *cdt; /* Pointer to the AstPlotCurveData for the next tick */ TickInfo *info; /* Pointer to the TickInfo for the current axis */ float xmax; /* Max graphics X value */ float xmin; /* Min graphics X value */ float ymax; /* Max graphics Y value */ float ymin; /* Min graphics Y value */ int oldedge; /* The original edge for axis 0 */ int result; /* Swap edges? */ int tick; /* Tick index */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure containing information describing the positions of the major tick marks along axis 0. */ info = grid[ 0 ]; /* Get a pointer to the structure containing information describing the breaks in the curve which is parallel to axis 1 and passes through the first major tick mark on axis 0. */ cdt = cdata[ 0 ]; /* Initialise the graphiocs X and Y bounds of the area covered by the axis. */ xmax = -1.0E10; xmin = 1.0E10; ymax = -1.0E10; ymin = 1.0E10; /* Loop round each of the major tick marks on axis 0. */ for( tick = 0; cdt && info && tick < info->nmajor; tick++ ){ /* Update the max and min graphics X and Y coords covered by the axis. */ if( cdt->nbrk > 0 ) { xmax = MAX( xmax, cdt->xbrk[0] ); xmin = MIN( xmin, cdt->xbrk[0] ); ymax = MAX( ymax, cdt->ybrk[0] ); ymin = MIN( ymin, cdt->ybrk[0] ); } /* Get a pointer to the curve through the next major tick mark. */ cdt++; } /* See which edge axis 0 would normally be labelled on. */ oldedge = astGetEdge( this, 0 ); /* If the X range is larger than the Y range, the textual label should be placed on the bottom edge. If required, indicate that the edges must be swapped to achieve this. */ if( xmax - xmin > ymax - ymin ) { if( oldedge == 0 || oldedge == 2 ) result = 1; /* If the X range is smaller than the Y range, the textual label should be placed on the left edge. If required, indicate that the edges must be swapped to achieve this. */ } else { if( oldedge == 1 || oldedge == 3 ) result = 1; } return result; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a Plot. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Plot member function (over-rides the astTestAttrib protected * method inherited from the FrameSet class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a Plot's attributes. * Parameters: * this * Pointer to the Plot. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstPlot *this; /* Pointer to the Plot structure */ char label[21]; /* Graphics item label */ int axis; /* Axis number */ int len; /* Length of attrib string */ int nax; /* Number of base Frame axes */ int nc; /* No. characters read by astSscanf */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_object; /* Get the number of base Frame axis (2 for a Plot, 3 for a Plot3D). */ nax = astGetNin( this ); /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* Tol. */ /* ---- */ if ( !strcmp( attrib, "tol" ) ) { result = astTestTol( this ); /* Edge(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "edge(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestEdge( this, axis - 1 ); /* Grid. */ /* ----- */ } else if ( !strcmp( attrib, "grid" ) ) { result = astTestGrid( this ); /* TickAll. */ /* -------- */ } else if ( !strcmp( attrib, "tickall" ) ) { result = astTestTickAll( this ); /* ForceExterior */ /* ------------- */ } else if ( !strcmp( attrib, "forceexterior" ) ) { result = astTestForceExterior( this ); /* Invisible. */ /* ---------- */ } else if ( !strcmp( attrib, "invisible" ) ) { result = astTestInvisible( this ); /* Border. */ /* ------- */ } else if ( !strcmp( attrib, "border" ) ) { result = astTestBorder( this ); /* ClipOp. */ /* ------- */ } else if ( !strcmp( attrib, "clipop" ) ) { result = astTestClipOp( this ); /* Clip. */ /* ----- */ } else if ( !strcmp( attrib, "clip" ) ) { result = astTestClip( this ); /* Grf. */ /* ---- */ } else if ( !strcmp( attrib, "grf" ) ) { result = astTestGrf( this ); /* DrawTitle. */ /* ---------- */ } else if ( !strcmp( attrib, "drawtitle" ) ) { result = astTestDrawTitle( this ); /* DrawAxes. */ /* --------- */ } else if ( !strcmp( attrib, "drawaxes" ) ) { result = astTestDrawAxes( this, 0 ); /* DrawAxes(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "drawaxes(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestDrawAxes( this, axis - 1 ); /* Abbrev. */ /* --------- */ } else if ( !strcmp( attrib, "abbrev" ) ) { result = astTestAbbrev( this, 0 ); /* Abbrev(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "abbrev(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestAbbrev( this, axis - 1 ); /* Escape. */ /* ------- */ } else if ( !strcmp( attrib, "escape" ) ) { result = astTestEscape( this ); /* Gap. */ /* ---- */ } else if ( !strcmp( attrib, "gap" ) ) { result = astTestGap( this, 0 ); /* Gap(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "gap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestGap( this, axis - 1 ); /* LabelAt(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelat(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLabelAt( this, axis - 1 ); /* LogGap. */ /* ---- */ } else if ( !strcmp( attrib, "loggap" ) ) { result = astTestLogGap( this, 0 ); /* LogGap(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loggap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLogGap( this, axis - 1 ); /* NumLabGap. */ /* --------- */ } else if ( !strcmp( attrib, "numlabgap" ) ) { result = astTestNumLabGap( this, 0 ); /* NumLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestNumLabGap( this, axis - 1 ); /* TextLabGap. */ /* --------- */ } else if ( !strcmp( attrib, "textlabgap" ) ) { result = astTestTextLabGap( this, 0 ); /* TextLabGap(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlabgap(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestTextLabGap( this, axis - 1 ); /* LabelUp. */ /* -------- */ } else if ( !strcmp( attrib, "labelup" ) ) { result = astTestLabelUp( this, 0 ); /* LabelUp(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelup(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLabelUp( this, axis - 1 ); /* LogPlot. */ /* -------- */ } else if ( !strcmp( attrib, "logplot" ) ) { result = astTestLogPlot( this, 0 ); /* LogPlot(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logplot(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLogPlot( this, axis - 1 ); /* LogTicks. */ /* -------- */ } else if ( !strcmp( attrib, "logticks" ) ) { result = astTestLogTicks( this, 0 ); /* LogTicks(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "logticks(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLogTicks( this, axis - 1 ); /* LogLabel. */ /* -------- */ } else if ( !strcmp( attrib, "loglabel" ) ) { result = astTestLogLabel( this, 0 ); /* LogLabel(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "loglabel(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLogLabel( this, axis - 1 ); /* NumLab. */ /* -------- */ } else if ( !strcmp( attrib, "numlab" ) ) { result = astTestNumLab( this, 0 ); /* NumLab(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "numlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestNumLab( this, axis - 1 ); /* MinTick. */ /* -------- */ } else if ( !strcmp( attrib, "mintick" ) ) { result = astTestMinTick( this, 0 ); /* MinTick(axis). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "mintick(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestMinTick( this, axis - 1 ); /* TextLab. */ /* ---------- */ } else if ( !strcmp( attrib, "textlab" ) ) { result = astTestTextLab( this, 0 ); /* TextLab(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "textlab(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestTextLab( this, axis - 1 ); /* LabelUnits. */ /* --------- */ } else if ( !strcmp( attrib, "labelunits" ) ) { result = astTestLabelUnits( this, 0 ); /* LabelUnits(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "labelunits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLabelUnits( this, axis - 1 ); /* Style. */ /* ------ */ } else if ( !strcmp( attrib, "style" ) ) { result = TestUseStyle( this, AST__BORDER_ID, status ); /* Style(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "style(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseStyle( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* Font. */ /* ----- */ } else if ( !strcmp( attrib, "font" ) ) { result = TestUseFont( this, AST__TEXTLABS_ID, status ); /* Font(label). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "font(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseFont( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* Colour. */ /* ------- */ } else if ( !strcmp( attrib, "colour" ) ) { result = TestUseColour( this, AST__TEXTLABS_ID, status ); /* Color. */ /* ------- */ } else if ( !strcmp( attrib, "color" ) ) { result = TestUseColour( this, AST__TEXTLABS_ID, status ); /* Colour(label). */ /* -------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "colour(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseColour( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* Color(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "color(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseColour( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* Width. */ /* ------ */ } else if ( !strcmp( attrib, "width" ) ) { result = TestUseWidth( this, AST__BORDER_ID, status ); /* Width(label). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "width(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseWidth( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* Size. */ /* ----- */ } else if ( !strcmp( attrib, "size" ) ) { result = TestUseSize( this, AST__TEXTLABS_ID, status ); /* Size(label). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "size(%20[^()])%n", label, &nc ) ) && ( nc >= len ) ) { result = TestUseSize( this, FullForm( GrfLabels, label, attrib, "astTest", astGetClass( this ), status ), status ); /* TitleGap. */ /* --------- */ } else if ( !strcmp( attrib, "titlegap" ) ) { result = astTestTitleGap( this ); /* MajTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "majticklen" ) ) { result = astTestMajTickLen( this, 0 ); /* MajTickLen(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "majticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestMajTickLen( this, axis - 1 ); /* MinTickLen. */ /* ----------- */ } else if ( !strcmp( attrib, "minticklen" ) ) { result = astTestMinTickLen( this, 0 ); /* MinTickLen(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "minticklen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestMinTickLen( this, axis - 1 ); /* Labelling. */ /* -------- */ } else if ( !strcmp( attrib, "labelling" ) ) { result = astTestLabelling( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static void Text( AstPlot *this, const char *text, const double pos[], const float up[], const char *just, int *status ){ /* *++ * Name: c astText f AST_TEXT * Purpose: * Draw a text string for a Plot. * Type: * Public virtual function. * Synopsis: c #include "plot.h" c void astText( AstPlot *this, const char *text, const double pos[], c const float up[], const char *just ) f CALL AST_TEXT( THIS, TEXT, POS, UP, JUST, STATUS ) * Class Membership: * Plot method. * Description: * This function draws a string of text at a position specified in * the physical coordinate system of a Plot. The physical position * is transformed into graphical coordinates to determine where the * text should appear within the plotting area. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Plot. c text f TEXT = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string containing the f A character string containing the * text to be drawn. Trailing white space is ignored. c pos f POS( * ) = DOUBLE PRECISION (Given) * An array, with one element for each axis of the Plot, giving * the physical coordinates of the point where the reference * position of the text string is to be placed. c up f UP( * ) = REAL (Given) * An array holding the components of a vector in the "up" * direction of the text (in graphical coordinates). For c example, to get horizontal text, the vector {0.0f,1.0f} should f example, to get horizontal text, the vector [0.0,1.0] should * be supplied. For a basic Plot, 2 values should be supplied. For * a Plot3D, 3 values should be supplied, and the actual up vector * used is the projection of the supplied up vector onto the text plane * specified by the current value of the Plot3D's Norm attribute. c just f JUST = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string identifying the f A character string identifying the * reference point for the text being drawn. The first character in * this string identifies the reference position in the "up" direction * and may be "B" (baseline), "C" (centre), "T" (top) or "M" (bottom). * The second character identifies the side-to-side reference position * and may be "L" (left), "C" (centre) or "R" (right ). The string is * case-insensitive, and only the first two characters are significant. * * For example, a value of "BL" means that the left end of the * baseline of the original (un-rotated) text is to be drawn at the c position given by "pos". f position given by POS. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - The Plot3D class currently does not interpret graphical escape * sequences contained within text displayed using this method. * - Text is not drawn at positions which have any coordinate equal * to the value AST__BAD (or where the transformation into * graphical coordinates yields coordinates containing the value * AST__BAD). c - If the plotting position is clipped (see astClip), then no f - If the plotting position is clipped (see AST_CLIP), then no * text is drawn. * - An error results if the base Frame of the Plot is not * 2-dimensional or (for a Plot3D) 3-dimensional. * - An error also results if the transformation between the * current and base Frames of the Plot is not defined (i.e. the * Plot's TranInverse attribute is zero). *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMapping *mapping; /* Pointer to graphics->physical mapping */ AstPointSet *pset1; /* PointSet holding physical positions */ AstPointSet *pset2; /* PointSet holding graphics positions */ const char *class; /* Object class */ const char *method; /* Current method */ const double **ptr1; /* Pointer to physical positions */ char ljust[3]; /* Upper case copy of "just" */ char *ltext; /* Local copy of "text" excluding trailing spaces */ double **ptr2; /* Pointer to graphics positions */ float xbn[ 4 ]; /* X coords of text bounding box. */ float ybn[ 4 ]; /* Y coord of text bounding box. */ int axis; /* Axis index */ int escs; /* Original astEscapes value */ int naxes; /* No. of axes in the base Frame */ int ncoord; /* No. of axes in the current Frame */ int ulen; /* Length of "text" excluding trailing spaces */ /* Check the global error status. */ if ( !astOK || !text ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Store the current method and class for inclusion in error messages generated by lower level functions. */ method = "astText"; class = astClass( this ); /* Check the base Frame of the Plot is 2-D. */ naxes = astGetNin( this ); if( naxes != 2 && astOK ){ astError( AST__NAXIN, "%s(%s): Number of axes (%d) in the base " "Frame of the supplied %s is invalid - this number should " "be 2.", status, method, class, naxes, class ); } /* Ensure AST functions included graphical escape sequences in any returned text strings. */ escs = astEscapes( 1 ); /* Initialise the bounding box for primatives produced by this call. */ if( !Boxp_freeze ) { Boxp_lbnd[ 0 ] = FLT_MAX; Boxp_lbnd[ 1 ] = FLT_MAX; Boxp_ubnd[ 0 ] = FLT_MIN; Boxp_ubnd[ 1 ] = FLT_MIN; } /* Indicate that the GRF module should re-calculate it's cached values (in case the state of the graphics system has changed since the last thing was drawn). */ RESET_GRF; /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__TEXT_ID, 1, GRF__TEXT, method, class ); /* Get the number of coordinates in the physical coordinate frame. */ ncoord = astGetNout( this ); /* Create a PointSet to hold the supplied physical coordinates. */ pset1 = astPointSet( 1, ncoord, "", status ); /* Allocate memory to hold pointers to the first value on each axis. */ ptr1 = (const double **) astMalloc( sizeof( const double * )* (size_t)( ncoord )); /* Check the pointer can be used, then store pointers to the first value on each axis. */ if( astOK ){ for( axis = 0; axis < ncoord; axis++ ){ ptr1[ axis ] = pos + axis; } } /* Store these pointers in the PointSet. */ astSetPoints( pset1, (double **) ptr1 ); /* Transform the supplied data from the current frame (i.e. physical coordinates) to the base frame (i.e. graphics coordinates) using the inverse Mapping defined by the Plot. */ mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); pset2 = Trans( this, NULL, mapping, pset1, 0, NULL, 0, method, class, status ); mapping = astAnnul( mapping ); /* Get pointers to the graphics coordinates. */ ptr2 = astGetPoints( pset2 ); /* Take a copy of the string excluding any trailing white space. */ ulen = ChrLen( text, status ); ltext = (char *) astStore( NULL, (void *) text, ulen + 1 ); /* Check the pointers can be used. */ if( astOK ){ /* Terminate the local copy of the text string. */ ltext[ ulen ] = 0; /* Produce an upper-case copy of the first two characters in "just". */ ljust[0] = (char) toupper( (int) just[0] ); ljust[1] = (char) toupper( (int) just[1] ); ljust[2] = 0; /* Convert the double precision values to single precision, checking for bad positions. */ if( ptr2[0][0] != AST__BAD && ptr2[1][0] != AST__BAD ){ /* Draw the text string. */ DrawText( this, 1, astGetEscape( this ), ltext, (float) ptr2[0][0], (float) ptr2[1][0], ljust, up[ 0 ], up[ 1 ], xbn, ybn, NULL, method, class, status ); } /* Free the local copy of the string. */ ltext = (char *) astFree( (void *) ltext ); } /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Free the memory holding the pointers to the first value on each axis. */ ptr1 = (const double **) astFree( (void *) ptr1 ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__TEXT_ID, 0, GRF__TEXT, method, class ); /* Restore the original value of the flag which says whether graphical escape sequences should be incldued in any returned text strings. */ astEscapes( escs ); /* Return */ return; } static void TextLabels( AstPlot *this, int edgeticks, int dounits[2], const char *method, const char *class, int *status ){ /* * * Name: * TextLabels * Purpose: * Draw textual labels round a grid. * Type: * Private function. * Synopsis: * #include "plot.h" * void TextLabels( AstPlot *this, int edgeticks, int dounits[2], * const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * This function displays a textual label for each physical axis, and a * title. The text strings are obtained from the Label and Title * attributes of the current Frame in the Plot. * Parameters: * this * A pointer to the Plot. * edgeticks * If tick marks and numerical labels were drawn around the edges * of the plotting area, this should be supplied as 1. Otherwise it * should be supplied as zero. * dounits * Flags indicating if the axis Units string should be included in * the edge labels. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char *new_text; /* Pointer to complete text string (inc. units) */ char *just; /* Pointer to axis label justification string */ const char *text; /* Pointer to text string to be displayed */ const char *units; /* Pointer to text string describing the units */ double mindim; /* Minimum dimension of plotting area */ double xrange; /* Width of plotting area */ double yrange; /* Height of plotting area */ float txtgap; /* Gap between bounding box and text string */ float upx; /* X component of text up-vector */ float upy; /* Y component of text up-vector */ float xbn[ 4 ]; /* X coords at corners of new label's bounding box */ float ybn[ 4 ]; /* Y coords at corners of new label's bounding box */ float xref; /* Graphics X coord. at text ref. position */ float yref; /* Graphics Y coord. at text ref. position */ float xlo, xhi, ylo, yhi;/* The original bounding box (excluding labels) */ int axis; /* Axis index */ int draw; /* Should label be drawn? */ int edge; /* Edge to be labelled */ int esc; /* Interpret escape sequences? */ int gelid; /* ID for next graphical element to be drawn */ int tlen; /* No. of characetsr in label */ int ulen; /* No. of characetsr in units */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this); /* Get the minimum dimension of the plotting area. */ xrange = this->xhi - this->xlo; yrange = this->yhi - this->ylo; mindim = MIN( xrange, yrange ); /* Take a copy of the bounding box which encloses all other parts of the annotated grid. If nothing has been plotted, use an area 20 % smaller than the plotting area. */ if( Box_lbnd[ 0 ] != FLT_MAX ) { xlo = Box_lbnd[ 0 ]; xhi = Box_ubnd[ 0 ]; ylo = Box_lbnd[ 1 ]; yhi = Box_ubnd[ 1 ]; } else { xlo = this->xlo + 0.2*xrange; xhi = this->xhi - 0.2*xrange; ylo = this->ylo + 0.2*yrange; yhi = this->yhi - 0.2*yrange; } /* See if escape sequences are to be interpreted within the labels. */ esc = astGetEscape( this ); /* Initialize the id value for graphical element being drawn. */ gelid = AST__TEXTLAB1_ID; /* Now write a label for each physical axis. */ for( axis = 0; axis < 2 && astOK; axis++ ){ /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, gelid, 1, GRF__TEXT, method, class ); /* See if the label is to be drawn. If an explicit value has not been set for the TextLab attribute, the default is to draw the label if tick marks were draw round the edge of the plotting area, and not to otherwise. */ if( astTestTextLab( this, axis ) ){ draw = astGetTextLab( this, axis ); } else { draw = edgeticks; } /* If so get the label. */ if( draw ){ text = astGetLabel( this, axis ); tlen = ChrLen( text, status ); /* If required, get the units string and concatenate it with the label (inside parenthesise). Ignore trailing spaces. */ if( dounits[ axis ] ){ units = astGetUnit( this, axis ); if( units && units[0] ){ ulen = ChrLen( units, status ); new_text = astMalloc( tlen + ulen + 4 ); if( new_text ) memcpy( new_text, text, tlen ); text = new_text + tlen; memcpy( (void *) text, " (", 2 ); text += 2; memcpy( (char *) text, units, ulen ); text += ulen; memcpy( (char *) text, ")", 1 ); text += 1; ( (char *) text )[0] = 0; text = new_text; } else { new_text = astStore( NULL, (void *) text, tlen + 1 ); new_text[ tlen ] = 0; text = new_text; units = NULL; } } else { new_text = astStore( NULL, (void *) text, tlen + 1 ); new_text[ tlen ] = 0; text = new_text; units = NULL; } /* Get the gap between the edge of the bounding box and the closest edge of the text string. */ txtgap = (float)( mindim*astGetTextLabGap( this, axis ) ); /* Get the edge to be labelled. Edge 0 is the left hand edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 is the bottom edge. */ edge = astGetEdge( this, axis ) % 4; if( edge < 0 ) edge = -edge; /* If the label is to be put on the left hand edge... */ if( edge == 0 ){ /* Set the up vector so that the text is written from bottom to top. */ upx = -1.0; upy = 0.0; /* Justify the bottom of the whole bounding box (not just the text base-line). */ just = "MC"; /* Set the x reference position just outside the box enclosing all the graphics drawn so far. The reference point refers to the centre of the text string in both directions ("CC" justification). Take account of whether or not the x axis is reversed. Do not allow the text to be written outside the whole plotting surface. */ if( this->xrev ){ xref = xhi + txtgap; } else { xref = xlo - txtgap; } /* The Y reference position is at the mid point vertically. */ yref = 0.5*( MIN( yhi, this->yhi ) + MAX( ylo, this->ylo ) ); /* Do the same for the top edge. */ } else if( edge == 1 ){ upx = 0.0; upy = 1.0; just = "MC"; if( this->yrev ){ yref = ylo - txtgap; } else { yref = yhi + txtgap; } xref = 0.5*( MIN( xhi, this->xhi ) + MAX( xlo, this->xlo ) ); /* Do the same for the right-hand edge. */ } else if( edge == 2 ){ upx = 1.0; upy = 0.0; just = "MC"; if( this->xrev ){ xref = xlo - txtgap; } else { xref = xhi + txtgap; } yref = 0.5*( MIN( yhi, this->yhi ) + MAX( ylo, this->ylo ) ); /* Do the same for the bottom edge. */ } else { upx = 0.0; upy = 1.0; just = "TC"; if( this->yrev ){ yref = yhi + txtgap; } else { yref = ylo - txtgap; } xref = 0.5*( MIN( xhi, this->xhi ) + MAX( xlo, this->xlo ) ); } /* Display the label. */ DrawText( this, 1, esc, text, xref, yref, just, upx, upy, xbn, ybn, NULL, method, class, status ); /* Release the memory allocated to store the axis label;. */ new_text = (char *) astFree( (void *) new_text ); text = NULL; } /* Re-establish the original graphical attributes. */ astGrfAttrs( this, gelid, 0, GRF__TEXT, method, class ); /* Set up the id for the next graphical element to be drawn. */ gelid = AST__TEXTLAB2_ID; } /* See if the title is to be drawn. */ if( astOK && astGetDrawTitle( this ) ){ /* If so get the title. */ text = astGetTitle( this ); /* Create a copy from which trailing spaces have been removed. */ tlen = ChrLen( text, status ); new_text = (char *) astStore( NULL, (void *) text, tlen + 1 ); new_text[ tlen ] = 0; text = new_text; /* Establish the correct graphical attributes as defined by attributes with the supplied Plot. */ astGrfAttrs( this, AST__TITLE_ID, 1, GRF__TEXT, method, class ); /* Take a copy of the bounding box which encloses all other parts of the annotated grid (this may have been extended by the above code). If nothing has been plotted, use an area 20 % smaller than the plotting area. */ if( Box_lbnd[ 0 ] != FLT_MAX ) { xlo = Box_lbnd[ 0 ]; xhi = Box_ubnd[ 0 ]; ylo = Box_lbnd[ 1 ]; yhi = Box_ubnd[ 1 ]; } else { xlo = this->xlo + 0.2*xrange; xhi = this->xhi - 0.2*xrange; ylo = this->ylo + 0.2*yrange; yhi = this->yhi - 0.2*yrange; } /* Get the graphics coordinates of the bottom centre point of the title. The X centre is put at the mid point of the used x axis range (restricted to the range of the plotting area). */ xref = 0.5*( MIN( xhi, this->xhi ) + MAX( xlo, this->xlo ) ); /* The Y centre is put a "TitleGap" distance outside the box containing the everything else. */ if( this->yrev ){ yref = ylo - (float)( mindim*astGetTitleGap( this ) ); } else { yref = yhi + (float)( mindim*astGetTitleGap( this ) ); } /* Display the title. Justify the bottom of the whole bounding box (not just the text base-line). */ DrawText( this, 1, esc, text, xref, yref, "MC", 0.0F, 1.0F, xbn, ybn, NULL, method, class, status ); /* Re-establish the original graphical attributes. */ astGrfAttrs( this, AST__TITLE_ID, 0, GRF__TEXT, method, class ); /* Release the memory allocated to store the title. */ new_text = (char *) astFree( (void *) new_text ); text = NULL; } /* Include the labels in the bounding box held in global variables Box_lbnd/ubnd. */ if( Box_lbnd[ 0 ] != FLT_MAX ) { Box_lbnd[ 0 ] = MIN( Box_lbnd[ 0 ], Boxp_lbnd[ 0 ] ); Box_ubnd[ 0 ] = MAX( Box_ubnd[ 0 ], Boxp_ubnd[ 0 ] ); Box_lbnd[ 1 ] = MIN( Box_lbnd[ 1 ], Boxp_lbnd[ 1 ] ); Box_ubnd[ 1 ] = MAX( Box_ubnd[ 1 ], Boxp_ubnd[ 1 ] ); } else { Box_lbnd[ 0 ] = Boxp_lbnd[ 0 ]; Box_ubnd[ 0 ] = Boxp_ubnd[ 0 ]; Box_lbnd[ 1 ] = Boxp_lbnd[ 1 ]; Box_ubnd[ 1 ] = Boxp_ubnd[ 1 ]; } /* Return. */ return; } static void UpdateConcat( float *xbn, float *ybn, float ux, float uy, float rx, float ry, float *x, float *y, float x0, float y0, float *alpha_lo, float *alpha_hi, float *beta_lo, float *beta_hi, int *status ){ /* * Name: * UpdateConcat * Purpose: * Update the concatenation point for a text string in preparation for * appending another string. * Synopsis: * #include "plot.h" * void UpdateConcat( float *xbn, float *ybn, float ux, float uy, * float rx, float ry, float *x, float *y, * float x0, float y0, float *alpha_lo, float *alpha_hi, * float *beta_lo, float *beta_hi, int *status ) * Description: * This function modifies the supplied concatenation point (x,y) by moving * it to the right along the baseline of the text by an amount equal * to the width of the supplied sub-string bounding box. It also updates * the supplied total bounding box so that it includes the supplied * sub-string bounding box. * Parameters: * xbn * Pointer to an array holding the x coord at the four corners of * the sub-string bounding box. * ybn * Pointer to an array holding the y coord at the four corners of * the sub-string bounding box. * ux * The x component of the up-vector for the text, in graphics coords. * The length of this vector should be equal to the height of normal * text drawn with this up-vector. * uy * The y component of the up-vector for the text. See "ux". * rx * The x component of the right-vector for the text. The length of this * vector should be equal to the height of normal text drawn with the * supplied up-vector. * ry * The y component of the right-vector for the text. see "rx". * x * Pointer to a float holding the x coord of the concatenation point * of the text just drawn. This is changed on exit so that the next * string will be appended to the end of the text just drawn. * y * Pointer to a float holding the y coord of the concatenation point * of the text just drawn. This is changed on exit so that the next * string will be appended to the end of the text just drawn. * x0 * The X coord at the left end of the baseline of the total string. * y0 * The Y coord at the left end of the baseline of the total string. * alpha_lo * Pointer to a double holding a value which gives the position of the * bottom edge of the total bounding box. The value is such that * (x0,y0) + alpha_lo*(ux,uy) is a point on the bottom edge of the * total bounding box. The returned value is updated so that the * total bounding box includes the supplied sub-string bounding box. * alpha_hi * Pointer to a double holding a value which gives the position of the * top edge of the total bounding box. The value is such that * (x0,y0) + alpha_hi*(ux,uy) is a point on the top edge of the * total bounding box. The returned value is updated so that the * total bounding box includes the supplied sub-string bounding box. * beta_lo * Pointer to a double holding a value which gives the position of the * left edge of the total bounding box. The value is such that * (x0,y0) + beta_lo*(rx,ry) is a point on the left edge of the * total bounding box. The returned value is updated so that the * total bounding box includes the supplied sub-string bounding box. * beta_hi * Pointer to a double holding a value which gives the position of the * right edge of the total bounding box. The value is such that * (x0,y0) + beta_hi*(rx,ry) is a point on the right edge of the * total bounding box. The returned value is updated so that the * total bounding box includes the supplied sub-string bounding box. * status * Pointer to the inherited status variable. */ /* Local Variables: */ float ahi; float alo; float alpha; float beta; float bhi; float blo; float denom; float dx; float dy; float xc; float yc; int ic; /* Check the global error status. */ if ( !astOK ) return; /* Check the supplied up and right vectors are not parallel. */ denom = ux*ry - uy*rx; if( denom != 0.0 ) { /* Get the coords at the centre of the sub-string bounding box. */ xc = ( xbn[ 0 ] + xbn[ 1 ] + xbn[ 2 ] + xbn[ 3 ] )/4.0; yc = ( ybn[ 0 ] + ybn[ 1 ] + ybn[ 2 ] + ybn[ 3 ] )/4.0; /* For each of the 4 corners of the sub-string bounding box, we consider the vector from the centre of the bounding box to the corner. We want to express this vector, vx, as a sum of a vector in the up direction and a vector in the right direction: vx = alpha*ux + beta+rx vy = alpha*uy + beta+ry where alpha and beta are constants which are different for each corner vector. We also want to find the minimum and maximum alpha and beta covered by the box. First initialise the limits. */ alo = 0.0; ahi = 0.0; blo = 0.0; bhi = 0.0; /* Now find alpha and beta for each of the four corners. */ for( ic = 0; ic < 4; ic++ ) { dx = xbn[ ic ] - xc; dy = ybn[ ic ] - yc; alpha = ( dx*ry - dy*rx ) /denom; beta = ( dy*ux - dx*uy ) /denom; /* Extend the bounds in alpha and beta. */ if( alpha < alo ) alo = alpha; if( alpha > ahi ) ahi = alpha; if( beta < blo ) blo = beta; if( beta > bhi ) bhi = beta; /* The bottom left corner has negative values for both alpha and beta. Commence the process of updating the concatenation point by subtracting off the coordinates at the bottom left corner. For zero height bounding boxes (such as may be produced if the text is completely blank), the "alpha" value should be zero, but may be slightly non-zero due to rounding errors. Allow for this (assuming non-blank text will always produce a boundiong box that is at least 1.0E-4 of the up vector in height). We do the same for bounding box width (although zero width boxes will probably not occur). */ if( alpha < 1.0E-4 ) { if( beta < 1.0E-4 ) { *x -= xbn[ ic ]; *y -= ybn[ ic ]; /* The bottom right corner has negative alpha and positive beta. Complete the process of updating the concatenation point by adding on the coordinates at the bottom right corner. */ } else if( beta > -1.0E-4 ) { *x += xbn[ ic ]; *y += ybn[ ic ]; } } } /* Also express the vector from (x0,y0) to (xc,yc) as a sum of a vector in the up direction and a vector in the right direction: xc - x0 = alpha*ux + beta*rx yc - y0 = alpha*uy + beta*ry Find alpha and beta. */ dx = xc - x0; dy = yc - y0; alpha = ( dx*ry - dy*rx ) /denom; beta = ( dy*ux - dx*uy ) /denom; /* We can now express the vector from (x0,y0) to each of the 4 corners as a sum of alpha*up and beta*right. Form the bounds of the sub-string in terms of up-vectors and right vectors from (x0,y0) instead of from the centre of the box. */ alo += alpha; ahi += alpha; blo += beta; bhi += beta; /* Extend the supplied alpha and beta bounding box to include these limits. */ if( alo < *alpha_lo ) *alpha_lo = alo; if( ahi > *alpha_hi ) *alpha_hi = ahi; if( blo < *beta_lo ) *beta_lo = blo; if( bhi > *beta_hi ) *beta_hi = bhi; } } static void Ticker( AstPlot *this, int edge, int axis, double value, double *gap, double tklen, int majtick, int save, EdgeCrossingsStatics **pstatics, const char *method, const char *class, int *status ){ /* * * Name: * Ticker * Purpose: * Draw edge tick marks for a given axis value. * Type: * Private function. * Synopsis: * #include "plot.h" * void Ticker( AstPlot *this, int edge, int axis, double value, * double *gap, double tklen, int majtick, int save, * EdgeCrossingsStatics **pstatics, const char *method, * const char *class, int *status ){ * Class Membership: * Plot member function. * Description: * This function draws tick marks at all occurences of a given * physical axis value on a given edge of the plotting area. * Parameters: * this * A pointer to the Plot. * edge * The edge of the plotting area to be ticked. Edge 0 is the left hand * edge. Edge 1 is the top edge. Edge 2 is the right-hand edge. Edge 3 * is the bottom edge. * axis * The index of the axis to which "value" refers. The tick mark extends * parallel to this axis. * value * The physical axis value at which to place the tick mark. * gap * Pointer to array of two values holding the gap between major * tick marks on the two axes. * tklen * The length of the tick, in graphics units. * majtick * Non-zero if the tick mark being drawn is a major tick, and zero * if it is a minor tick. * save * If non-zero, the tick mark position will be saved in the Plot structure. * pstatics * Address of a pointer to a structure holding values for variables * which were statically defined within this function prior to the * thread-safe version of AST. If the pointer is supplied as NULL, * then a new structure is allocated and initialised. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ double *cross; /* Pointer to crossings information */ double *vx; /* Pointer to next X vector component value */ double *vy; /* Pointer to next Y vector component value */ double *x; /* Pointer to next X value */ double *y; /* Pointer to next Y value */ double xe; /* X at tick end */ double ye; /* Y at tick end */ int j; /* Crossing index */ int ncross; /* No. of crossings of tick value and edge */ /* Check the global status. */ if( !astOK ) return; /* See where the current major tick value crosses the edge. */ ncross = EdgeCrossings( this, edge, axis, value, gap, &cross, pstatics, method, class, status ); /* Do nothing if the supplied axis value does not occur on the specified edge of the plotting area. */ if( ncross ){ /* Draw major tick marks at the crossings. */ x = cross; y = cross + 1; vx = cross + 2; vy = cross + 3; /* Draw a tick mark at each occurence of the axis value on the specified edge. */ for( j = 0; j < ncross; j++ ){ /* Check the tick mark position and directionm are defined. */ if( *vx != AST__BAD && *vy != AST__BAD && *x != AST__BAD && *y != AST__BAD ){ /* Ensure the tick mark will point into the plotting area, no matter which edge it is on. First ensure the direction vector refers to a system in which X increases to the left and Y increases upwards. */ if( this->xrev ) *vx = -*vx; if( this->yrev ) *vy = -*vy; /* If necessary reverse the vector so that it points into the plotting area. How to do this depends on which edge is being ticked. */ if( ( edge == 0 && *vx < 0.0 ) || /* left-hand edge */ ( edge == 1 && *vy > 0.0 ) || /* Top edge */ ( edge == 2 && *vx > 0.0 ) || /* Right-hand edge */ ( edge == 3 && *vy < 0.0 ) ){ /* Bottom edge */ *vx = -*vx; *vy = -*vy; } /* Now ensure the direction vector refers to a the native graphics system taking account of any reversal of axes. */ if( this->xrev ) *vx = -*vx; if( this->yrev ) *vy = -*vy; /* Do not draw the tick if the start of the tick is outside the bounds of the axis it is labelling. */ if( ( ( edge == 1 || edge == 3 ) && *x < this->xhi && *x > this->xlo ) || ( ( edge == 0 || edge == 2 ) && *y < this->yhi && *y > this->ylo ) ) { /* Store the x and y graphics coords of the far end of the tick mark */ xe = *x + tklen*(*vx); ye = *y + tklen*(*vy); /* Ensure the far end of the tick mark is within the bounds of the axis it is labelling. If not, redice the length of the tick mark until it is.*/ if( edge == 1 || edge == 3 ) { /* Top or bottom edge */ if( xe > this->xhi ) { ye = *y + tklen*(*vy)*( this->xhi - *x )/(xe - *x ); xe = this->xhi; } else if( xe < this->xlo ) { ye = *y + tklen*(*vy)*( this->xlo - *x )/(xe - *x ); xe = this->xlo; } } else { /* Left or right edge */ if( ye > this->yhi ) { xe = *x + tklen*(*vx)*( this->yhi - *y )/(ye - *y ); ye = this->yhi; } else if( ye < this->ylo ) { xe = *x + tklen*(*vx)*( this->ylo - *y )/(ye - *y ); ye = this->ylo; } } /* Draw the tick mark as a straight line of the specified length. */ if( save ) SaveTick( this, axis, *x, *y, majtick, status ); if( *x != xe || *y != ye ) { Bpoly( this, (float) *x, (float) *y, status ); Apoly( this, (float) xe, (float) ye, status ); Opoly( this, status ); } } /* Move on to the next crossing. */ x += 4; y += 4; vx += 4; vy += 4; } } /* Free the memory holding the crossings. */ if( cross ) cross = (double *) astFree( (void *) cross ); } /* Return. */ return; } static TickInfo *TickMarks( AstPlot *this, int axis, double *cen, double *gap, int *inval, GetTicksStatics **pstatics, const char *method, const char *class, int *status ){ /* * Name: * TickMarks * Purpose: * Obtain a list of tick mark values and labels for a single axis in a 2-D * physical coordinate Frame. * Type: * Private function. * Synopsis: * #include "plot.h" * TickInfo *TickMarks( AstPlot *this, int axis, double *cen, double *gap, * int *inval, GetTicksStatics **pstatics, * const char *method, const char *class, int *status ) * Class Membership: * Plot member function. * Description: * A set of tick marks values and corresponding formatted labels are * found for an axis which result in all adjacent labels being different, * but using the minimum number of digits of precision in the formatting. * This algorithm is over-ridden if the caller has set an explicit Format * string for the axis. The gap between tick marks can be specified by * the caller or a default value may be found automatically. * Parameters: * this * The Plot. * axis * The zero-based index of the axis to use. * cen * Pointer to the supplied axis value at which to put a single * central tick. Other ticks will be placed evenly on either side of * this tick. If AST__BAD is provided, a value will be used which * would put a tick at an axis value of zero. The used value is * returned. * gap * The supplied values for the gaps between ticks on the axis. If * this is AST__BAD a suitable default value will be used and * returned in place of the AST__BAD value. * inval * A pointer to a location at which to return a flag indicating if * any invalid physical coordinates were encountered while deciding on * the tick values. * pstatics * Address of a pointer to a structure holding static data values * used within the GetTicks function. A NULL pointer should be supplied * on the first invocation (dynamic memory will then be allocated to * hold ths structure). The memory is freed when a NULL value for * "this" is supplied. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a TickInfo structure holding information about the tick * marks (no. of major and minor ticks, the major tick mark values and * labels). This structure should be freed, together with its contents, * using astFree when it is no longer needed. * Notes: * - The returned labels are NOT abbreviated to remove identical * leading fields. * - This function allocates some static resources on its first * invocation, which should be released when no longer needed, or when * a different Plot is supplied, by calling this function with a NULL * pointer for parameter "this". All other parameters (except axis) are * ignored. * - This function assumes that the physical coordinate system is 2 * dimensional, and it should not be used if this is not the case. * - An error is reported if the region containing valid physical * coordinates is too small to use. * - If an error has already occurred, or if this function should fail * for any reason, then a NULL pointer is returned. */ /* Local Constants: */ #define MAXFLD 10 /* Local Variables: */ AstAxis *ax; /* Pointer to the axis. */ AstFrame *frame; /* Pointer to the current Frame in the Plot */ TickInfo *ret; /* Pointer to the returned structure. */ char **labels; /* Pointer to list of formatted labels */ char **newlabels; /* Pointer to new list of shortened formatted labels */ char **oldlabels; /* Pointer to old list of formatted labels */ char *fields[ MAXFLD ]; /* Pointers to starts of fields in a label */ char *old_format; /* Original Format string */ char *used_fmt; /* Copy of format string actually used */ const char *a; /* Pointer to next character to consider */ const char *fmt; /* Format string actually used */ double *ticks; /* Pointer to major tick mark values */ double *minticks; /* Pointer to minor tick mark values */ double cen0; /* Supplied value of cen */ double junk; /* Unused value */ double refval; /* Value for other axis to use when normalizing */ double used_gap; /* The gap size actually used */ int bot_digits; /* Digits value which makes labels as short as possible */ int digits; /* New Digits value */ int digset; /* Did the format string fix the no. of digits to use? */ int fmtset; /* Was a format set? */ int i; /* Tick index. */ int nc[ MAXFLD ]; /* Lengths of fields in a label */ int nf; /* Number of fields in a label */ int nmajor; /* No. of major tick marks */ int nminor; /* No. of minor tick marks */ int ok; /* Are all adjacent labels different? */ int reset_fmt; /* Re-instate the original state of the Format attribute? */ /* If a NULL pointer has been supplied for "this", release the resources allocated within GetTicks, and return. */ if( !this ){ (void) GetTicks( NULL, axis, NULL, &ticks, &nmajor, &minticks, &nminor, 0, inval, &refval, pstatics, method, class, status ); return NULL; } /* Check the global status. */ if( !astOK ) return NULL; /* Initialise the returned pointer. */ ret = NULL; /* Store the supplied value of cen. */ cen0 = cen ? *cen : AST__BAD ; /* Get a pointer to the current Frame from the Plot. */ frame = astGetFrame( this, AST__CURRENT ); /* Initialise a flag to indicate that all adjacent labels are different. */ ok = 0; /* Initialise the pointer to the list of formatted tick mark values to indicate that no memory has yet been obtained. */ labels = NULL; /* Initialise the pointer to a copy of the used format string to indicate that no memory has yet been obtained. */ used_fmt = NULL; /* Get a pointer to the axis. */ ax = astGetAxis( frame, axis ); /* See if a value has been set for the axis Format. */ fmtset = astTestFormat( frame, axis ); /* Get an initial set of tick mark values. This also establishes defaults for LogTicks and LogLabel attributes, and so must be done before the following block which uses the LogLabel attribute. */ used_gap = GetTicks( this, axis, cen, &ticks, &nmajor, &minticks, &nminor, fmtset, inval, &refval, pstatics, method, class, status ); /* See if exponential labels using superscript powers are required. */ old_format = NULL; reset_fmt = 0; if( astGetLogLabel( this, axis ) && astGetEscape( this ) && GCap( this, GRF__SCALES, 1, status ) ) { /* Save a copy of the Frame's Format value, if set. It will be re-instated at the end of this function. */ if( fmtset ) { fmt = astGetFormat( frame, axis ); old_format = astStore( NULL, (void *) fmt, strlen(fmt) + 1 ); } /* Temporarily use a format of "%&g" to get "10**x" style axis labels, with super-scripted "x". */ astSetFormat( frame, axis, "%&g" ); /* Not all subclasses of Frame support this format specifier, so format a test value, and see if it has two fields, the first of which is "10". If not, we cannot use log labels so re-instate the original format. */ nf = astFields( frame, axis, "%&g", astFormat( frame, axis, 1.0E4 ), MAXFLD, fields, nc, &junk ); if( nf != 2 || nc[ 0 ] != 2 || strncmp( fields[ 0 ], "10", 2 ) ) { if( old_format ) { astSetFormat( frame, axis, old_format ); old_format = astFree( old_format); } else { astClearFormat( frame, axis ); } /* If the "%&g" format is usable, note that we should reset the Format back to its original state before leaving this function. */ } else { reset_fmt = 1; } } /* If a value has been set for the axis Format, see if the format string contains a wildcard precision specifier ".*". If so, we are free to vary the number of digits used in the label in order to produce distinct labels. If no value has been set for the axis Format, we are also free to vary the number of digits. */ digset = 0; if( fmtset ) { fmt = astGetFormat( frame, axis ); if( fmt ) { digset = 1; a = fmt; while( (a = strchr( a, '.' )) ){ if( *(++a) == '*' ) { digset = 0; break; } } } } /* If the axis precision has been specified, either through the Format string or Digits value, or the Frame Digits value, we should use it so that the user's attempts to get a specific result are not foiled. */ if( digset || astTestAxisDigits( ax ) || astTestDigits( frame ) ){ /* Reserve memory to hold pointers to the formatted labels. */ labels = (char **) astMalloc( sizeof(char *)*(size_t)nmajor ); /* Format the labels. We do not check that all adjacent labels are distinct in order not to foil the users choice of format. That is, "ok" is set non-zero by the call to CheckLabels, even if some identical adjacent labels are found. */ ok = CheckLabels( this, frame, axis, ticks, nmajor, 1, labels, refval, status ); /* Note the format used. */ fmt = astGetFormat( frame, axis ); if( fmt ) used_fmt = (char *) astStore( used_fmt, (void *) fmt, strlen( fmt ) + 1 ); /* If no precision has been specified for the axis, we need to find a Digits value which gives different labels, but without using any more digits than necessary. */ } else if( astOK ){ /* Reserve memory to hold pointers to an initial set of labels formatted with the default digits value. */ labels = (char **) astMalloc( sizeof(char *)*(size_t)nmajor ); /* Produce these default labels. */ CheckLabels( this, frame, axis, ticks, nmajor, 1, labels, refval, status ); /* The first task is to decide what the smallest usable number of digits is. Starting at the default number of digits used above to produce the default labels, we reduce the number of digits until one or more of the formatted labels *increases* in length. This can happen for instance if printf decides to include an exponent in the label. The *absolute* minimum value 1. Set this first. */ bot_digits = 1; oldlabels = labels; for( digits = astGetDigits( frame ) - 1; digits > 0; digits-- ){ astSetAxisDigits( ax, digits ); /* CheckLabels2 formats the labels with the decreased number of digits, and compares them with the old labels in "labels". If any of the new labels are longer than the corresponding old labels, then a null pointer is returned. Otherwise, a pointer is returned to the new set of labels. */ newlabels = CheckLabels2( this, frame, axis, ticks, nmajor, oldlabels, refval, status ); /* Free the old labels unless they are the orignal labels (which are needed below). */ if( oldlabels != labels ) { for( i = 0; i < nmajor; i++ ){ if( oldlabels[ i ] ) oldlabels[ i ] = (char *) astFree( (void *) oldlabels[ i ] ); } oldlabels = (char **) astFree( (void *) oldlabels ); } /* If any of the labels got longer as a result of reducing the digits value, then use the previous number of digits as the lowest possible number of digits. Break out of the loop. */ if( !newlabels ) { bot_digits = digits + 1; break; } /* If none of the labels got longer, we arrive here. Use the shorter labels for the next pass round this loop. */ oldlabels = newlabels; } /* Free any remaining labels. */ if( oldlabels && oldlabels != labels ) { for( i = 0; i < nmajor; i++ ){ if( oldlabels[ i ] ) oldlabels[ i ] = (char *) astFree( (void *) oldlabels[ i ] ); } oldlabels = (char **) astFree( (void *) oldlabels ); } /* Now loop round increasing the number of digits in the formatted labels from the lowest usable value found above until all adjacent labels are different. An arbitrary upper limit of 1000 is used for Digits to stop it looping for ever. */ for( digits = bot_digits; digits < 1000; digits++ ){ /* Store the new Digits value. */ astSetAxisDigits( ax, digits ); /* Free memory used to hold the current set of labels. A new set will be created by the following call to CheckLabels. */ if( labels ) { for( i = 0; i < nmajor; i++ ) labels[ i ] = astFree( labels[ i ] ); } /* Break out of the loop if a Digits value has been found which results in all adjacent labels being different. Note the format used (we know the Format attribute is currently unset, but the default Format string reflects the current value of the Digits attribute). */ if( CheckLabels( this, frame, axis, ticks, nmajor, 0, labels, refval, status ) ) { ok = 1; fmt = astGetFormat( frame, axis ); used_fmt = (char *) astStore( NULL, (void *) fmt, strlen( fmt ) + 1 ); break; } } /* Clear the Digits value. */ astClearAxisDigits( ax ); } /* Annul the pointer to the Axis. */ ax = astAnnul( ax ); /* Re-instate the original format specifier if required. */ if( reset_fmt ) { if( old_format ) { astSetFormat( frame, axis, old_format ); old_format = astFree( old_format); } else { astClearFormat( frame, axis ); } } /* If suitable labels were found... */ if( ok && astOK ) { /* Store the used gap size. */ *gap = used_gap; /* If the caller has specified the number of minor tick marks to use, use the specified value rather than the value found above. */ if( astTestMinTick( this, axis ) ){ nminor = astGetMinTick( this, axis ); } /* Allocate memory for the returned structure. */ ret = (TickInfo *) astMalloc( sizeof( TickInfo ) ); /* If the pointer can be used, store the information. */ if( astOK ){ ret->nmajor = nmajor; ret->nminor = nminor; ret->ticks = ticks; ret->minticks = minticks; ret->labels = labels; ret->fmt = used_fmt; used_fmt = NULL; ret->start = NULL; ret->length = NULL; ret->nsect = 0; ret->gap = used_gap; } /* If no suitable labels were found report an error. */ } else if( astOK ){ if( fmtset ){ astError( AST__PLFMT, "%s(%s): No numerical labels can be produced " "for axis %d using the supplied %s format string '%s'.", status, method, class, axis + 1, astGetClass( frame ), astGetFormat( frame, axis ) ); } else { astError( AST__PLFMT, "%s(%s): No suitable format can be found to " "produce numerical labels for axis %d of a %s.", status, method, class, axis + 1, astGetClass( frame ) ); } } /* Release any remaining resources. */ frame = astAnnul( frame ); if( used_fmt ) used_fmt = astFree( used_fmt ); /* If an error has occurred, release the returned information. */ if( !astOK ){ ticks = (double *) astFree( (void *) ticks ); minticks = (double *) astFree( (void *) minticks ); if( labels ){ for( i = 0; i < nmajor; i++ ) { labels[ i ] = (char *) astFree( (void *) labels[ i ] ); } labels = (char **) astFree( (void *) labels ); if( ret ) (void ) astFree( (void *) ret->fmt ); } ret = (TickInfo *) astFree( (void *) ret ); } /* Return the structure. */ return ret; /* Undefine local constants. */ #undef MAXFLD } static int TraceBorder( AstPlot *this, AstMapping *map, double xlo, double xhi, double ylo, double yhi, int dim, double tol, int edges[ 4 ], const char *method, const char *class, int *status ) { /* * Name: * TraceBorder * Purpose: * Trace the boundary between good and bad physical coordinates through a * fine grid. * Type: * Private function. * Synopsis: * #include "plot.h" * int TraceBorder( AstPlot *this, AstMapping *map, double xlo, double xhi, * double ylo, double yhi, int dim, double tol, * int edges[ 4 ], const char *method, const char *class, * int *status ) { * Class Membership: * Plot member function. * Description: * A rectangular grid of points in graphics coords is created covering * the region specified by (xlo,xhi,ylo,yhi), using "dim" points along * each axis. This grid of points is converted into physical (WCS) * coords, and a flag is associatred with each point saying whether * the WCS coords are good or bad. The cells in this grid are then * scanned from bottom left to top right in raster fashion (each cell * has a grid point at each of its 4 corners). If a cell has a mix of * bad and good corners, the good/bad boundary must pass through it. * If the grid is sufficiently fine (as defined by "tol") then this * function draws a single straight line through each cell as an * approximation to the good bad boundary. This line joins the centres * of the two cells edges through which the boundary passes (as * indicated by the fact that one end of the edge has good WCS coords * and the other end has bad WCS coords). If the grid is not * sufficiently fine to meet the "tol" requirement, then this function * is invoked recursively to draw the curve through each cell through * which the boundary passes. * Parameters: * this * The plot. * map * The Graphics->WCS mapping. * xlo * The lower bounds on the graphics X axis of the rectangle being * considered. * xhi * The upper bounds on the graphics X axis of the rectangle being * considered. * ylo * The lower bounds on the graphics Y axis of the rectangle being * considered. * yhi * The upper bounds on the graphics Y axis of the rectangle being * considered. * dim * The number of points along one edge of the fine grid. * tol * The plotting tolerance. Once each cell is smaller than this * distance (in graphics coords), the cell is drawn. Otherwise, * this function is invoked recursively to draw the cell using a * finer grid. * edges * A pointer to an array of 4 int, in which will be returned * flags indicating if the good/bad boundary intersects any of the * edges of the grid. These flags are stored in the order left, * top, right, bottom. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPointSet *pset1; AstPointSet *pset2; double **ptr2; double *px1; double *px2; double *py1; double *py2; double cxhi; double cxlo; double cyhi; double cylo; double dx; double dy; float xc; float yc; int *bndry; int *drawn; int bad1; int bad2; int bad3; int bad4; int icell; int icol; int irow; int lastcell; int ncell; int recurse; int result; int sedges[ 4 ]; int totcells; /* Initialise returned edge flags */ edges[ 0 ] = 0; edges[ 1 ] = 0; edges[ 2 ] = 0; edges[ 3 ] = 0; /* Initialise the returned flag to indicate that no bad regions were found. */ result = 0; /* Check the global status. */ if ( !astOK ) return result; /* Create a grid of graphics and WCS coords covering the specified region of graphics coords. "ptr2" is used to access the WCS coords at each point in the grid. */ ptr2 = MakeGrid( this, NULL, map, 0, dim, xlo, xhi, ylo, yhi, 2, &pset1, &pset2, 0, method, class, status ); /* The number of cells along each axis of the grid is one less than the number of points. Also get the number of cells in the whole grid. */ ncell = dim - 1; totcells = ncell*ncell; /* Store the dimensions of each cell in graphics coords. */ dx = ( xhi - xlo )/ncell; dy = ( yhi - ylo )/ncell; /* Set a flag indicating if the cell size is larger than the required plotting tolerance. If so, we will call this function recursively to draw the curve using a finer grid. */ recurse = ( dx > tol || dy > tol ); /* If we have not yet reached the plotting tolerance, allocate work arrays with one element for each cell in the grid. */ if( recurse ) { bndry = astMalloc( sizeof( int )*totcells ); drawn = astMalloc( sizeof( int )*totcells ); } else { bndry = NULL; drawn = NULL; } /* Check pointers can be used safely. */ if( astOK ) { /* If required, initialise work arrays to hold zero. */ if( recurse ) { /* Initialise "boundary passes through cell" flags to zero. */ memset( bndry, 0, sizeof( int )*totcells ); /* Initialise "cell has been drawn" flags to zero. */ memset( drawn, 0, sizeof( int )*totcells ); } /* Store the Y graphics coords at the bottom and top of the first row. */ cylo = ylo; cyhi = ylo + dy; /* Store pointers to the physical coords at the bottom left corner of the first cell in the first row. */ px1 = ptr2[ 0 ]; py1 = ptr2[ 1 ]; /* Store pointers to the physical coords at the top left corner of the first cell in the first row. */ px2 = px1 + dim; py2 = py1 + dim; /* Store the index of the last cell in a row or column. */ lastcell = ncell - 1; /* Initialise index of next cell. */ icell = 0; /* Loop round every row of cells in this grid. */ for( irow = 0; irow < ncell; irow++ ) { /* See if the physical coords are bad at the bottom left corner of the first cell in this row. At the same time, increment the pointers so they refer to the bottom right corner of the first cell in this row. */ bad1 = ( *px1 == AST__BAD || *py1 == AST__BAD ); /* Increment the pointers. Do not do it in the above "if" statement since the or (!!) means that the second expression may never be evaluated. */ px1++; py1++; /* See if the physical coords are bad at the top left corner of the first cell in this row. At the same time, increment the pointers so they refer to the top right corner of the first cell in this row. */ bad2 = ( *px2 == AST__BAD || *py2 == AST__BAD ); px2++; py2++; /* Loop round every cell in the current row of cells. */ for( icol = 0; icol < ncell; icol++, icell++ ) { /* See if the physical coords are bad at the bottom right corner of the current cell in this row. At the same time, increment the pointers so they refer to the bottom right corner of the next cell in this row. */ bad3 = ( *px1 == AST__BAD || *py1 == AST__BAD ); px1++; py1++; /* See if the physical coords are bad at the top right corner of the current cell in this row. At the same time, increment the pointers so they refer to the top right corner of the next cell in this row. */ bad4 = ( *px2 == AST__BAD || *py2 == AST__BAD ); px2++; py2++; /* Set the returned flag non-zero if any invalidpositions are found. */ if( bad1 || bad2 || bad3 || bad4 ) result = 1; /* If there are a mixture of good and bad corners, the good/bad boundary must pass through the current cell. */ if( bad2 != bad1 || bad3 != bad1 || bad4 != bad1 ) { /* If we have not yet reached the required plotting tolerance, set a flag to indicate that the boundary should be plotted through this cell using a recirsive call to this function. */ if( recurse ) { bndry[ icell ] = 1; /* If we have reached the required plotting tolerance, draw the boundary as a straight line between the centres of the edges through which the boundary enteres and leaves the current cell. */ } else { /* Get the upper and lower graphics X bounds of the current cell. */ cxlo = xlo + icol*dx; cxhi = cxlo + dx; /* If an edge of the current cell has good coords at one end but bad coords at the other, the boundary is assumed to pass through the edge at its centre. Normally, we expect only two cell edges to have this property (i.e the boundary enters the cell through one edge and leaves through the other). However, sometimes all four edges may have this property. In this case, two sections of the boundary must pass through the cell, and there is no way of knowing which edges connect together (short of further recursion), and we arbitrarily decide to join opposite edges. */ if( bad1 == bad4 && bad2 == bad3 ) { /* Draw a horizontal line through the cell centre */ yc = 0.5*( cylo + cyhi ); Bpoly( this, (float) cxlo, yc, status ); Apoly( this, (float) cxhi, yc, status ); /* Draw a vertical line through the cell centre */ xc = 0.5*( cxlo + cxhi ); Bpoly( this, xc, (float) cylo, status ); Apoly( this, xc, (float) cyhi, status ); /* If the boundary passes through the left hand edge, it must also have passed through the right edge of the previous cell in the row (unless this is the first cell in the row), so we do not need to begin a new polyline (we can just extend the existing polyline). */ } else if( bad1 != bad2 ) { /* If this is the first cell in the row, begin a new polyline. */ yc = 0.5*( cylo + cyhi ); if( icol == 0 ) Bpoly( this, (float) cxlo, yc, status ); /* and through the top edge, draw a line between the centres of the left and top edges. */ if( bad2 != bad4 ) { xc = 0.5*( cxlo + cxhi ); Apoly( this, xc, (float) cyhi, status ); /* or through the right edge, draw a line between the centres of the left and right edges. */ } else if( bad3 != bad4 ) { Apoly( this, (float) cxhi, yc, status ); /* Otherwise, draw a line between the centres of the left and bottom edges. */ } else { xc = 0.5*( cxlo + cxhi ); Apoly( this, xc, (float) cylo, status ); } /* If the boundary passes through the top edge (we do not need to check the left edge because that was done above)... */ } else if( bad4 != bad2 ) { /* and through the right edge, draw a line between the centres of the top and right edges. */ if( bad3 != bad4 ) { xc = 0.5*( cxlo + cxhi ); yc = 0.5*( cylo + cyhi ); Bpoly( this, xc, (float) cyhi, status ); Apoly( this, (float) cxhi, yc, status ); /* Otherwise, draw a line between the centres of the top and bottom edges. */ } else { xc = 0.5*( cxlo + cxhi ); Bpoly( this, xc, (float) cyhi, status ); Apoly( this, xc, (float) cylo, status ); } /* If the boundary passes through the right edge it must also pass throught the bottom edge since all other combinations will have been trapped above. */ } else { xc = 0.5*( cxlo + cxhi ); yc = 0.5*( cylo + cyhi ); Bpoly( this, xc, (float) cylo, status ); Apoly( this, (float) cxhi, yc, status ); } /* If the current cell is on the edge of the grid, set flags in the returned "edges" array to indicate that the boundary passes out of the grid on the appropriate edge. */ if( icol == 0 ) { if( bad1 != bad2 ) edges[ 0 ] = 1; /* Left edge */ } else if( icol == lastcell ) { if( bad3 != bad4 ) edges[ 2 ] = 1; /* Right edge */ } if( irow == 0 ) { if( bad1 != bad3 ) edges[ 3 ] = 1; /* Bottom edge */ } else if( irow == lastcell ) { if( bad2 != bad4 ) edges[ 1 ] = 1; /* Top edge */ } } } /* The flags for the right hand corners of the current cell can be re-used as the flags for the left hand corners of the next cell. */ bad1 = bad3; bad2 = bad4; } /* Store the Y graphics coords at the bottom and top of the next row. */ cylo = cyhi; cyhi = cylo + dy; } /* If we have not yet reached the required plotting tolerance, call this function recursively to draw the boundary through the cells identified above. On each pass through this loop, we may discover more boundary cells in the grid, in addition to those found above. Continue looping until no further boundary cells are found. */ while( recurse ) { /* Assume that the current pass though this loop will result in all boundary cells being draw, in which case we can then leave the loop. */ recurse = 0; /* Store the Y graphics coords at the bottom and top of the first row. */ cylo = ylo; cyhi = ylo + dy; /* Initialise the cell index */ icell = 0; /* Loop round every row of cells in this grid. */ for( irow = 0; irow < ncell; irow++ ) { /* Loop round every cell in the current row of cells. */ for( icol = 0; icol < ncell; icol++, icell++ ) { /* If the good/bad boundary passes through the current cell we need to draw it unless it has already been drawn. */ if( bndry[ icell ] && ! drawn[ icell ] ){ /* Get the upper and lower graphics X bounds of the current cell. */ cxlo = xlo + icol*dx; cxhi = cxlo + dx; /* Call this function recursively to draw the boundary through the current cell, setting the returned flag non-zero if any bad positions are found. */ if( TraceBorder( this, map, cxlo, cxhi, cylo, cyhi, 3, tol, sedges, method, class, status ) ) result = 1; /* The boundary may have passed out of the current cell and then back into the cell on the same edge (i.e. a small loop that pokes out into a neighbouring cell). Such neighbouring cells may not have been identified by the earlier section of this function, so we now ensure that any such cells are flagged as boundary cells. */ /* If the boundary passed out of the left edge of the cell... */ if( sedges[ 0 ] ) { /* If the current cell is at the left edge of the grid, indicate that the boundary passes out of the left edge of the grid. */ if( icol == 0 ) { edges[ 0 ] = 1; /* Left edge */ /* Otherwise, if the left hand neighbour of the current cell is not flagged as a boundary cell, flag it now and indicate that another pass though the loop is needed to draw the extra cell. */ } else if( ! bndry[ icell - 1 ] ) { bndry[ icell - 1 ] = 1; recurse = 1; } } /* If the boundary passed out of the top edge of the cell... */ if( sedges[ 1 ] ) { /* If the current cell is at the top edge of the grid, indicate that the boundary passes out of the top edge of the grid. */ if( irow == lastcell ) { edges[ 1 ] = 1; /* Top edge */ /* Otherwise, ensure that the upper neighbour of the current cell is flagged as a boundary cell. */ } else { bndry[ icell + ncell ] = 1; } } /* If the boundary passed out of the right edge of the cell... */ if( sedges[ 2 ] ) { /* If the current cell is at the right edge of the grid, indicate that the boundary passes out of the right edge of the grid. */ if( icol == lastcell ) { edges[ 2 ] = 1; /* Right edge */ /* Otherwise, ensure that the right hand neighbour of the current cell is flagged as a boundary cell. */ } else { bndry[ icell + 1 ] = 1; } } /* If the boundary passed out of the bottom edge of the cell... */ if( sedges[ 3 ] ) { /* If the current cell is at the bottom edge of the grid, indicate that the boundary passes out of the bottom edge of the grid. */ if( irow == 0 ) { edges[ 3 ] = 1; /* Bottom edge */ /* Otherwise, if the lower neighbour of the current cell is not flagged as a boundary cell, flag it now and indicate that another pass though the loop is needed to draw the extra cell. */ } else if( ! bndry[ icell - ncell ] ) { bndry[ icell - ncell ] = 1; recurse = 1; } } /* Indicate this cell has been drawn. */ drawn[ icell ] = 1; } } /* Store the Y graphics coords at the bottom and top of the next row. */ cylo += dy; cyhi = cylo + dy; } } } /* Free resources */ bndry = astFree( bndry ); drawn = astFree( drawn ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Return the result. */ return result; } static AstPointSet *Trans( AstPlot *this, AstFrame *frm, AstMapping *mapping, AstPointSet *in, int forward, AstPointSet *out, int norm, const char *method, const char *class, int *status ) { /* * Name: * Trans * Purpose: * Use a Mapping to transform a set of points. * Type: * Private function. * Synopsis: * #include "plot.h" * AstPointSet *Trans( AstPlot *this, AstFrame *frm, AstMapping *mapping, * AstPointSet *in, int forward, AstPointSet *out, * int norm, const char *method, const char *class ) * Class Membership: * Plot member function. * Description: * This performs the same task as the protected method astTransform * but uses the astTransform method for the supplied Mapping instead * the parent method for the Plot. This allows the Mapping to be * extracted from the Plot using astGetMapping once, rather than every * time a mapping is performed. * Parameters: * this * Pointer to the Plot (only used to access clipping attributes and * other methods). * frm * Pointer to the Current Frame in the Plot. If this is NULL, then * a pointer for the Current Frame is found within this function if * required (i.e. if "forward" and "norm" are both non-zero). * mapping * Pointer to the Mapping extracted from the Plot. If this is NULL, then * a pointer for the base->current Mapping is found within this function. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate * transformation should be applied while a zero value requests the * inverse transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * norm * The normalisation of returned physical coordinates is only done * if "norm" is non-zero. Otherwise they are left as returned by * astTransform. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - Clipping is only performed as set up using the astClip method. * In particular, the clipping specified by the arguments to the astPlot * constructor function is NOT performed. This is done in order to improve * the efficiency of the curve drawing method astGridLine. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the Plot being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstFrame *cfr; /* Pointer to the Current Frame */ AstFrame *fr; /* Pointer to the clipping Frame */ AstMapping *map; /* Pointer to output->clip mapping */ AstPointSet *clip; /* Positions in clipping Frame */ AstPointSet *result; /* Positions in output Frame */ double **ptr_clip; /* Pointer to clipping Frame data */ double **ptr_out; /* Pointer to output coordinate data */ double *work; /* Pointer to array holding an o/p position */ double axval; /* Axis value in clipping frame */ double lbnd; /* Lower bound on current clipping axis */ double ubnd; /* Upper bound on current clipping axis */ int axin; /* Is the axis value within the allowed range? */ int clip_norm; /* Normalise the clipping positions? */ int clip_or; /* Combine axes using a logical OR? */ int clipit; /* Should the current point be clipped? */ int i; /* Point index */ int iframe; /* Validated index for clipping Frame */ int j; /* Axis index */ int naxes; /* Number of axes in clipping Frame */ int ncoord_out; /* Number of coordinates per output point */ int npoint; /* Number of points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Ensure we have a Mapping */ if( !mapping ) mapping = astGetMapping( this, AST__BASE, AST__CURRENT ); /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent FrameSet class. */ result = astTransform( mapping, in, forward, out ); /* Get the dimensions of the returned data, and an array of pointers to the axis values. */ ncoord_out = astGetNcoord( result ); npoint = astGetNpoint( result ); ptr_out = astGetPoints( result ); /* If we have done a forward mapping, we now normalise the returned physical positions if required using the astNorm method for the supplied object. */ if( forward && norm ){ /* If no Frame was supplied, get a pointer to the Current Frame. Otherwise, use the supplied pointer. */ if( !frm ) { cfr = astGetFrame( this, AST__CURRENT ); } else { cfr = frm; } /* Get work space to hold a single positions. */ work = (double *) astMalloc( sizeof(double)*(size_t)ncoord_out ); /* Check the work space and axis pointers can be used. */ if( astOK ){ /* Now loop through every position, copying the axis values to the work array, normalising them using astNorm, and copying them back to the returned PointSet. */ for( i = 0; i < npoint; i++ ){ for( j = 0; j < ncoord_out; j++ ) work[ j ] = ptr_out[ j ][ i ]; astNorm( cfr, work ); for( j = 0; j < ncoord_out; j++ ) ptr_out[ j ][ i ] = work[ j ]; } } /* Free the work space. */ work = (double *) astFree( (void *) work ); /* Annul the pointer to the Current Frame if it was obtained in this function. */ if( !frm ) cfr = astAnnul( cfr ); } /* Clipping is only performed if the bounds of a clipping region are available for both axes. */ if( this->clip_lbnd && this->clip_ubnd ){ /* Validate and translate the index of the clipping Frame. */ iframe = astValidateFrameIndex( this, this->clip_frame, method ); /* Obtain a pointer to the clipping Frame and determine how many axes it has. */ fr = astGetFrame( this, iframe ); naxes = astGetNaxes( fr ); /* Report an error if the number of bounds does not equal the number of axes in the clipping Frame. */ if( astOK && naxes != this->clip_axes ){ astError( AST__CLPAX, "%s%s): The supplied %s specifies clipping " "in %d dimensions, but the clipping Frame ('%s') has " "%d axes.", status, method, class, class, this->clip_axes, astGetTitle( fr ), naxes ); } /* Set a flag indicating if the coordinates in the clipping frame need to be normalised. */ clip_norm = 1; /* We now obtain a pointer to a PointSet holding the corresponding coordinates in the clipping frame. If the clipping frame is the base frame, then take a clone of the PointSet holding base frame coordinates. */ if( iframe == astGetBase( this ) ){ if( forward ){ clip = astClone( in ); } else { clip = astClone( result ); } /* If the clipping frame is the current frame, then take a clone of the PointSet holding current coordinates. Note, if the returned physical coordinates have already been normalised, we don't need to normalise the clipping coordinates. */ } else if( iframe == astGetCurrent( this ) ){ if( forward ){ clip = astClone( result ); if( norm ) clip_norm = 0; } else { clip = astClone( in ); } /* If the clipping Frame is neither the base nor the current Frame, we need to map the returned normalised points into the clipping Frame. */ } else { if( forward ){ map = astGetMapping( this, AST__CURRENT, iframe ); } else { map = astGetMapping( this, AST__BASE, iframe ); } clip = astTransform( map, result, 1, NULL ); map = astAnnul( map ); } /* Get a pointer to the coordinate data in the clipping Frame. */ ptr_clip = astGetPoints( clip ); /* If necessary, normalise the coordinates in the clipping frame. */ if( clip_norm ){ /* Get work space to hold a single position. */ work = (double *) astMalloc( sizeof(double)*(size_t)naxes ); /* Check the work space and axis pointers can be used. */ if( astOK ){ /* Now loop through every position, copying the axis values to the work array, normalising them using astNorm, and copying them back to the clipping PointSet. */ for( i = 0; i < npoint; i++ ){ for( j = 0; j < naxes; j++ ) work[ j ] = ptr_clip[ j ][ i ]; astNorm( fr, work ); for( j = 0; j < naxes; j++ ) ptr_clip[ j ][ i ] = work[ j ]; } } /* Free the work space. */ work = (double *) astFree( (void *) work ); } /* If all has gone ok, we will now clip the returned points. */ if( astOK ){ /* Get the logical operation to be used to determine if a point is to be clipped. A zero value means that a logical AND is to be performed between the axes (i.e. all axes must be within the supplied bounds for a point to be retained). A non-zero value means that a logical OR is to be performed between the axes (i.e. only a single axis need be within the supplied bounds for a point to be retained). */ clip_or = astGetClipOp( this ); /* Do each point in turn. */ for( j = 0; j < npoint; j++ ){ /* If all axes must fall within the supplied range to avoid the point being clipped (i.e. if clip_or is 0), then assume initially that the point is not to be clipped. This will be toggled as soon as the first out-of-bounds point is found. If, on the other hand, the point is only clipped if all axis values are out-of-bounds, then assume initially that the point is to be clipped. This will be toggled as soon as the first axis value is found which is not out-of-bounds. */ clipit = clip_or; /* Check each axis value for the current point. */ for( i = 0; i < naxes; i++ ){ axval = ptr_clip[ i ][ j ]; /* Chekc that it is not bad. */ if( axval != AST__BAD ){ /* Store the bounds of the clipping volume on this axis. */ lbnd = this->clip_lbnd[ i ]; ubnd = this->clip_ubnd[ i ]; /* Set a flag indicating if the axis value is within the specified range. If the supplied bounds are reversed, they specify the range to exclude, otherwise they specify the range to include. */ if( lbnd <= ubnd ){ axin = ( axval >= lbnd && axval <= ubnd ); } else { axin = ( axval < ubnd || axval > lbnd ); } /* If the point is within the range and only one such point is required to avoid the point being clipped, indicate that the point should not be clipped, and leave the loop. */ if( axin && clip_or ){ clipit = 0; break; /* If the point is not within the range and we only one such point is required to cause the point to be clipped, indicate that the point should be clipped, and leave the loop. */ } else if( !axin && !clip_or ){ clipit = 1; break; } /* Clip the point if any axis value is bad in the clipping Frame. */ } else { clipit = 1; break; } } /* If the point is to be clipped, set all returned axis values bad. */ if( clipit ) { for( i = 0; i < naxes; i++ ) ptr_out[ i ][ j ] = AST__BAD; } } } /* Annul the PointSet holding clipping Frame positions. */ if( clip ) clip = astAnnul( clip ); /* Annul the clipping Frame pointer. */ fr = astAnnul( fr ); } /* If an error has occurred, annul the result. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Use a Plot to transform a set of points. * Type: * Private function. * Synopsis: * #include "plot.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out ) * Class Membership: * Plot member function (over-rides the astTransform protected * method inherited from the FrameSet class). * Description: * This function takes a Plot and a set of points encapsulated in a * PointSet and transforms the points from graphics coordinates to * physical coordinates (in the forward direction). If the returned * positions are physical coordinates (i.e. if a forward mapping is * performed) they are normalised using the astNorm method of the supplied * Plot. The returned axis values are set to AST__BAD for any positions * which are outside the clipping volume set up by the astClip method. * Parameters: * this * Pointer to the Plot. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate * transformation should be applied while a zero value requests the * inverse transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - Clipping is only performed as set up using the astClip method. * In particular, the clipping specified by the arguments to the astPlot * constructor function is NOT performed. This is done in order to improve * the efficiency of the curve drawing method astGridLine. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the Plot being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstMapping *map; /* Pointer to the mapping */ AstPointSet *result; /* Positions in output Frame */ AstPlot *plot; /* The Plot */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the Plot. */ plot = (AstPlot *) this; /* Get the Mapping from the base to the current Frame. */ map = astGetMapping( plot, AST__BASE, AST__CURRENT ); /* Do the transformation. */ result = Trans( plot, NULL, map, in, forward, out, 1, "astTransform", astGetClass( this ), status ); /* Annul the mapping. */ map = astAnnul( map ); /* If an error has occurred, annul the result. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static double Typical( int n, double *value, double lolim, double hilim, double *width, int *status ) { /* * Name: * Typical * Purpose: * Return a typical value within the supplied array of values. * Type: * Private function. * Synopsis: * #include "plot.h" * double Typical( int n, double *value, double lolim, double hilim, * double *width, int *status ) * Class Membership: * Plot member function. * Description: * This function locates the approximate mode of the supplied values, * and returns one of the supplied values which is close to the modal * value. Values outside an indicated range are ignored. * Parameters: * n * The number of data values. * value * A pointer to an array of "n" values. * lolim * Values less than lolim are ignored. Supply as -DBL_MAX if there * is no lower limit. * hilim * Values greater than hilim are ignored. Supply as DBL_MAX if there * is no upper limit. * width * Pointer to a double in which to return the width (i,e, data range) * of the non-empty histogram cells. This is an estimate of the * range of used values in the supplied array. NULL may be supplied. * status * Pointer to the inherited status variable. * Returned Value: * A typical value from the supplied array. AST__BAD is returned only * if an error has occurred, or if all the supplied values are AST__BAD * or outside the specified range. */ /* Local Variables: */ double *a; /* Pointer to next value */ double cnt; /* Modified count */ double delta; /* Bin size */ double maxval; /* Maximum supplied value */ double mean; /* Mean supplied value */ double minval; /* Minimum supplied value */ double result; /* The returned value. */ double w0; /* Rate of increase of weight with dist from edge */ double w1; /* Weight for left edge */ double w2; /* Weight for right edge */ double w; /* Weight for this bin */ int *hist; /* Pointer to first cell of histogram array */ int i; /* Loop count */ int ibin; /* Bin index */ int maxcnt; /* Maximum no. of values in any bin */ int modify; /* Modify the effect of the edge bins? */ int nbin; /* No. of bins in histogram */ int nc; /* Total number of points in histogram */ int ngood; /* No. of good values supplied */ int nonemp; /* No. of non-empty bins in hstogram */ /* Initialise. */ result = AST__BAD; if( width ) *width = 0.0; /* Check the global error status. */ if ( !astOK ) return result; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ ibin = 0; /* Find the minimum and maximum value in the supplied array, which are also within the supplied limits. Also store the first good value encountered in "result". */ minval = DBL_MAX; maxval = -DBL_MAX; a = value; ngood = 0; for( i = 0; i < n; i++, a++ ) { if( *a != AST__BAD ) { if( *a >= lolim && *a <= hilim ) { if( *a < minval ) minval = *a; if( *a > maxval ) maxval = *a; if( ngood == 0 ) result = *a; ngood++; } } } /* Initialise the returned width to the total data range. */ if( width && maxval != -DBL_MAX ) *width = maxval - minval; /* If less than 3 points were found, we will return the first. Otherwise, if 3 or more good values were found, find a typical value. */ if( ngood > 2 ) { /* We will form a histogram of the supplied values in order to find the mode. The number of bins in this histogram is chosen so that there is an average of 2 points per bin. Find the number of bins. */ nbin = ( ngood + 1 )/2; /* Find the bin size. If zero (i.e. if all values are equal), return the first good value established above. */ delta = ( maxval - minval )/ nbin; if( delta > 0.0 ) { /* Allocat ememory for the histogram. */ hist = astMalloc( sizeof(int)*(size_t)nbin ); if( hist ) { /* Initialise the histogram. */ for( i = 0; i < nbin; i++ ) hist[ i ] = 0; /* Form the histogram. Form the mean data value at the same time. */ mean = 0.0; a = value; nc = 0; for( i = 0; i < n; i++, a++ ){ if( *a != AST__BAD ) { if( *a >= lolim && *a <= hilim ) { mean += *a; ibin = (int) ( ( *a - minval )/ delta ); if( ibin == nbin ) ibin--; hist[ ibin ]++; nc++; } } } mean /= ngood; /* We tend to prefer not to use reference values which are very close the the limits since they can give problems with regard to normalization (rounding errors can knock them over the edge), so we modify the counts in each bin of the histogram to reduce the impact of bins near the edge. However, we do not do this if the number of bins is very small or if all the counts are in the edge bins. */ modify = ( nbin > 4 && ( hist[ 0 ] + hist[ nbin - 1 ] < 0.98*ngood ) ); /* Find the bin with the highest modified count. If there is more than one bin with the highest modified count, choose the one which is closest to the mean data value found above. Also count the number of non-empty bins. */ nonemp = 0; maxcnt = 0; w0 = nbin/2; for( i = 0; i < nbin; i++ ) { cnt = hist[ i ]; if( cnt ) nonemp++; if( modify ) { w1 = i*w0; w2 = ( nbin - 1 - i )*w0; w = ( w1 < w2 ) ? w1 :w2; if( w < 1.0 ) cnt *= w; } if( cnt > maxcnt ) { maxcnt = cnt; ibin = i; } else if( cnt == maxcnt ) { if( fabs( minval + ( i - 0.5 )*delta - mean ) < fabs( minval + ( ibin - 0.5 )*delta - mean ) ) { maxcnt = cnt; ibin = i; } } } /* Free the histogram memory. */ hist = astFree( hist ); /* If required, return the width of the non-empty bins. */ if( width ) *width = nonemp*delta; /* Call this function recursively to refine the value, restricting attention to those data values which are within the range of the bin found above. */ if( maxcnt < nc && ibin*delta > 1000.0*DBL_EPSILON*fabs(maxval) ) { minval += ibin*delta; maxval = minval + delta; result = Typical( n, value, minval, maxval, NULL, status ); } } } } /* Return the result. */ return result; } static int GetUseColour( AstPlot *this, int id, int *status ) { /* * Name: * GetUseColour * Purpose: * Get the Colour value to use for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int GetUseColour( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This returns the Colour value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the colour * for the first set specific value is returned. For example, if the * Colour for AST__AXES_ID is requested, then the colour for AST__AXIS1_ID * will be returned if set, and otherwise the colour for AST__AXIS2_ID will * be returned. If AST__AXIS2_ID is not set either, then the default for * AST__AXIS2_ID will be returned. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Colour value to use. */ /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return NOCOLOUR; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the value of the first set genuine identifier. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); if( nid > 1 ) { if( astTestColour( this, id1 ) ) { id = id1; } else if( nid > 1 && astTestColour( this, id2 ) ) { id = id2; } else if( nid > 2 && astTestColour( this, id3 ) ) { id = id3; } else { id = id1; } } /* Return the result. */ return astGetColour( this, id ); } static int GetUseFont( AstPlot *this, int id, int *status ) { /* * Name: * GetUseFont * Purpose: * Get the Font value to use for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int GetUseFont( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This returns the Font value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the Font * for the first set specific value is returned. For example, if the * Font for AST__AXES_ID is requested, then the Font for AST__AXIS1_ID * will be returned if set, and otherwise the Font for AST__AXIS2_ID will * be returned. If AST__AXIS2_ID is not set either, then the default for * AST__AXIS2_ID will be returned. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Font value to use. */ /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return NOFONT; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the value of the first set genuine identifier. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); if( nid > 1 ) { if( astTestFont( this, id1 ) ) { id = id1; } else if( nid > 1 && astTestFont( this, id2 ) ) { id = id2; } else if( nid > 2 && astTestFont( this, id3 ) ) { id = id3; } else { id = id1; } } /* Return the result. */ return astGetFont( this, id ); } static double GetUseSize( AstPlot *this, int id, int *status ) { /* * Name: * GetUseSize * Purpose: * Get the Size value to use for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * double GetUseSize( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This returns the Size value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the Size * for the first set specific value is returned. For example, if the * Size for AST__AXES_ID is requested, then the Size for AST__AXIS1_ID * will be returned if set, and otherwise the Size for AST__AXIS2_ID will * be returned. If AST__AXIS2_ID is not set either, then the default for * AXIS2_ID will be returned. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Size value to use. */ /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return NOSIZE; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the value of the first set genuine identifier. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); if( nid > 1 ) { if( astTestSize( this, id1 ) ) { id = id1; } else if( nid > 1 && astTestSize( this, id2 ) ) { id = id2; } else if( nid > 2 && astTestSize( this, id3 ) ) { id = id3; } else { id = id1; } } /* Return the result. */ return astGetSize( this, id ); } static int GetUseStyle( AstPlot *this, int id, int *status ) { /* * Name: * GetUseStyle * Purpose: * Get the Style value to use for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int GetUseStyle( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This returns the Style value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the style * for the first set specific value is returned. For example, if the * Style for AST__AXES_ID is requested, then the style for AST__AXIS1_ID * will be returned if set, and otherwise the style for AST__AXIS2_ID will * be returned. If AST__AXIS2_ID is not set either, then the default for * AST__AXIS2_ID will be returned. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Style value to use. */ /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return NOSTYLE; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the value of the first set genuine identifier. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); if( nid > 1 ) { if( astTestStyle( this, id1 ) ) { id = id1; } else if( nid > 1 && astTestStyle( this, id2 ) ) { id = id2; } else if( nid > 2 && astTestStyle( this, id3 ) ) { id = id3; } else { id = id1; } } /* Return the result. */ return astGetStyle( this, id ); } static double GetUseWidth( AstPlot *this, int id, int *status ) { /* * Name: * GetUseWidth * Purpose: * Get the Width value to use for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * double GetUseWidth( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This returns the Width value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the Width * for the first set specific value is returned. For example, if the * Width for AST__AXES_ID is requested, then the Width for AST__AXIS1_ID * will be returned if set, and otherwise the Width for AST__AXIS2_ID will * be returned. If AST__AXIS2_ID is not set either, then the default for * AST__AXIS2_ID will be returned. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Width value to use. */ /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return NOWIDTH; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the value of the first set genuine identifier. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); if( nid > 1 ) { if( astTestWidth( this, id1 ) ) { id = id1; } else if( nid > 1 && astTestWidth( this, id2 ) ) { id = id2; } else if( nid > 2 && astTestWidth( this, id3 ) ) { id = id3; } else { id = id1; } } /* Return the result. */ return astGetWidth( this, id ); } static int TestUseColour( AstPlot *this, int id, int *status ) { /* * Name: * TestUseColour * Purpose: * Test the Colour value for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestUseColour( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This tests the Colour value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the element * is considered to be set if all the corresponding specific values are * set. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Colour value state (1 if set, zero otherwise). */ /* Local Variables: */ int ret; /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return 0; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the logical AND of the test flags for the genuine identifiers. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); ret = astTestColour( this, id1 ); if( nid > 1 ) ret = ret && astTestColour( this, id2 ); if( nid > 2 ) ret = ret && astTestColour( this, id3 ); /* Return the result. */ return ret; } static int TestUseFont( AstPlot *this, int id, int *status ) { /* * Name: * TestUseFont * Purpose: * Test the Font value for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestUseFont( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This tests the Font value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the element * is considered to be set if all the corresponding specific values are * set. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Font value state (1 if set, zero otherwise). */ /* Local Variables: */ int ret; /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return 0; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the logical AND of the test flags for the genuine identifiers. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); ret = astTestFont( this, id1 ); if( nid > 1 ) ret = ret && astTestFont( this, id2 ); if( nid > 2 ) ret = ret && astTestFont( this, id3 ); /* Return the result. */ return ret; } static int TestUseSize( AstPlot *this, int id, int *status ) { /* * Name: * TestUseSize * Purpose: * Test the Size value for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestUseSize( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This tests the Size value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the element * is considered to be set if all the corresponding specific values are * set. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Size value state (1 if set, zero otherwise). */ /* Local Variables: */ int ret; /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return 0; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the logical AND of the test flags for the genuine identifiers. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); ret = astTestSize( this, id1 ); if( nid > 1 ) ret = ret && astTestSize( this, id2 ); if( nid > 2 ) ret = ret && astTestSize( this, id3 ); /* Return the result. */ return ret; } static int TestUseStyle( AstPlot *this, int id, int *status ) { /* * Name: * TestUseStyle * Purpose: * Test the Style value for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestUseStyle( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This tests the Style value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the element * is considered to be set if all the corresponding specific values are * set. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Style value state (1 if set, zero otherwise). */ /* Local Variables: */ int ret; /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return 0; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the logical AND of the test flags for the genuine identifiers. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); ret = astTestStyle( this, id1 ); if( nid > 1 ) ret = ret && astTestStyle( this, id2 ); if( nid > 2 ) ret = ret && astTestStyle( this, id3 ); /* Return the result. */ return ret; } static int TestUseWidth( AstPlot *this, int id, int *status ) { /* * Name: * TestUseWidth * Purpose: * Test the Width value for a specified graphical element. * Type: * Private function. * Synopsis: * #include "plot.h" * int TestUseWidth( AstPlot *this, int id, int *status ) * Class Membership: * Plot member function. * Description: * This tests the Width value for the graphical element specified by * id. If an element related to a generic value is being accessed (e.g * "Axes" is generic, "Axis1" and "Axis2" are not), then the element * is considered to be set if all the corresponding specific values are * set. * Parameters: * this * Pointer to the Plot. * id * An integer specifying the graphical element to be drawn. * status * Pointer to the inherited status variable. * Returned Value: * The Width value state (1 if set, zero otherwise). */ /* Local Variables: */ int ret; /* Local Variables: */ int id1; /* First genuine identifier */ int id2; /* Second genuine identifier */ int id3; /* Third genuine identifier */ int nid; /* Number of genuine attributes */ /* Check the global error status. */ if ( !astOK ) return 0; /* See if the supplied identifier is a psuedo-identifier representing two or three other genuine identifiers. If so, return the logical AND of the test flags for the genuine identifiers. */ nid = IdFind( id, astGetNin( this ), &id1, &id2, &id3, status ); ret = astTestWidth( this, id1 ); if( nid > 1 ) ret = ret && astTestWidth( this, id2 ); if( nid > 2 ) ret = ret && astTestWidth( this, id3 ); /* Return the result. */ return ret; } static int ToggleLogLin( AstPlot *this, int axis, int islog, const char *method, int *status ){ /* * * Name: * ToggleLogLin * Purpose: * Toggle the nature of the Plot axis mapping. * Type: * Private function. * Synopsis: * #include "plot.h" * int ToggleLogLin( AstPlot *this, int axis, int islog, * const char *method, int *status ) * Class Membership: * Plot member function * Description: * Each axis in the graphics Frame of a Plot can be mapped linearly or * logarithmically onto the corresponding axis in the base Frame of * the FrameSet supplied whtn the Plot was constructed. This function * toggles the nature of the specified axis; if it is currently * logarithmic it becomes linear, and if it is linear it becomes * logarithmic. * * If the Frame canot be re-maped (for instance because the visible * part of the axis includes the value zero), then zero is returned * but no error is reported. * Parameters: * this * The Plot. * axis * Zero based axis index. * islog * Is the axis currently logarithmic? If so, this function remaps * it so that it is linear (and vice-versa). * method * Pointer to a null-terminated string holding the name of the calling * method (only used within error mesages). * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the attempt to re-map the graphics Frame was succesful, * zero otherwise. */ /* Local Variables: */ AstCmpMap *remap1; /* 1D Mapping to re-map the graphics Frame */ AstCmpMap *remap2; /* 2D Mapping to re-map the graphics Frame */ AstMathMap *logmap; /* 1D Logarithmic axis Mapping */ AstUnitMap *unitmap; /* 1D Unit mapping */ AstWinMap *linmap; /* 1D Linear axis Mapping */ char fwdexp[ 25 + 2*DBL_DIG ]; /* Forward log mapping expression */ char invexp[ 28 + 2*DBL_DIG ]; /* Inverse log mapping expression */ const char *fwd[1]; /* Pointer to pass to MathMap constructor */ const char *inv[1]; /* Pointer to pass to MathMap constructor */ double a; /* Constant for log expression */ double b1; /* Original base Frame axis value at first edge */ double b2; /* Original base Frame axis value at second edge */ double b; /* Constant for log expression */ double c; /* Constant for log expression */ double g1; /* Graphics axis value at first edge */ double g2; /* Graphics axis value at second edge */ int result; /* Returned value */ /* Inotialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get the corresponding axis limits in the graphics coordinate system and the original base Frame coordinate system. */ if( axis == 0 ) { if( this->xrev ) { g1 = this->xhi; g2 = this->xlo; } else { g1 = this->xlo; g2 = this->xhi; } b1 = this->bbox[ 0 ]; b2 = this->bbox[ 2 ]; } else { if( this->yrev ) { g1 = this->yhi; g2 = this->ylo; } else { g1 = this->ylo; g2 = this->yhi; } b1 = this->bbox[ 1 ]; b2 = this->bbox[ 3 ]; } /* Check the limits are usable (e.g. the base Frame values will be bad if this Plot was restored from a dump of a Plot created before the LogPlot attributes were added). */ if( b1 != AST__BAD && b2 != AST__BAD && g1 != g2 && b1 != b2 && b1*b2 > 0.0 ) { /* Form the 1D Mapping which maps the specified axis linearly onto the plotting surface. The forward transformation goes from graphics to base Frame. */ linmap = astWinMap( 1, &g1, &g2, &b1, &b2, "", status ); /* Form the 1D Mapping which maps the specified axis logarithmically onto the plotting surface. The forward transformation goes from graphics to base Frame. */ c = log10( b1/b2 ); a = ( g1 - g2 )/c; if( b1 > 0.0 ) { b = ( g2*log10( b1 ) - g1*log10( b2 ) )/c; (void) sprintf( invexp, "g=%.*g*log10(b)+%.*g", DBL_DIG, a, DBL_DIG, b ); (void) sprintf( fwdexp, "b=pow(10,(g-%.*g)/%.*g)", DBL_DIG, b, DBL_DIG, a ); } else { b = ( g2*log10( -b1 ) - g1*log10( -b2 ) )/c; (void) sprintf( invexp, "g=%.*g*log10(-b)+%.*g", DBL_DIG, a, DBL_DIG, b ); (void) sprintf( fwdexp, "b=-pow(10,(g-%.*g)/%.*g)", DBL_DIG, b, DBL_DIG, a ); } fwd[ 0 ] = (const char *) fwdexp; inv[ 0 ] = (const char *) invexp; logmap = astMathMap( 1, 1, 1, fwd, 1, inv, "SimpFI=1,SimpIF=1", status ); /* If the axis was previously logarithmic, get the Mapping with which to remap the graphics Frame so that it becomes linearly related to the base Frame in the FrameSet supplied when the Plot was constructed. */ if( islog ) { astInvert( linmap ); remap1 = astCmpMap( logmap, linmap, 1, "", status ); /* If the axis was previously linear, store the new value and get the Mapping with which to remap the graphics Frame so that it becomes logarithmically related to the base Frame in the FrameSet supplied when the Plot was constructed. */ } else { astInvert( logmap ); remap1 = astCmpMap( linmap, logmap, 1, "", status ); } /* Add a 1D UnitMap to map the unaltered mapping. */ unitmap = astUnitMap( 1, "", status ); if( axis == 0 ) { remap2 = astCmpMap( remap1, unitmap, 0, "", status ); } else { remap2 = astCmpMap( unitmap, remap1, 0, "", status ); } /* Remap the base (graphics) Frame in the Plot. */ astRemapFrame( this, AST__BASE, remap2 ); /* Free resources. */ remap1 = astAnnul( remap1 ); remap2 = astAnnul( remap2 ); logmap = astAnnul( logmap ); linmap = astAnnul( linmap ); unitmap = astAnnul( unitmap ); /* Indicate success. */ if( astOK ) result = 1; } /* Return the result. */ return result; } static int Ustrcmp( const char *a, const char *b, int *status ){ /* * Name: * Ustrncmp * Purpose: * A case blind version of strcmp. * Type: * Private function. * Synopsis: * #include "plot.h" * int Ustrcmp( const char *a, const char *b ) * Class Membership: * Plot member function. * Description: * Returns 0 if there are no differences between the two strings, and 1 * otherwise. Comparisons are case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference between * the two strings, whereas "strcmp" does. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Loop round each character. */ while( 1 ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } static int Ustrncmp( const char *a, const char *b, size_t n, int *status ){ /* * Name: * Ustrncmp * Purpose: * A case blind version of strncmp. * Type: * Private function. * Synopsis: * #include "plot.h" * int Ustrncmp( const char *a, const char *b, size_t n ) * Class Membership: * Plot member function. * Description: * Returns 0 if there are no differences between the first "n" * characters of the two strings, and 1 otherwise. Comparisons are * case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * n * The maximum number of characters to compare. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference * between the two strings, whereas "strncmp" does. * - This function attempts to execute even if an error has * occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int i; /* Character index */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Compare up to "n" characters. */ for( i = 0; i < (int) n; i++ ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Plot objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Plot objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstPlot *this; /* Pointer to Plot */ int i; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) obj; /* Free the clipping bounds arrays. */ this->clip_lbnd = (double *) astFree( (void *) this->clip_lbnd ); this->clip_ubnd = (double *) astFree( (void *) this->clip_ubnd ); /* Free the Grf function stack */ this->grfstack = (AstGrfPtrs *) astFree( (void *) this->grfstack ); /* Free the graphics attribute stack. */ for( i = this->ngat - 1; i >= 0; i-- ) { this->gat[ i ] = astFree( this->gat[ i ] ); } /* Free the graphics context pointer. */ if( this->grfcontext ) { this->grfcontext = astAnnul( this->grfcontext ); this->grfcontextID = astAnnulId( this->grfcontextID ); } /* Free the information about the tick marks to draw. */ for( i = 0; i < 3; i++ ) { this->majtickval[ i ] = astFree( this->majtickval[ i ] ); this->mintickval[ i ] = astFree( this->mintickval[ i ] ); this->nmajtickval[ i ] = 0; this->nmintickval[ i ] = 0; } /* Free the information about the drawn tick marks. */ SaveTick( this, -1, 0.0, 0.0, 0, status ); } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Plot objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Plot objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstPlot *in; /* Pointer to input Plot */ AstPlot *out; /* Pointer to output Plot */ int axis; /* Zero based axis index */ int n; /* Number of ticks saved */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output Plots. */ in = (AstPlot *) objin; out = (AstPlot *) objout; /* For safety, first clear any references to the input memory from the output Plot. */ out->clip_lbnd = NULL; out->clip_ubnd = NULL; out->gat = NULL; out->ngat = 0; for( axis = 0; axis < 3; axis++ ) { out->majtickgx[ axis ] = NULL; out->majtickgy[ axis ] = NULL; out->majtickcount[ axis ] = 0; out->mintickgx[ axis ] = NULL; out->mintickgy[ axis ] = NULL; out->mintickcount[ axis ] = 0; out->majtickval[ axis ] = NULL; out->nmajtickval[ axis ] = 0; out->mintickval[ axis ] = NULL; out->nmintickval[ axis ] = 0; } /* Copy the clipping bounds arrays. */ out->clip_lbnd = (double *) astStore( NULL, (void *) in->clip_lbnd, sizeof(double)*(size_t)(in->clip_axes) ); out->clip_ubnd = (double *) astStore( NULL, (void *) in->clip_ubnd, sizeof(double)*(size_t)(in->clip_axes) ); /* Copy the Grf function stack */ out->grfstack = (AstGrfPtrs *) astStore( NULL, (void *) in->grfstack, sizeof(AstGrfPtrs)*(size_t)(in->grfnstack )); /* Copy the information about drawn tick marks. */ for( axis = 0; axis < 3; axis++ ) { n = in->majtickcount[ axis ]; out->majtickgx[ axis ] = (double *) astStore( NULL, in->majtickgx[ axis ], n*sizeof( double ) ); out->majtickgy[ axis ] = (double *) astStore( NULL, in->majtickgy[ axis ], n*sizeof( double ) ); out->majtickcount[ axis ] = n; n = in->mintickcount[ axis ]; out->mintickgx[ axis ] = (double *) astStore( NULL, in->mintickgx[ axis ], n*sizeof( double ) ); out->mintickgy[ axis ] = (double *) astStore( NULL, in->mintickgy[ axis ], n*sizeof( double ) ); out->mintickcount[ axis ] = n; n = in->nmajtickval[ axis ]; out->majtickval[ axis ] = (double *) astStore( NULL, in->majtickval[ axis ], n*sizeof( double ) ); out->nmajtickval[ axis ] = n; n = in->nmintickval[ axis ]; out->mintickval[ axis ] = (double *) astStore( NULL, in->mintickval[ axis ], n*sizeof( double ) ); out->nmintickval[ axis ] = n; } /* If an error occurred, free any allocated memory. */ if ( !astOK ) { out->clip_lbnd = (double *) astFree( out->clip_lbnd ); out->clip_ubnd = (double *) astFree( out->clip_ubnd ); out->grfstack = (AstGrfPtrs *) astFree( out->grfstack ); SaveTick( out, -1, 0.0, 0.0, 0, status ); } } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Plot objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Plot class to an output Channel. * Parameters: * this * Pointer to the Plot whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstPlot *this; /* Pointer to the Plot structure */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ char *comment; /* Pointer to comment string */ double dval; /* Double precision value */ int ax; /* Axis to which element refers */ int axis; /* Zero based axis index */ int id; /* Zero based graphical object id */ int ival; /* Integer value */ int itick; /* Tick mark index */ int nax; /* Number of base Frame axes */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Plot structure. */ this = (AstPlot *) this_object; /* Get the number of graphics (base) frame axes - 2 for a Plot, 3 for a Plot3D. */ nax = astGetNin( this ); /* Write out values representing the instance variables for the Plot class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Tol. */ /* ---- */ set = TestTol( this, status ); dval = set ? GetTol( this, status ) : astGetTol( this ); astWriteDouble( channel, "Tol", set, 0, dval, "Plotting tolerance" ); /* Grid. */ /* ----- */ set = TestGrid( this, status ); ival = set ? GetGrid( this, status ) : astGetGrid( this ); astWriteInt( channel, "Grid", set, 0, ival, "Is a grid required?" ); /* TickAll. */ /* -------- */ set = TestTickAll( this, status ); ival = set ? GetTickAll( this, status ) : astGetTickAll( this ); astWriteInt( channel, "TckAll", set, 1, ival, "Put ticks on all edges?" ); /* ForceExterior. */ /* -------------- */ set = TestForceExterior( this, status ); ival = set ? GetForceExterior( this, status ) : astGetForceExterior( this ); astWriteInt( channel, "FrcExt", set, 1, ival, "Force exterior labelling?" ); /* Invisible. */ /* ---------- */ set = TestInvisible( this, status ); ival = set ? GetInvisible( this, status ) : astGetInvisible( this ); astWriteInt( channel, "Invsbl", set, 1, ival, "Use invisible ink?" ); /* Border. */ /* ------- */ set = TestBorder( this, status ); ival = set ? GetBorder( this, status ) : astGetBorder( this ); astWriteInt( channel, "Border", set, 0, ival, "Draw a border round the grid?" ); /* ClipOp. */ /* ------- */ set = TestClipOp( this, status ); ival = set ? GetClipOp( this, status ) : astGetClipOp( this ); astWriteInt( channel, "ClpOp", set, 0, ival, "Clip using logical OR?" ); /* Clip. */ /* ----- */ set = TestClip( this, status ); ival = set ? GetClip( this, status ) : astGetClip( this ); astWriteInt( channel, "Clip", set, 0, ival, ((ival == 0)?"Do not clip at plot edges": ((ival == 1)?"Clip curves at plot edges": ((ival == 2)?"Clip markers at plot edges": "Clip markers and curves at plot edges")))); /* DrawTitle. */ /* --------- */ set = TestDrawTitle( this, status ); ival = set ? GetDrawTitle( this, status ) : astGetDrawTitle( this ); astWriteInt( channel, "DrwTtl", set, 1, ival, "Add a title to the grid?" ); /* DrawAxesUnits(axis). */ /* ----------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestDrawAxes( this, axis, status ); ival = set ? GetDrawAxes( this, axis, status ) : astGetDrawAxes( this, axis ); (void) sprintf( buff, "DrwAxs%d", axis + 1 ); astWriteInt( channel, buff, set, 0, ival, "Draw axis through ticks?" ); } /* Abbrev(axis). */ /* ------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestAbbrev( this, axis, status ); ival = set ? GetAbbrev( this, axis, status ) : astGetAbbrev( this, axis ); (void) sprintf( buff, "Abbrv%d", axis + 1 ); astWriteInt( channel, buff, set, 0, ival, "Abbreviate numerical axis labels?" ); } /* Escape. */ /* ------- */ set = TestEscape( this, status ); ival = set ? GetEscape( this, status ) : astGetEscape( this ); astWriteInt( channel, "Escape", set, 1, ival, "Interpret escape sequences?" ); /* LabelAt(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLabelAt( this, axis, status ); dval = set ? GetLabelAt( this, axis, status ) : astGetLabelAt( this, axis ); if( dval != AST__BAD ){ (void) sprintf( buff, "LblAt%d", axis + 1 ); astWriteDouble( channel, buff, set, 0, dval, "Put numerical labels at" ); } } /* Centre(axis). */ /* ------------ */ for( axis = 0; axis < nax; axis++ ){ set = TestCentre( this, axis, status ); dval = set ? GetCentre( this, axis, status ) : astGetCentre( this, axis ); if( dval != AST__BAD ){ (void) sprintf( buff, "Cen%d", axis + 1 ); astWriteDouble( channel, buff, set, 0, dval, "Tick mark origin" ); } } /* Gap(axis). */ /* ---------- */ /* Discovering the default value requires a lot of calculation. Only write out this attribute if an explicit value has been set. */ for( axis = 0; axis < nax; axis++ ){ if( astTestGap( this, axis ) ) { dval = astGetGap( this, axis ); if( dval != AST__BAD ){ (void) sprintf( buff, "Gap%d", axis + 1 ); astWriteDouble( channel, buff, set, 0, dval, "Difference between ticks" ); } } } /* LogGap(axis). */ /* ------------- */ /* Discovering the default value requires a lot of calculation. Only write out this attribute if an explicit value has been set. */ for( axis = 0; axis < nax; axis++ ){ if( astTestLogGap( this, axis ) ) { dval = astGetLogGap( this, axis ); if( dval != AST__BAD ){ (void) sprintf( buff, "LgGap%d", axis + 1 ); astWriteDouble( channel, buff, set, 0, dval, "Ratio between ticks" ); } } } /* NumLabGap(axis). */ /* ---------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestNumLabGap( this, axis, status ); dval = set ? GetNumLabGap( this, axis, status ) : astGetNumLabGap( this, axis ); if( dval != AST__BAD ) { (void) sprintf( buff, "NmGap%d", axis + 1 ); astWriteDouble( channel, buff, set, 1, dval, "Spacing of numerical labels" ); } } /* TextLabGap(axis). */ /* ----------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestTextLabGap( this, axis, status ); dval = set ? GetTextLabGap( this, axis, status ) : astGetTextLabGap( this, axis ); if( dval != AST__BAD ) { (void) sprintf( buff, "TxGap%d", axis + 1 ); astWriteDouble( channel, buff, set, 1, dval, "Spacing of descriptive labels" ); } } /* LabelUp(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLabelUp( this, axis, status ); ival = set ? GetLabelUp( this, axis, status ) : astGetLabelUp( this, axis ); (void) sprintf( buff, "LblUp%d", axis + 1 ); astWriteInt( channel, buff, set, 1, ival, "Draw numerical labels upright?" ); } /* LogPlot(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLogPlot( this, axis, status ); ival = set ? GetLogPlot( this, axis, status ) : astGetLogPlot( this, axis ); (void) sprintf( buff, "LgPlt%d", axis + 1 ); astWriteInt( channel, buff, set, 1, ival, "Map plot axis logarithmically?" ); } /* LogTicks(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLogTicks( this, axis, status ); ival = set ? GetLogTicks( this, axis, status ) : astGetLogTicks( this, axis ); (void) sprintf( buff, "LgTck%d", axis + 1 ); astWriteInt( channel, buff, set, 1, ival, "Space ticks logarithmically?" ); } /* LogLabel(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLogLabel( this, axis, status ); ival = set ? GetLogLabel( this, axis, status ) : astGetLogLabel( this, axis ); (void) sprintf( buff, "LgLbl%d", axis + 1 ); astWriteInt( channel, buff, set, 1, ival, "Scientific notation for labels?" ); } /* NumLab(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestNumLab( this, axis, status ); ival = set ? GetNumLab( this, axis, status ) : astGetNumLab( this, axis ); (void) sprintf( buff, "NmLbl%d", axis + 1 ); astWriteInt( channel, buff, set, 1, ival, "Draw numerical labels?" ); } /* MinTick(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestMinTick( this, axis, status ); ival = set ? GetMinTick( this, axis, status ) : astGetMinTick( this, axis ); (void) sprintf( buff, "MnTks%d", axis + 1 ); astWriteInt( channel, buff, set, 0, ival, "No. of sub-divisions " "between major tick marks" ); } /* TextLab(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestTextLab( this, axis, status ); ival = set ? GetTextLab( this, axis, status ) : astGetTextLab( this, axis ); (void) sprintf( buff, "TxLbl%d", axis + 1 ); astWriteInt( channel, buff, set, 0, ival, "Draw textual label?" ); } /* LabelUnits(axis). */ /* ----------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestLabelUnits( this, axis, status ); ival = set ? GetLabelUnits( this, axis, status ) : astGetLabelUnits( this, axis ); (void) sprintf( buff, "LbUnt%d", axis + 1 ); astWriteInt( channel, buff, set, 0, ival, "Add units to axis label?" ); } /* Style(object). */ /* -------------- */ for( id = 0; id < AST__NPID; id++ ){ set = TestStyle( this, id, status ); ival = set ? GetStyle( this, id, status ) : astGetStyle( this, id ); (void) sprintf( buff, "Style%d", id + 1 ); comment = GrfItem( id, " line style", &ax, status ); if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); comment = (char *) astFree( (void *) comment ); } /* Font(object). */ /* ------------- */ for( id = 0; id < AST__NPID; id++ ){ set = TestFont( this, id, status ); ival = set ? GetFont( this, id, status ) : astGetFont( this, id ); (void) sprintf( buff, "Font%d", id + 1 ); comment = GrfItem( id, " character font", &ax, status ); if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); comment = (char *) astFree( (void *) comment ); } /* Colour(object). */ /* --------------- */ for( id = 0; id < AST__NPID; id++ ){ set = TestColour( this, id, status ); ival = set ? GetColour( this, id, status ) : astGetColour( this, id ); (void) sprintf( buff, "Col%d", id + 1 ); comment = GrfItem( id, " colour index", &ax, status ); if( ax < nax ) astWriteInt( channel, buff, set, 0, ival, comment ); comment = (char *) astFree( (void *) comment ); } /* Width(object). */ /* -------------- */ for( id = 0; id < AST__NPID; id++ ){ set = TestWidth( this, id, status ); dval = set ? GetWidth( this, id, status ) : astGetWidth( this, id ); if( dval != AST__BAD ) { (void) sprintf( buff, "Width%d", id + 1 ); comment = GrfItem( id, " line width", &ax, status ); if( ax < nax ) astWriteDouble( channel, buff, set, 0, dval, comment ); comment = (char *) astFree( (void *) comment ); } } /* Size(object). */ /* ------------- */ for( id = 0; id < AST__NPID; id++ ){ set = TestSize( this, id, status ); dval = set ? GetSize( this, id, status ) : astGetSize( this, id ); if( dval != AST__BAD ) { (void) sprintf( buff, "Size%d", id + 1 ); comment = GrfItem( id, " character size", &ax, status ); if( ax < nax ) astWriteDouble( channel, buff, set, 0, dval, comment ); comment = (char *) astFree( (void *) comment ); } } /* TitleGap. */ /* --------- */ set = TestTitleGap( this, status ); dval = set ? GetTitleGap( this, status ) : astGetTitleGap( this ); if( dval != AST__BAD ) astWriteDouble( channel, "TtlGap", set, 1, dval, "Gap between title and edge" ); /* MajTickLen(axis). */ /* ----------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestMajTickLen( this, axis, status ); dval = set ? GetMajTickLen( this, axis, status ) : astGetMajTickLen( this, axis ); if( dval != AST__BAD ) { (void) sprintf( buff, "MjTkLn%d", axis + 1 ); astWriteDouble( channel, buff, set, 0, dval, "Major tick length" ); } } /* MinTickLen(axis). */ /* ----------------- */ for( axis = 0; axis < nax; axis++ ){ set = TestMinTickLen( this, axis, status ); dval = set ? GetMinTickLen( this, axis, status ) : astGetMinTickLen( this, axis ); if( dval != AST__BAD ) { (void) sprintf( buff, "MnTkLn%d", axis + 1 ); astWriteDouble( channel, buff, set, 1, dval, "Minor tick length" ); } } /* Labelling. */ /* ---------- */ set = TestLabelling( this, status ); ival = set ? GetLabelling( this, status ) : astGetLabelling( this ); comment = "Labelling scheme"; astWriteString( channel, "Lbling", set, 0, xlbling[ival], comment ); /* Edge(axis). */ /* ----------- */ for( axis = 0; axis < nax; axis++ ){ set = TestEdge( this, axis, status ); ival = set ? GetEdge( this, axis, status ) : astGetEdge( this, axis ); (void) sprintf( buff, "Edge%d", axis + 1 ); comment = "Edge used to label an axis"; astWriteString( channel, buff, set, 0, xedge[ival], comment ); } /* Now do instance variables which are not attributes. */ /* =================================================== */ /* Only write out clipping information if set. */ if( this->clip_lbnd && this->clip_ubnd ){ /* The lower bounds of the clipping volume. */ for( axis = 0; axis < this->clip_axes; axis++ ){ (void) sprintf( buff, "ClpLb%d", axis + 1 ); if( this->clip_lbnd && (this->clip_lbnd)[ axis ] != AST__BAD ){ astWriteDouble( channel, buff, 1, 0, (this->clip_lbnd)[ axis ], "Lower bound of clipping region" ); } } /* The upper bounds of the clipping volume. */ for( axis = 0; axis < this->clip_axes; axis++ ){ (void) sprintf( buff, "ClpUb%d", axis + 1 ); if( this->clip_ubnd && (this->clip_ubnd)[ axis ] != AST__BAD ){ astWriteDouble( channel, buff, 1, 0, (this->clip_ubnd)[ axis ], "Upper bound of clipping region" ); } } /* The number of bounds supplied for the clipping volume. */ astWriteInt( channel, "ClpAxs", 1, 0, this->clip_axes, "No. of bounds for clipping region" ); /* The index of the clipping Frame within the Plot. */ astWriteInt( channel, "ClpFrm", 1, 0, this->clip_frame, "Index of clipping Frame" ); } /* The bounds of the plotting area in graphics coords. */ astWriteDouble( channel, "Xlo", 1, 1, this->xlo, "Lower X bound of plotting area" ); astWriteDouble( channel, "Ylo", 1, 1, this->ylo, "Lower Y bound of plotting area" ); astWriteDouble( channel, "Xhi", 1, 1, this->xhi, "Upper X bound of plotting area" ); astWriteDouble( channel, "Yhi", 1, 1, this->yhi, "Upper Y bound of plotting area" ); /* Axis reversal flags. */ astWriteInt( channel, "Xrev", 1, 0, this->xrev, "X axis reversed?" ); astWriteInt( channel, "Yrev", 1, 0, this->yrev, "Y axis reversed?" ); /* The bounds of the plotting area in the base Frame of the FrameSet supplied when the Plot was constructed. */ astWriteDouble( channel, "Xb1", 1, 1, this->bbox[ 0 ], "Lower X bound of supplied base Frame" ); astWriteDouble( channel, "Yb1", 1, 1, this->bbox[ 1 ], "Lower Y bound of supplied base Frame" ); astWriteDouble( channel, "Xb2", 1, 1, this->bbox[ 2 ], "Upper X bound of supplied base Frame" ); astWriteDouble( channel, "Yb2", 1, 1, this->bbox[ 3 ], "Upper Y bound of supplied base Frame" ); /* User-specified tick values */ for( axis = 0; axis < 3; axis++ ) { if( this->nmajtickval[ axis ] > 0 ) { sprintf( buff, "NMjTk%d", axis + 1 ); astWriteInt( channel, buff, 1, 1, this->nmajtickval[ axis ], "" ); for( itick = 0; itick < this->nmajtickval[ axis ]; itick++ ) { sprintf( buff, "MjTk%d_%d", axis + 1, itick + 1 ); astWriteDouble( channel, buff, 1, 1, this->majtickval[ axis ][ itick ], "" ); } } if( this->nmintickval[ axis ] > 0 ) { sprintf( buff, "NMnTk%d", axis + 1 ); astWriteInt( channel, buff, 1, 1, this->nmintickval[ axis ], "" ); for( itick = 0; itick < this->nmintickval[ axis ]; itick++ ) { sprintf( buff, "MnTk%d_%d", axis + 1, itick + 1 ); astWriteDouble( channel, buff, 1, 1, this->mintickval[ axis ][ itick ], "" ); } } } /* Return. */ return; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAPlot and astCheckPlot functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Plot,FrameSet) astMAKE_CHECK(Plot) AstPlot *astPlot_( void *frame_void, const float *graphbox, const double *basebox, const char *options, int *status, ...) { /* *+ * Name: * astPlot * Purpose: * Create a Plot. * Type: * Protected function. * Synopsis: * #include "plot.h" * AstPlot *astPlot( AstFrame *frame, const float *graphbox, * const double *basebox, const char *options, ..., int *status ) * Class Membership: * Plot constructor. * Description: * This function creates a new Plot and optionally initialises * its attributes. * * The supplied Frame (or the base frame if a FrameSet was supplied) is * assumed to be related to the graphics world coordinate system by a * simple shift and scale along each axis. The mapping between graphics * world coordinates and this Frame is specified by supplying the * coordinates in both systems at the bottom left and top right corners * of a box on the graphics device. By default, no graphics will be * produced outside the supplied box, but this default behaviour can be * changed by setting explicit values for the various clipping attributes. * Parameters: * frame * A pointer to a Frame or FrameSet to be annotated. If a NULL pointer * is supplied, then a default 2-D Frame will be created to which labels, * etc, can be attached by setting the relevant Frame attributes. * graphbox * A pointer to an array of 4 values giving the graphics world * coordinates of the bottom left and top right corners of a box on * the graphics output device. The first pair of values should be the * coordinates of the bottom left corner of the box and the second * pair of values should be the coordinates of the top right corner. * The horizontal axis should be given first in each pair. * basebox * A pointer to an array of 4 values giving the coordinates in the * supplied Frame, or base frame of the supplied FrameSet, at the * bottom left and top right corners of the box specified by parameter * graphbox. These should be supplied in the same order as for * parameter "graphbox". * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new Plot. The syntax used is the same as * for the astSet method and may include "printf" format * specifiers identified by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then * an optional list of arguments may follow it in order to * supply values to be substituted for these specifiers. The * rules for supplying these are identical to those for the * astSet method (and for the C "printf" function). * Returned Value: * A pointer to the new Plot. * Notes: * - The base Frame of the created Plot corresponds to the graphics world * coordinate system, and should not, in general, be changed. * - The current Frame of the created Plot corresponds to the Frame * given by parameter "frame". If a FrameSet was supplied then its * current Frame becomes the current Frame of the created Plot. * - If the supplied Frame, or base Frame if a FrameSet was supplied, * has more than 2 axes, then the sub-Frame defined by the first 2 axes * is used. * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- * Implementation Notes: * - This function implements the basic Plot constructor which * is available via the protected interface to the Plot class. * A public interface is provided by the astPlotId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "frame" parameter is of type (void *) and is converted and * validated within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstPlot *new; /* Pointer to new Plot */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ new = NULL; /* Obtain and validate a pointer to any supplied Frame structure. */ if( frame_void ){ frame = astCheckFrame( frame_void ); } else { frame = NULL; } /* Check the pointer can be used. */ if ( astOK ) { /* Initialise the Plot, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPlot( NULL, sizeof( AstPlot ), !class_init, &class_vtab, "Plot", frame, graphbox, basebox ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Plot's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new Plot. */ return new; } AstPlot *astInitPlot_( void *mem, size_t size, int init, AstPlotVtab *vtab, const char *name, AstFrame *frame, const float *graphbox, const double *basebox, int *status ) { /* *+ * Name: * astInitPlot * Purpose: * Initialise a Plot. * Type: * Protected function. * Synopsis: * #include "plot.h" * AstPlot *astInitPlot( void *mem, size_t size, int init, * AstPlotVtab *vtab, const char *name, * AstFrame *frame, const float *graphbox, * const double *basebox ) * Class Membership: * Plot initialiser. * Description: * This function is provided for use by class implementations to initialise * a new Plot object. It allocates memory (if necessary) to accommodate * the Plot plus any additional data associated with the derived class. * It then initialises a Plot structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a Plot at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Plot is to be created. This * must be of sufficient size to accommodate the Plot data * (sizeof(Plot)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the Plot (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the Plot * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the Plot's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new Plot. If NULL, the vtab associated with this class * (Plot) will be used. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * frame * A pointer to the Frame or Frameset to be annotated. * graphbox * A pointer to an array of 4 values giving the graphics coordinates * of the bottom left and top right corners of a box on the graphics * output device. The first pair of values should be the graphics * coordinates of the bottom left corner of the box and the second * pair of values are the graphics coordinates of the top right corner. * The horizontal axis should be given first in each pair. * basebox * A pointer to an array of 4 values giving the coordinates in the * supplied Frame or base Frame of the supplied FrameSet at the bottom * left and top right corners of the box specified by parameter graphbox. * These should be supplied in the same order as for parameter "graphbox". * Returned Value: * A pointer to the new Plot. * Notes: * - If the supplied Frame, or base Frame if a FrameSet was supplied, * has more than 2 axes, then the sub-Frame defined by the first 2 axes * is used. * - The current Frame of the supplied FrameSet need not be 2-dimensional. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *baseframe; /* Pointer to base frame */ AstFrame *graphicsframe; /* Pointer to graphics frame */ AstFrameSet *fset0; /* The n-D FrameSet to be annotated */ AstFrameSet *fset; /* The 2-D FrameSet to be annotated */ AstPlot *new; /* Pointer to new Plot */ AstWinMap *map; /* Mapping for converting bbox -> gbox */ char *mess; /* Pointer to a descriptive message */ double gbox[ 4 ]; /* Double precision version of "graphbox" */ int axis; /* Axis index, 0 or 1 */ int bi; /* Index of base frame */ int ci; /* Index of current frame */ int i; /* Loop count */ int id; /* Plot object id */ int naxes; /* No. of axes in frame */ /* Check the global status. */ if ( !astOK ) return NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(frame); /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ fset = NULL; mess = NULL; /* If no vtab was supplied, use the vtab for this class (Plot). */ if( !vtab ) { vtab = &class_vtab; if ( !class_init ) { astInitPlotVtab( vtab, "Plot" ); class_init = 1; } /* If necessary, initialise the virtual function table. */ } else if ( init ) { astInitPlotVtab( vtab, name ); } /* Initialise. */ new = NULL; baseframe = NULL; /* First of all we need to ensure that we have a FrameSet and a base Frame on which to base the new Plot. If a NULL Frame pointer was supplied, create a default 2-D Frame, and then create a FrameSet containing just this default Frame. Also store a pointer to a message which can be used to describe the object within error messages. */ if( !frame ){ baseframe = astFrame( 2, "", status ); fset = astFrameSet( baseframe, "", status ); mess = "default 2-d Frame"; /* If an object was supplied, report an error if it is not a Frame or an object derived from a Frame (such as a FrameSet). */ } else if( !astIsAFrame( frame ) ){ if( astOK ){ astError( AST__BDOBJ, "astInitPlot(%s): Supplied Object (class '%s') " "is not a Frame.", status, name, astGetClass( frame ) ); } /* If the supplied object is a Plot or an object derived from a Plot (a Plot is a sort of Frame and so will pass the above test), extract a FrameSet from the Plot, and clear the Domain attribute for any existing Frames which have Domain GRAPHICS. */ } else if( astIsAPlot( frame ) ){ fset0 = astFrameSet( frame, "", status ); fset = astCopy( fset0 ); fset0 = astAnnul( fset0 ); for( i = 0; i < astGetNframe( fset ); i++ ) { graphicsframe = astGetFrame( fset, i ); if( !strcmp( astGetDomain( graphicsframe ), "GRAPHICS" ) ) { astClearDomain( graphicsframe ); } graphicsframe = astAnnul( graphicsframe ); } baseframe = astGetFrame( fset, astGetBase( fset ) ); mess = "base Frame of the supplied Plot"; /* If the object is not a FrameSet, create a FrameSet holding the supplied Frame. If the Frame is not 2D, an extra 2D Frame is included in the FrameSet derived from axes 1 and 2 of the supplied Frame. This new Frame becomes the base Frame. */ } else if( !astIsAFrameSet( frame ) ){ fset0 = astFrameSet( frame, "", status ); mess = "supplied Frame"; fset = Fset2D( fset0, AST__BASE, status ); fset0 = astAnnul( fset0 ); baseframe = astGetFrame( fset, astGetBase( fset ) ); /* If a FrameSet was supplied, ensure it has a 2D base Frame. If the supplied FrameSet is not 2D, then a new base Frame is inserted into it which is derived from axes 1 and 2 of the original base Frame. */ } else { fset = Fset2D( (AstFrameSet *) frame, AST__BASE, status ); baseframe = astGetFrame( fset, astGetBase( fset ) ); mess = "base Frame of the supplied FrameSet"; } /* Check that there are 2 axes in the base frame of the FrameSet. */ naxes = astGetNaxes( baseframe ); if ( naxes != 2 && astOK ) { astError( AST__NAXIN, "astInitPlot(%s): Number of axes (%d) in the %s " "is invalid - this number should be 2.", status, name, naxes, mess ); } /* Check that neither dimension of the graphbox is zero. */ if( ( graphbox[ 2 ] == graphbox[ 0 ] || graphbox[ 3 ] == graphbox[ 1 ] ) && astOK ){ astError( AST__BADBX, "astInitPlot(%s): The plotting area has zero size " "in the graphics world coordinate system.", status, name ); } /* Check that neither dimension of the graphbox is bad. */ if( astISBAD(graphbox[0]) || astISBAD(graphbox[1]) || astISBAD(graphbox[2]) || astISBAD(graphbox[3]) ) { astError( AST__BADBX, "astInitPlot(%s): The plotting area has undefined limits " "in the graphics world coordinate system.", status, name ); } /* Check that neither dimension of the basebox is zero. */ if( astISBAD(basebox[2]) || astISBAD(basebox[0]) ) { astError( AST__BADBX, "astInitPlot(%s): The limits of the horizontal " "axis of the %s are undefined or bad.", status, name, name ); } else if( astISBAD(basebox[3]) || astISBAD(basebox[1]) ) { astError( AST__BADBX, "astInitPlot(%s): The limits of the vertical " "axis of the %s are undefined or bad.", status, name, name ); } /* Create a Frame which describes the graphics world coordinate system. */ graphicsframe = astFrame( 2, "Domain=GRAPHICS,Title=Graphical Coordinates", status ); /* Initialise a FrameSet structure (the parent class) as the first component within the Plot structure, allocating memory if necessary. The new FrameSet is initialised to hold the graphics Frame created above. */ new = (AstPlot *) astInitFrameSet( mem, size, 0, (AstFrameSetVtab *) vtab, name, graphicsframe ); if ( astOK ) { /* Initialise the Plot data. */ /* ----------------------------- */ /* Get a double precision version of "graphbox". */ gbox[ 0 ] = (double) graphbox[ 0 ]; gbox[ 1 ] = (double) graphbox[ 1 ]; gbox[ 2 ] = (double) graphbox[ 2 ]; gbox[ 3 ] = (double) graphbox[ 3 ]; /* Store the bounds in graphics coordinates of the clipping box, ensuring that the low bound is lower than the high bound. Set flags to indicate if the supplied bounds has to be reversed to do this (some graphics system have the Y axis increasing from the top of the screen to the bottom). */ if( graphbox[ 0 ] <= graphbox[ 2 ] ){ new->xlo = gbox[ 0 ]; new->xhi = gbox[ 2 ]; new->xrev = 0; } else { new->xhi = gbox[ 0 ]; new->xlo = gbox[ 2 ]; new->xrev = 1; astSetDirection( graphicsframe, 0, 0 ); } if( graphbox[ 1 ] <= graphbox[ 3 ] ){ new->ylo = gbox[ 1 ]; new->yhi = gbox[ 3 ]; new->yrev = 0; } else { new->yhi = gbox[ 1 ]; new->ylo = gbox[ 3 ]; new->yrev = 1; astSetDirection( graphicsframe, 1, 0 ); } /* Store the bounds of the Plot within the base Frame of the supplied FrameSet. */ new->bbox[ 0 ] = basebox[ 0 ]; new->bbox[ 1 ] = basebox[ 1 ]; new->bbox[ 2 ] = basebox[ 2 ]; new->bbox[ 3 ] = basebox[ 3 ]; /* We initially assume that the base Frame of the supplied FrameSet is mapped lineary onto the graphics frame. This may be changed later by assigning values to the LogPlot attributes. Create a WinMap which maps the base box (within the base Frame of the supplied FrameSet) onto the graphics box. */ map = astWinMap( 2, gbox, gbox + 2, basebox, basebox + 2, "", status ); /* Get the index of the current (physical) and base (pixel) Frames in the supplied FrameSet. */ bi = astGetBase( fset ); ci = astGetCurrent( fset ); /* Temporarily set the current Frame to be the pixel frame. */ astSetCurrent( fset, bi ); /* Add the supplied FrameSet into the Plot (i.e. FrameSet) created earlier. This leaves the graphics frame with index 1 in the returned Plot. We use the linear mapping initially. */ astAddFrame( (AstFrameSet *) new, 1, map, fset ); map = astAnnul( map ); /* Set the current Frame in the Plot to be the physical coordinate Frame (with index incremented by one because the graphics Frame has been added). */ astSetCurrent( (AstFrameSet *) new, ci + 1 ); /* Re-establish the original current Frame in the supplied FrameSet. */ astSetCurrent( fset, ci ); /* Store a value of -1.0 for Tol to indicate that no value has yet been set. This will cause a default value of 0.001 to be used. */ new->tol = -1.0; /* Set up default clipping information which gives no clipping. */ new->clip_frame = AST__NOFRAME; new->clip_lbnd = NULL; new->clip_ubnd = NULL; new->clip_axes = 0; /* Is a grid covering the plotting area required? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no) to be used. */ new->grid = -1; /* Are tick marks to be placed on both edges in a pair of opposite edges? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 1 (yes) to be used. */ new->tickall = -1; /* Graphics context identifier */ new->grfcontext = NULL; new->grfcontextID = NULL; /* Shoudl ast Grid draw a boundary round the regions of valid coordinates? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 1 (yes) to be used. */ new->border = -1; /* Should graphics be drawn invisible? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no) to be used. */ new->invisible = -1; /* By default clip markers but not curves at the boundary of the plotting area. This was the only behaviour available prior to the introduction of the Clip attribute, and is chosen as the default to maintain backwards compatibility. */ new->clip = -1; /* Is clipping to be done using a logical OR operation between the axes? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no, i.e. a logical AND) to be used. */ new->clipop = -1; /* Is the graphics interface registered using astGrfSet to be used? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no, i.e. use the graphics interface selected at link-time) to be used. */ new->grf = -1; /* Wrapper functions to call the drawing routines. These are the default wrappers which call GRF routines written in C. Alternative wrappers are defined in fplot.c for use with GRF routines written in F77. */ new->GAttr = CGAttrWrapper; new->GBBuf = CGBBufWrapper; new->GEBuf = CGEBufWrapper; new->GFlush = CGFlushWrapper; new->GLine = CGLineWrapper; new->GMark = CGMarkWrapper; new->GText = CGTextWrapper; new->GCap = CGCapWrapper; new->GTxExt = CGTxExtWrapper; new->GScales = CGScalesWrapper; new->GQch = CGQchWrapper; for( i = 0; i < AST__NGRFFUN; i++ ) new->grffun[i] = NULL; new->grfstack = NULL; new->grfnstack = 0; /* Is a title to be added to an annotated grid? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 1 (yes) to be used. */ new->drawtitle = -1; /* Are escape sequences within text strings to be interpreted? If not, they are printed literally. Store a value of -1 when not set. This will cause a default value of 1 (yes) to be used. */ new->escape = -1; /* A boolean attribute indicating where numerical labels are to be placed; zero implies round the edges of the plotting area; non-zero implies within the plotting area. The unset value of -9999 yields a default of zero. */ new->labelling = -9999; /* Graphics attributes. Default behaviour is to use the current values. */ for( id = 0; id < AST__NPID; id++ ){ new->style[ id ] = -1; new->font[ id ] = -1; new->colour[ id ] = -1; new->width[ id ] = AST__BAD; new->size[ id ] = AST__BAD; } /* The space between the top edge and the grid title as a fraction of the minimum dimension of the plotting area. Store AST__BAD to indicate that no value has been set. This will cause a default of 0.05 to be used. */ new->titlegap = AST__BAD; /* Initialise the protected Ink attribute so that visible ink is used. */ new->ink = -1; /* A stack of AstGat pointers used to store the graphical attributes for text within strings which include graphical escape sequences. */ new->gat = NULL; new->ngat = 0; /* Now set the attribute values for each axis. The arrays stored in the Plot struture allow for 3 graphics axes (e.g. as used by a Plot3D) so we initialise 3 axes here even though the Plot class only uses 2. */ for( axis = 0; axis < 3; axis++ ) { /* Are curves to be drawn through the tick marks even if no grid is produced? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 1 (yes) to be used. */ new->drawaxes[ axis ] = -1; /* Are adjacent numerical axis labels to be abbreviated by removing matching leading fields? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 1 (yes) to be used. */ new->abbrev[ axis ] = -1; /* The length of the major tick marks as a fraction of the minimum dimension of the plotting area. Store AST__BAD to indicate that no value has been set. This will cause a default of 0.015 to be used. */ new->majticklen[ axis ] = AST__BAD; /* The length of the minor tick marks as a fraction of the minimum dimension of the plotting area. Store AST__BAD to indicate that no value has been set. This will cause a default of 0.007 to be used. */ new->minticklen[ axis ] = AST__BAD; /* Are numeric labels to be drawn upright? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no) to be used. */ new->labelup[ axis ] = -1; /* The space between an axis and its numeric labels as a fraction of the minimum dimension of the plotting area. Store AST__BAD to indicate that no value has been set. This will cause a default of 0.01 to be used. */ new->numlabgap[ axis ] = AST__BAD; new->textlabgap[ axis ] = AST__BAD; /* The edges on which to put labels for axes 1 and 2. Store values of -1 to indicate that no values have been set. This will cause default values to be used. */ new->edge[ axis ] = -1; /* The placement of labels within the plotting area will be done automatically by default. */ new->labelat[ axis ] = AST__BAD; /* The central tick is placed automatically by default. */ new->centre[ axis ] = AST__BAD; /* The gap between tick marks and the number of minor tick marks will be found automatically by default. */ new->gap[ axis ] = AST__BAD; new->loggap[ axis ] = AST__BAD; new->mintick[ axis ] = -1; /* Both axes will be labelled by default. */ new->numlab[ axis ] = -1; new->textlab[ axis ] = -1; new->labelunits[ axis ] = -1; /* Log/lin attributes. Default value is to use linear axes. */ new->logplot[ axis ] = -1; new->logticks[ axis ] = -1; new->loglabel[ axis ] = -1; /* Initialise the components used to store the values actually used for attributes which have dynamic defaults. */ new->ulglb[ axis ] = new->loglabel[ axis ]; new->ulgtk[ axis ] = new->logticks[ axis ]; new->uloggap[ axis ] = new->loggap[ axis ]; new->ugap[ axis ] = new->gap[ axis ]; new->ucentre[ axis ] = new->centre[ axis ]; new->uedge[ axis ] = new->edge[ axis ]; new->ulblat[ axis ] = new->labelat[ axis ]; new->ulbunit[ axis ] = new->labelunits[ axis ]; new->umintk[ axis ] = new->mintick[ axis ]; new->utxtlb[ axis ] = new->textlab[ axis ]; new->umjtkln[ axis ] = new->majticklen[ axis ]; /* Initialise the arrays used to hold information describing the tick marks that have been drawn for the axis. */ new->majtickgx[ axis ] = NULL; new->majtickgy[ axis ] = NULL; new->majtickcount[ axis ] = 0; new->mintickgx[ axis ] = NULL; new->mintickgy[ axis ] = NULL; new->mintickcount[ axis ] = 0; new->nmajtickval[ axis ] = 0; new->majtickval[ axis ] = NULL; new->nmintickval[ axis ] = 0; new->mintickval[ axis ] = NULL; } new->ugrid = new->grid; new->ulbling = new->labelling; new->uborder = new->border; } /* Annul the frame. */ graphicsframe = astAnnul( graphicsframe ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); /* Annul the pointer to the base Frame and FrameSet. */ baseframe = astAnnul( baseframe ); fset = astAnnul( fset ); /* Return a pointer to the new object. */ return new; } AstPlot *astLoadPlot_( void *mem, size_t size, AstPlotVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadPlot * Purpose: * Load a Plot. * Type: * Protected function. * Synopsis: * #include "Plot.h" * AstPlot *astLoadPlot( void *mem, size_t size, * AstPlotVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * Plot loader. * Description: * This function is provided to load a new Plot using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Plot structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a Plot at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the Plot is to be * loaded. This must be of sufficient size to accommodate the * Plot data (sizeof(Plot)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Plot (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Plot structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstPlot) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Plot. If this is NULL, a pointer * to the (static) virtual function table for the Plot class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Plot" is used instead. * Returned Value: * A pointer to the new Plot. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPlot *new; /* Pointer to the new Plot */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ char *text; /* Textual version of integer value */ int axis; /* Zero based axis index */ int id; /* Zero based graphical object id */ int i; /* Loop count */ int itick; /* Tick mark index */ int nax; /* Number of base Frame axes */ int ntick; /* Total number of ticks */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Plot. In this case the Plot belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstPlot ); vtab = &class_vtab; name = "Plot"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitPlotVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Plot. */ new = astLoadFrameSet( mem, size, (AstFrameSetVtab *) vtab, name, channel ); if ( astOK ) { /* Get the number of graphics (base) frame axes - 2 for a Plot, 3 for a Plot3D. */ nax = astGetNin( new ); /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Plot" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Tol. */ /* ---- */ new->tol = astReadDouble( channel, "tol", -1.0 ); if ( TestTol( new, status ) ) SetTol( new, new->tol, status ); /* Grid. */ /* ----- */ new->grid = astReadInt( channel, "grid", -1 ); if ( TestGrid( new, status ) ) SetGrid( new, new->grid, status ); /* TickAll. */ /* -------- */ new->tickall = astReadInt( channel, "tckall", -1 ); if ( TestTickAll( new, status ) ) SetTickAll( new, new->tickall, status ); /* ForceExterior. */ /* -------- */ new->forceexterior = astReadInt( channel, "frcext", -1 ); if ( TestForceExterior( new, status ) ) SetForceExterior( new, new->forceexterior, status ); /* Invisible. */ /* ---------- */ new->invisible = astReadInt( channel, "invsbl", -1 ); if ( TestInvisible( new, status ) ) SetInvisible( new, new->invisible, status ); /* Border. */ /* -------- */ new->border = astReadInt( channel, "border", -1 ); if ( TestBorder( new, status ) ) SetBorder( new, new->border, status ); /* ClipOp. */ /* ------- */ new->clipop = astReadInt( channel, "clpop", -1 ); if ( TestClipOp( new, status ) ) SetClipOp( new, new->clipop, status ); /* Clip. */ /* ----- */ new->clip = astReadInt( channel, "clip", -1 ); if ( TestClip( new, status ) ) SetClip( new, new->clip, status ); /* DrawTitle. */ /* --------- */ new->drawtitle = astReadInt( channel, "drwttl", -1 ); if ( TestDrawTitle( new, status ) ) SetDrawTitle( new, new->drawtitle, status ); /* LabelUp(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lblup%d", axis + 1 ); new->labelup[ axis ] = astReadInt( channel, buff, -1 ); if ( TestLabelUp( new, axis, status ) ) SetLabelUp( new, axis, new->labelup[ axis ], status ); } /* LogPlot(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lgplt%d", axis + 1 ); new->logplot[ axis ] = astReadInt( channel, buff, -1 ); if ( TestLogPlot( new, axis, status ) ) SetLogPlot( new, axis, new->logplot[ axis ], status ); } /* LogTicks(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lgtck%d", axis + 1 ); new->logticks[ axis ] = astReadInt( channel, buff, -1 ); if ( TestLogTicks( new, axis, status ) ) SetLogTicks( new, axis, new->logticks[ axis ], status ); } /* LogLabel(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lglbl%d", axis + 1 ); new->loglabel[ axis ] = astReadInt( channel, buff, -1 ); if ( TestLogLabel( new, axis, status ) ) SetLogLabel( new, axis, new->loglabel[ axis ], status ); } /* DrawAxes. */ /* --------- */ new->drawaxes[ 0 ] = astReadInt( channel, "drwaxs", -1 ); if( new->drawaxes[ 0 ] != -1 ) { new->drawaxes[ 1 ] = new->drawaxes[ 0 ]; if ( TestDrawAxes( new, 0, status ) ) SetDrawAxes( new, 0, new->drawaxes[ 0 ], status ); if ( TestDrawAxes( new, 1, status ) ) SetDrawAxes( new, 1, new->drawaxes[ 1 ], status ); } else { for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "drwaxs%d", axis + 1 ); new->drawaxes[ axis ] = astReadInt( channel, buff, -1 ); if ( TestDrawAxes( new, axis, status ) ) SetDrawAxes( new, axis, new->drawaxes[ axis ], status ); } } /* Abbrev. */ /* ------- */ new->abbrev[ 0 ] = astReadInt( channel, "abbrv", -1 ); if( new->abbrev[ 0 ] != -1 ) { new->abbrev[ 1 ] = new->abbrev[ 0 ]; if ( TestAbbrev( new, 0, status ) ) SetAbbrev( new, 0, new->abbrev[ 0 ], status ); if ( TestAbbrev( new, 1, status ) ) SetAbbrev( new, 1, new->abbrev[ 1 ], status ); } else { for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "abbrv%d", axis + 1 ); new->abbrev[ axis ] = astReadInt( channel, buff, -1 ); if ( TestAbbrev( new, axis, status ) ) SetAbbrev( new, axis, new->abbrev[ axis ], status ); } } /* Escape. */ /* ------- */ new->escape = astReadInt( channel, "escape", -1 ); if ( TestEscape( new, status ) ) SetEscape( new, new->escape, status ); /* LabelAt(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lblat%d", axis + 1 ); new->labelat[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestLabelAt( new, axis, status ) ) SetLabelAt( new, axis, new->labelat[ axis ], status ); } /* Centre(axis). */ /* ------------ */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "cen%d", axis + 1 ); new->centre[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestCentre( new, axis, status ) ) SetCentre( new, axis, new->centre[ axis ], status ); } /* Gap(axis). */ /* ---------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "gap%d", axis + 1 ); new->gap[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestGap( new, axis, status ) ) SetGap( new, axis, new->gap[ axis ], status ); } /* LogGap(axis). */ /* ------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lggap%d", axis + 1 ); new->loggap[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestLogGap( new, axis, status ) ) SetLogGap( new, axis, new->loggap[ axis ], status ); } /* NumLabGap(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "nmgap%d", axis + 1 ); new->numlabgap[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestNumLabGap( new, axis, status ) ) SetNumLabGap( new, axis, new->numlabgap[ axis ], status ); } /* TextLabGap(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "txgap%d", axis + 1 ); new->textlabgap[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestTextLabGap( new, axis, status ) ) SetTextLabGap( new, axis, new->textlabgap[ axis ], status ); } /* NumLab(axis). */ /* ---------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "nmlbl%d", axis + 1 ); new->numlab[ axis ] = astReadInt( channel, buff, -1 ); if ( TestNumLab( new, axis, status ) ) SetNumLab( new, axis, new->numlab[ axis ], status ); } /* MinTick(axis). */ /* --------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "mntks%d", axis + 1 ); new->mintick[ axis ] = astReadInt( channel, buff, -1 ); if ( TestMinTick( new, axis, status ) ) SetMinTick( new, axis, new->mintick[ axis ], status ); } /* TextLab(axis). */ /* -------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "txlbl%d", axis + 1 ); new->textlab[ axis ] = astReadInt( channel, buff, -1 ); if ( TestTextLab( new, axis, status ) ) SetTextLab( new, axis, new->textlab[ axis ], status ); } /* LabelUnits(axis). */ /* --------------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "lbunt%d", axis + 1 ); new->labelunits[ axis ] = astReadInt( channel, buff, -1 ); if ( TestLabelUnits( new, axis, status ) ) SetLabelUnits( new, axis, new->labelunits[ axis ], status ); } /* Style(object). */ /* ------------ */ for( id = 0; id < AST__NPID; id++ ){ (void) sprintf( buff, "style%d", id + 1 ); new->style[ id ] = astReadInt( channel, buff, -1 ); if ( TestStyle( new, id, status ) ) SetStyle( new, id, new->style[ id ], status ); } /* Font(object). */ /* ----------- */ for( id = 0; id < AST__NPID; id++ ){ (void) sprintf( buff, "font%d", id + 1 ); new->font[ id ] = astReadInt( channel, buff, -1 ); if ( TestFont( new, id, status ) ) SetFont( new, id, new->font[ id ], status ); } /* Colour(object). */ /* --------------- */ for( id = 0; id < AST__NPID; id++ ){ (void) sprintf( buff, "col%d", id + 1 ); new->colour[ id ] = astReadInt( channel, buff, -1 ); if ( TestColour( new, id, status ) ) SetColour( new, id, new->colour[ id ], status ); } /* Width(object). */ /* ------------ */ for( id = 0; id < AST__NPID; id++ ){ (void) sprintf( buff, "width%d", id + 1 ); new->width[ id ] = astReadDouble( channel, buff, AST__BAD ); if ( TestWidth( new, id, status ) ) SetWidth( new, id, new->width[ id ], status ); } /* Size(object). */ /* ----------- */ for( id = 0; id < AST__NPID; id++ ){ (void) sprintf( buff, "size%d", id + 1 ); new->size[ id ] = astReadDouble( channel, buff, AST__BAD ); if ( TestSize( new, id, status ) ) SetSize( new, id, new->size[ id ], status ); } /* TitleGap. */ /* --------- */ new->titlegap = astReadDouble( channel, "ttlgap", AST__BAD ); if ( TestTitleGap( new, status ) ) SetTitleGap( new, new->titlegap, status ); /* MajTickLen. */ /* ----------- */ /* Retained in order to read old Plots - new Plots use MajTickLen(axis). */ new->majticklen[ 0 ] = astReadDouble( channel, "mjtkln", AST__BAD ); if( new->majticklen[ 0 ] != AST__BAD ) { new->majticklen[ 1 ] = new->majticklen[ 0 ]; if ( TestMajTickLen( new, 0, status ) ) SetMajTickLen( new, 0, new->majticklen[ 0 ], status ); if ( TestMajTickLen( new, 1, status ) ) SetMajTickLen( new, 1, new->majticklen[ 1 ], status ); /* MajTickLen(axis). */ /* ----------------- */ } else { for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "mjtkln%d", axis + 1 ); new->majticklen[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestMajTickLen( new, axis, status ) ) SetMajTickLen( new, axis, new->majticklen[ axis ], status ); } } /* MinTickLen. */ /* ----------- */ /* Retained in order to read old Plots - new Plots use MinTickLen(axis). */ new->minticklen[ 0 ] = astReadDouble( channel, "mntkln", AST__BAD ); if( new->minticklen[ 0 ] != AST__BAD ) { new->minticklen[ 1 ] = new->minticklen[ 0 ]; if ( TestMinTickLen( new, 0, status ) ) SetMinTickLen( new, 0, new->minticklen[ 0 ], status ); if ( TestMinTickLen( new, 1, status ) ) SetMinTickLen( new, 1, new->minticklen[ 1 ], status ); /* MinTickLen(axis). */ /* ----------------- */ } else { for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "mntkln%d", axis + 1 ); new->minticklen[ axis ] = astReadDouble( channel, buff, AST__BAD ); if ( TestMinTickLen( new, axis, status ) ) SetMinTickLen( new, axis, new->minticklen[ axis ], status ); } } /* Labelling. */ /* ---------- */ text = astReadString( channel, "lbling", " " ); if( astOK && strcmp( text, " " ) ) { new->labelling = FindString( 2, xlbling, text, "the Plot component 'Lbling'", "astRead", astGetClass( channel ), status ); } else { new->labelling = -9999; } if ( TestLabelling( new, status ) ) SetLabelling( new, new->labelling, status ); text = astFree( text ); /* Edge(axis). */ /* ----------- */ for( axis = 0; axis < nax; axis++ ){ (void) sprintf( buff, "edge%d", axis + 1 ); text = astReadString( channel, buff, " " ); if( astOK && strcmp( text, " " ) ) { new->edge[ axis ] = FindString( 4, xedge, text, "the Plot component 'Edge'", "astRead", astGetClass( channel ), status ); } else { new->edge[ axis ] = -1; } if ( TestEdge( new, axis, status ) ) SetEdge( new, axis, new->edge[ axis ], status ); text = astFree( text ); } /* Now do instance variables which are not attributes. */ /* =================================================== */ /* We have no graphics context. */ new->grfcontext = NULL; new->grfcontextID = NULL; /* Initialise the protected Ink attribute so that visible ink is used. */ new->ink = -1; /* The number of bounds supplied for the clipping volume. */ new->clip_axes = astReadInt( channel, "clpaxs", 0 ); if ( new->clip_axes < 0 ) new->clip_axes = 0; /* The index of the clipping Frame within the Plot. */ new->clip_frame = astReadInt( channel, "clpfrm", AST__NOFRAME ); /* If necessary, allocate memory to hold the bounds of the clipping volume. */ if( new->clip_axes > 0 ){ new->clip_lbnd = astMalloc( sizeof( double ) * (size_t) new->clip_axes ); new->clip_ubnd = astMalloc( sizeof( double ) * (size_t) new->clip_axes ); /* If an error occurs, ensure that all allocated memory is freed. */ if ( !astOK ) { new->clip_lbnd = (double *) astFree( (void *) new->clip_lbnd ); new->clip_ubnd = (double *) astFree( (void *) new->clip_ubnd ); /* Otherwise, store the bounds. Use extreme defaults if no values are available. */ } else { for( axis = 0; axis < new->clip_axes; axis++ ){ (void) sprintf( buff, "clplb%d", axis + 1 ); new->clip_lbnd[ axis ] = astReadDouble( channel, buff, -DBL_MAX ); (void) sprintf( buff, "clpub%d", axis + 1 ); new->clip_ubnd[ axis ] = astReadDouble( channel, buff, DBL_MAX ); } } /* If there are no clipping axes, store NULL pointers for the bounds arrays. */ } else { new->clip_lbnd = NULL; new->clip_ubnd = NULL; } /* The bounds of the plotting area in graphics coords. */ new->xlo = astReadDouble( channel, "xlo", 0.0 ); new->xhi = astReadDouble( channel, "xhi", 1.0 ); new->ylo = astReadDouble( channel, "ylo", 0.0 ); new->yhi = astReadDouble( channel, "yhi", 1.0 ); /* Axis reversal flags. */ new->xrev = astReadInt( channel, "xrev", 0 ); new->yrev = astReadInt( channel, "yrev", 0 ); /* The bounds of the plotting area in the base Frame of the FrameSet supplied when the Plot was constructed. */ new->bbox[ 0 ] = astReadDouble( channel, "xb1", AST__BAD ); new->bbox[ 1 ] = astReadDouble( channel, "yb1", AST__BAD ); new->bbox[ 2 ] = astReadDouble( channel, "xb2", AST__BAD ); new->bbox[ 3 ] = astReadDouble( channel, "yb2", AST__BAD ); /* Grf. */ new->grf = -1; new->GAttr = CGAttrWrapper; new->GBBuf = CGBBufWrapper; new->GEBuf = CGEBufWrapper; new->GFlush = CGFlushWrapper; new->GLine = CGLineWrapper; new->GMark = CGMarkWrapper; new->GText = CGTextWrapper; new->GCap = CGCapWrapper; new->GTxExt = CGTxExtWrapper; new->GScales = CGScalesWrapper; new->GQch = CGQchWrapper; for( i = 0; i < AST__NGRFFUN; i++ ) new->grffun[i] = NULL; new->grfstack = NULL; new->grfnstack = 0; /* A stack of AstGat pointers used to store the graphical attributes for text within strings which include graphical escape sequences. */ new->gat = NULL; new->ngat = 0; /* Arrays holding user-specified major and minot tick mark values. */ for( axis = 0; axis < 3; axis++ ) { sprintf( buff, "nmjtk%d", axis + 1 ); ntick = astReadInt( channel, buff, 0 ); new->nmajtickval[ axis ] = ntick; new->majtickval[ axis ] = astMalloc( ntick*sizeof( double ) ); for( itick = 0; itick < ntick; itick++ ) { sprintf( buff, "mjtk%d_%d", axis + 1, itick + 1 ); new->majtickval[ axis ][ itick ] = astReadDouble( channel, buff, AST__BAD ); } sprintf( buff, "nmntk%d", axis + 1 ); ntick = astReadInt( channel, buff, 0 ); new->nmintickval[ axis ] = ntick; new->mintickval[ axis ] = astMalloc( ntick*sizeof( double ) ); for( itick = 0; itick < ntick; itick++ ) { sprintf( buff, "mntk%d_%d", axis + 1, itick + 1 ); new->mintickval[ axis ][ itick ] = astReadDouble( channel, buff, AST__BAD ); } } /* Initialise the arrays used to hold information describing the tick marks that have already been drawn for each axis. */ for( axis = 0; axis < 3; axis++ ) { new->majtickgx[ axis ] = NULL; new->majtickgy[ axis ] = NULL; new->majtickcount[ axis ] = 0; new->mintickgx[ axis ] = NULL; new->mintickgy[ axis ] = NULL; new->mintickcount[ axis ] = 0; } /* If an error occurred, clean up by deleting the new Plot. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Plot pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astBBuf_( AstPlot *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,BBuf))(this, status ); } int astBorder_( AstPlot *this, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,Plot,Border))(this, status ); } void astBoundingBox_( AstPlot *this, float lbnd[2], float ubnd[2], int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,BoundingBox))(this,lbnd,ubnd, status ); } void astClip_( AstPlot *this, int iframe, const double lbnd[], const double ubnd[], int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,Clip))(this,iframe,lbnd,ubnd, status ); } void astGrid_( AstPlot *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,Grid))(this, status ); } int astCvBrk_( AstPlot *this, int ibrk, double *brk, double *vbrk, double *len, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,Plot,CvBrk))(this,ibrk,brk,vbrk,len, status ); } void astEBuf_( AstPlot *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,EBuf))(this, status ); } void astMirror_( AstPlot *this, int axis, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,Mirror))(this,axis, status ); } AstPointSet *astGetDrawnTicks_( AstPlot *this, int axis, int major, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,Plot,GetDrawnTicks))(this,axis,major, status ); } void astSetTickValues_( AstPlot *this, int axis, int nmajor, double *major, int nminor, double *minor, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,SetTickValues))(this,axis,nmajor,major,nminor,minor, status ); } void astCopyPlotDefaults_( AstPlot *this, int axis, AstPlot *dplot, int daxis, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,CopyPlotDefaults))(this,axis,dplot,daxis, status ); } int astGetLabelUnits_( AstPlot *this, int axis, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,Plot,GetLabelUnits))(this,axis, status ); } void astMark_( AstPlot *this, int nmark, int ncoord, int indim, const double *in, int type, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Plot,Mark))( this, nmark, ncoord, indim, in, type, status ); } void astText_( AstPlot *this, const char *text, const double pos[], const float up[], const char *just, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Plot,Text))( this, text, pos, up, just, status ); } void astGridLine_( AstPlot *this, int axis, const double start[], double length, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GridLine))(this,axis,start,length, status ); } void astCurve_( AstPlot *this, const double start[], const double finish[], int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,Curve))(this,start,finish, status ); } void astGenCurve_( AstPlot *this, AstMapping *map, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GenCurve))(this,map, status ); } void astPolyCurve_( AstPlot *this, int npoint, int ncoord, int dim, const double *in, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,PolyCurve))(this,npoint,ncoord,dim,in, status ); } void astGrfSet_( AstPlot *this, const char *name, AstGrfFun fun, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GrfSet))(this,name,fun, status ); } void astGrfPush_( AstPlot *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GrfPush))(this, status ); } void astGrfPop_( AstPlot *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GrfPop))(this, status ); } void astGrfWrapper_( AstPlot *this, const char *name, AstGrfWrap wrapper, int *status ){ if( !astOK ) return; (**astMEMBER(this,Plot,GrfWrapper))(this,name,wrapper, status ); } void astSetLogPlot_( AstPlot *this, int axis, int value, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Plot,SetLogPlot))( this, axis, value, status ); } void astClearLogPlot_( AstPlot *this, int axis, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Plot,ClearLogPlot))( this, axis, status ); } AstKeyMap *astGetGrfContext_( AstPlot *this, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Plot,GetGrfContext))( this, status ); } /* Special public interface functions. */ /* =================================== */ /* These provide the public interface to certain special functions whose public interface cannot be handled using macros (such as astINVOKE) alone. In general, they are named after the corresponding protected version of the function, but with "Id" appended to the name. */ /* Special interface function implementations. */ /* ------------------------------------------- */ AstPlot *astPlotId_( void *frame_void, const float graphbox[4], const double basebox[4], const char *options, ... ) { /* *++ * Name: c astPlot f AST_PLOT * Purpose: * Create a Plot. * Type: * Public function. * Synopsis: c #include "plot.h" c AstPlot *astPlot( AstFrame *frame, const float graphbox[ 4 ], c const double basebox[ 4 ], const char *options, ... ) f RESULT = AST_PLOT( FRAME, GRAPHBOX, BASEBOX, OPTIONS, STATUS ) * Class Membership: * Plot constructor. * Description: * This function creates a new Plot and optionally initialises its * attributes. * * A Plot is a specialised form of FrameSet, in which the base * Frame describes a "graphical" coordinate system and is * associated with a rectangular plotting area in the underlying * graphics system. This plotting area is where graphical output * appears. It is defined when the Plot is created. * * The current Frame of a Plot describes a "physical" coordinate * system, which is the coordinate system in which plotting * operations are specified. The results of each plotting operation * are automatically transformed into graphical coordinates so as * to appear in the plotting area (subject to any clipping which * may be in effect). * * Because the Mapping between physical and graphical coordinates * may often be non-linear, or even discontinuous, most plotting * does not result in simple straight lines. The basic plotting * element is therefore not a straight line, but a geodesic curve c (see astCurve). A Plot also provides facilities for drawing c markers or symbols (astMark), text (astText) and grid lines c (astGridLine). It is also possible to draw curvilinear axes with c optional coordinate grids (astGrid). f (see AST_CURVE). A Plot also provides facilities for drawing f markers or symbols (AST_MARK), text (AST_TEXT) and grid lines f (AST_GRIDLINE). It is also possible to draw curvilinear axes f with optional coordinate grids (AST_GRID). * A range of Plot attributes is available to allow precise control * over the appearance of graphical output produced by these c functions. f routines. * * You may select different physical coordinate systems in which to * plot (including the native graphical coordinate system itself) * by selecting different Frames as the current Frame of a Plot, * using its Current attribute. You may also set up clipping (see c astClip) to limit the extent of any plotting you perform, and f AST_CLIP) to limit the extent of any plotting you perform, and * this may be done in any of the coordinate systems associated * with the Plot, not necessarily the one you are plotting in. * * Like any FrameSet, a Plot may also be used as a Frame. In this * case, it behaves like its current Frame, which describes the * physical coordinate system. * * When used as a Mapping, a Plot describes the inter-relation * between graphical coordinates (its base Frame) and physical * coordinates (its current Frame). It differs from a normal * FrameSet, however, in that an attempt to transform points which * lie in clipped areas of the Plot will result in bad coordinate * values (AST__BAD). * Parameters: c frame f FRAME = INTEGER (Given) * Pointer to a Frame describing the physical coordinate system * in which to plot. A pointer to a FrameSet may also be given, * in which case its current Frame will be used to define the * physical coordinate system and its base Frame will be mapped * on to graphical coordinates (see below). * * If a null Object pointer (AST__NULL) is given, a default * 2-dimensional Frame will be used to describe the physical * coordinate system. Labels, etc. may then be attached to this * by setting the appropriate Frame attributes * (e.g. Label(axis)) for the Plot. c graphbox f GRAPHBOX( 4 ) = REAL (Given) * An array giving the position and extent of the plotting area * (on the plotting surface of the underlying graphics system) * in which graphical output is to appear. This must be * specified using graphical coordinates appropriate to the * underlying graphics system. * * The first pair of values should give the coordinates of the * bottom left corner of the plotting area and the second pair * should give the coordinates of the top right corner. The * coordinate on the horizontal axis should be given first in * each pair. Note that the order in which these points are * given is important because it defines up, down, left and * right for subsequent graphical operations. c basebox f BASEBOX( 4 ) = DOUBLE PRECISION (Given) * An array giving the coordinates of two points in the supplied * Frame (or in the base Frame if a FrameSet was supplied) which * correspond to the bottom left and top right corners of the * plotting area, as specified above. This range of coordinates * will be mapped linearly on to the plotting area. The * coordinates should be given in the same order as above. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new Plot. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new Plot. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astPlot() f AST_PLOT * A pointer to the new Plot. * Notes: * - The base Frame of the returned Plot will be a new Frame which * is created by this function to represent the coordinate system * of the underlying graphics system (graphical coordinates). It is * given a Frame index of 1 within the Plot. The choice of base * Frame (Base attribute) should not, in general, be changed once a * Plot has been created (although you could use this as a way of * moving the plotting area around on the plotting surface). c - If a Frame is supplied (via the "frame" pointer), then it f - If a Frame is supplied (via the FRAME pointer), then it * becomes the current Frame of the new Plot and is given a Frame * index of 2. c - If a FrameSet is supplied (via the "frame" pointer), then f - If a FrameSet is supplied (via the FRAME pointer), then * all the Frames within this FrameSet become part of the new Plot * (where their Frame indices are increased by 1), with the * FrameSet's current Frame becoming the current Frame of the Plot. * - If a null Object pointer (AST__NULL) is supplied (via the c "frame" pointer), then the returned Plot will contain two f FRAME pointer), then the returned Plot will contain two * Frames, both created by this function. The base Frame will * describe graphics coordinates (as above) and the current Frame * will be a basic Frame with no attributes set (this will * therefore give default values for such things as the Plot Title * and the Label on each axis). Physical coordinates will be mapped * linearly on to graphical coordinates. * - An error will result if the Frame supplied (or the base Frame * if a FrameSet was supplied) is not 2-dimensional. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astPlot constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astPlot_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - Because no checking or casting of arguments is performed * before the function is invoked, the "frame" parameter is of type * (void *) and is converted from an ID value to a pointer and * validated within the function itself. * - The variable argument list also prevents this function from * invoking astPlot_ directly, so it must be a * re-implementation of it in all respects, except for the * conversions between IDs and pointers on input/output of Objects. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *frame; /* Pointer to Frame structure */ AstPlot *new; /* Pointer to new Plot */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get apointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ new = NULL; /* Obtain a Frame pointer from any ID supplied and validate the pointer to ensure it identifies a valid Frame. */ if( frame_void ){ frame = astVerifyFrame( astMakePointer( frame_void ) ); } else { frame = NULL; } /* Check the pointer can be used. */ if ( astOK ) { /* Initialise the Plot, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPlot( NULL, sizeof( AstPlot ), !class_init, &class_vtab, "Plot", frame, graphbox, basebox ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Plot's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return an ID value for the new Plot. */ return astMakeId( new ); } ./ast-7.3.3/ast_cpp.in0000644000175000017500000000062512262533650013126 0ustar olesoles # Replacement for the C pre-processor command "cpp" which is not # always available. This uses the compiler command "cc" to do the same # thing. Also, this reads from standard input (which "cc" won't do). # # The name of the CPP processor is substituted in by the ./configure script, # based on the result of the AC_PROG_CPP test. cat >/tmp/ast_cpp_$$.c @CPP@ /tmp/ast_cpp_$$.c rm -f /tmp/ast_cpp_$$.c ./ast-7.3.3/stc.c0000644000175000017500000035200412262533650012103 0ustar olesoles/* *class++ * Name: * Stc * Purpose: * Represents an instance of the IVOA STC class. * Constructor Function: c astStc f AST_STC * Description: * The Stc class is an implementation of the IVOA STC class which forms * part of the IVOA Space-Time Coordinate Metadata system. See: * * http://hea-www.harvard.edu/~arots/nvometa/STC.html * * The Stc class does not have a constructor function of its own, as it * is simply a container class for a family of specialised sub-classes * including StcCatalogEntryLocation, StcResourceProfile, StcSearchLocation * and StcObsDataLocation. * Inheritance: * The Stc class inherits from the Region class. * Attributes: * In addition to those attributes common to all Regions, every * Stc also has the following attributes: * * - RegionClass: The class name of the encapsulated Region. * Functions: c In addition to those functions applicable to all Regions, the c following functions may also be applied to all Stc's: f In addition to those routines applicable to all Regions, the f following routines may also be applied to all Stc's: * c - astGetStcRegion: Get a pointer to the encapsulated Region f - AST_GETSTCREGION: Get a pointer to the encapsulated Region c - astGetStcCoord: Get information about an AstroCoords element f - AST_GETSTCCOORD: Get information about an AstroCoords element c - astGetStcNCoord: Returns the number of AstroCoords elements in an Stc f - AST_GETSTCNCOORD: Returns the number of AstroCoords elements in an Stc * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2008 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 23-NOV-2004 (DSB): * Original version. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 13-MAR-2009 (DSB): * Over-ride astRegBasePick. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Stc /* The number of components in an AstroCoords element which are described using a Region within a KeyMap. */ #define NREG 5 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "unitmap.h" /* Unit Mappings */ #include "region.h" /* Regions (parent class) */ #include "channel.h" /* I/O channels */ #include "stc.h" /* Interface definition for this class */ #include "keymap.h" /* Lists of value/key pairs */ #include "pointlist.h" /* Individual points in a Frame */ #include "ellipse.h" /* Ellipses within a Frame */ #include "interval.h" /* Axis intervals within a Frame */ #include "prism.h" /* Extrusions into higher dimensions */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstMapping *(* parent_simplify)( AstMapping *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstRegion *(* parent_getdefunc)( AstRegion *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_equal)( AstObject *, AstObject *, int * ); static int (* parent_getobjsize)( AstObject *, int * ); static int (* parent_getusedefs)( AstObject *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_setregfs)( AstRegion *, AstFrame *, int * ); static void (*parent_regclearattrib)( AstRegion *, const char *, char **, int * ); static void (*parent_regsetattrib)( AstRegion *, const char *, char **, int * ); static void (* parent_clearnegated)( AstRegion *, int * ); static void (* parent_clearclosed)( AstRegion *, int * ); static void (* parent_clearfillfactor)( AstRegion *, int * ); static void (* parent_clearmeshsize)( AstRegion *, int * ); static void (* parent_setclosed)( AstRegion *, int, int * ); static void (* parent_setfillfactor)( AstRegion *, double, int * ); static void (* parent_setmeshsize)( AstRegion *, int, int * ); static void (* parent_setnegated)( AstRegion *, int, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* The keys associated with each component of an AstroCoords element within KeyMap */ static const char *regkey[ NREG ] = { AST__STCERROR, AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE }; /* The comments associated with each component of an AstroCoords element within KeyMap */ static const char *regcom[ NREG ] = { "AstroCoords error region", "AstroCoords resolution region", "AstroCoords size region", "AstroCoords pixel size region", "AstroCoords value region" }; #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Stc) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(Stc,Class_Init) #define class_vtab astGLOBAL(Stc,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstStcVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstKeyMap *GetStcCoord( AstStc *, int, int * ); static AstKeyMap *MakeAstroCoordsKeyMap( AstRegion *, AstKeyMap *, const char *, int * ); static AstMapping *Simplify( AstMapping *, int * ); static AstPointSet *RegBaseMesh( AstRegion *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstRegion *GetDefUnc( AstRegion *, int * ); static AstRegion *GetStcRegion( AstStc *, int * ); static AstRegion *RegBasePick( AstRegion *this, int, const int *, int * ); static const char *GetRegionClass( AstStc *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetBounded( AstRegion *, int * ); static int GetObjSize( AstObject *, int * ); static int GetStcNCoord( AstStc *, int * ); static int GetUseDefs( AstObject *, int * ); static int Overlap( AstRegion *, AstRegion *, int * ); static int OverlapX( AstRegion *, AstRegion *, int * ); static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void GetRegion( AstStc *, AstRegion **, int *, int * ); static void RegBaseBox( AstRegion *, double *, double *, int * ); static void RegClearAttrib( AstRegion *, const char *, char **, int * ); static void RegSetAttrib( AstRegion *, const char *, char **, int * ); static void SetRegFS( AstRegion *, AstFrame *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearClosed( AstRegion *, int * ); static int GetClosed( AstRegion *, int * ); static void SetClosed( AstRegion *, int, int * ); static int TestClosed( AstRegion *, int * ); static void ClearMeshSize( AstRegion *, int * ); static int GetMeshSize( AstRegion *, int * ); static void SetMeshSize( AstRegion *, int, int * ); static int TestMeshSize( AstRegion *, int * ); static void ClearFillFactor( AstRegion *, int * ); static double GetFillFactor( AstRegion *, int * ); static void SetFillFactor( AstRegion *, double, int * ); static int TestFillFactor( AstRegion *, int * ); static void ClearNegated( AstRegion *, int * ); static int GetNegated( AstRegion *, int * ); static void SetNegated( AstRegion *, int, int * ); static int TestNegated( AstRegion *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Stc member function (over-rides the astClearAttrib protected * method inherited from the Region class). * Description: * This function clears the value of a specified attribute for a * Stc, so that the default value will subsequently be used. * Parameters: * this * Pointer to the Stc. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ int len; /* Length of attrib string */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* (none as yet) */ /* ------------- */ /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then report an error. */ if ( !strcmp( attrib, "regionclass" ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two Objects are equivalent. * Type: * Private function. * Synopsis: * #include "stc.h" * int Equal( AstObject *this_object, AstObject *that_object, int *status ) * Class Membership: * Stc member function (over-rides the astEqual protected * method inherited from the Region class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two Stcs are equivalent. * Parameters: * this * Pointer to the first Stc. * that * Pointer to the second Stc. * status * Pointer to the inherited status variable. * Returned Value: * One if the Stcs are equivalent, zero otherwise. * Notes: * - The Stcs are equivalent if their encapsulated Region are * equivalent, and if they have the same boolean operation, negation * and closed flags. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstStc *that; AstStc *this; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the Equal method inherited from the parent Region class. This checks that the Objects are both of the same class, and have the same Negated and Closed flags (amongst other things). */ if( (*parent_equal)( this_object, that_object, status ) ) { /* Obtain pointers to the two Stc structures. */ this = (AstStc *) this_object; that = (AstStc *) that_object; /* Test their encapsulated Region for equality. */ result = astEqual( this->region, that->region ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } /* * Name: * MAKE_SET * Purpose: * Define a function to set an attribute value for a Stc. * Type: * Private macro. * Synopsis: * #include "stc.h" * MAKE_SET(attribute,lattribute,type) * Class Membership: * Defined by the Stc class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Set( AstRegion *this, value ) * * that sets the value of a specified Region attribute in the parent * Region structure and also in the encapsulated Region. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * lattribute * Name of the attribute, all in lower case. * type * The C type of the attribute. */ /* Define the macro. */ #define MAKE_SET(attribute,lattribute,type) \ static void Set##attribute( AstRegion *this_region, type value, int *status ) { \ \ /* Local Variables: */ \ AstStc *this; /* Pointer to the Stc structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Use the parent method to set the value in the parent Region structure. */ \ (*parent_set##lattribute)( this_region, value, status ); \ \ /* Also set the value in the encapsulated Region. */ \ this = (AstStc *) this_region; \ astSet##attribute( this->region, value ); \ } /* Use the above macro to create accessors for the MeshSize, Closed and FillFactor attributes. */ MAKE_SET(FillFactor,fillfactor,double) MAKE_SET(MeshSize,meshsize,int) MAKE_SET(Closed,closed,int) MAKE_SET(Negated,negated,int) /* Undefine the macro. */ #undef MAKE_SET /* * Name: * MAKE_CLEAR * Purpose: * Define a function to clear an attribute value for a Stc. * Type: * Private macro. * Synopsis: * #include "stc.h" * MAKE_CLEAR(attribute,lattribute) * Class Membership: * Defined by the Stc class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Clear( AstRegion *this ) * * that sets the value of a specified Region attribute in the parent * Region structure and also in the encapsulated Region. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * lattribute * Name of the attribute, all in lower case. */ /* Define the macro. */ #define MAKE_CLEAR(attribute,lattribute) \ static void Clear##attribute( AstRegion *this_region, int *status ) { \ \ /* Local Variables: */ \ AstStc *this; /* Pointer to the Stc structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Use the parent method to clear the value in the parent Region structure. */ \ (*parent_clear##lattribute)( this_region, status ); \ \ /* Also clear the value in the encapsulated Region. */ \ this = (AstStc *) this_region; \ astClear##attribute( this->region ); \ } /* Use the above macro to create accessors for the MeshSize, Closed and FillFactor attributes. */ MAKE_CLEAR(FillFactor,fillfactor) MAKE_CLEAR(MeshSize,meshsize) MAKE_CLEAR(Closed,closed) MAKE_CLEAR(Negated,negated) /* Undefine the macro. */ #undef MAKE_CLEAR /* * Name: * MAKE_GET * Purpose: * Define a function to get an attribute value for a Stc. * Type: * Private macro. * Synopsis: * #include "stc.h" * MAKE_GET(attribute,type,bad) * Class Membership: * Defined by the Stc class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static Get( AstRegion *this ) * * that gets the value of a specified Region attribute from the encapsulated * Region. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. * bad * Value to return in caseof error. */ /* Define the macro. */ #define MAKE_GET(attribute,type,bad) \ static type Get##attribute( AstRegion *this_region, int *status ) { \ \ /* Local Variables: */ \ AstStc *this; /* Pointer to the Stc structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad); \ \ /* Get the value from the encapsulated Region. */ \ this = (AstStc *) this_region; \ return astGet##attribute( this->region ); \ } /* Use the above macro to create accessors for the MeshSize, Closed and FillFactor attributes. */ MAKE_GET(FillFactor,double,AST__BAD) MAKE_GET(MeshSize,int,100) MAKE_GET(Closed,int,1) MAKE_GET(Negated,int,0) /* Undefine the macro. */ #undef MAKE_GET /* * Name: * MAKE_TEST * Purpose: * Define a function to test an attribute value for a Stc. * Type: * Private macro. * Synopsis: * #include "stc.h" * MAKE_TEST(attribute) * Class Membership: * Defined by the Stc class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static int Test( AstRegion *this ) * * that test the value of a specified Region attribute from the encapsulated * Region. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * type * The C type of the attribute. */ /* Define the macro. */ #define MAKE_TEST(attribute) \ static int Test##attribute( AstRegion *this_region, int *status ) { \ \ /* Local Variables: */ \ AstStc *this; /* Pointer to the Stc structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Test the value from the encapsulated Region. */ \ this = (AstStc *) this_region; \ return astTest##attribute( this->region ); \ } /* Use the above macro to create accessors for the MeshSize, Closed and FillFactor attributes. */ MAKE_TEST(FillFactor) MAKE_TEST(MeshSize) MAKE_TEST(Closed) MAKE_TEST(Negated) /* Undefine the macro. */ #undef MAKE_TEST static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "stc.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * Stc member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied Stc, * in bytes. * Parameters: * this * Pointer to the Stc. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstStc *this; /* Pointer to Stc structure */ int result; /* Result value to return */ int i; /* AstroCoords index */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the Stc structure. */ this = (AstStc *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->region ); if( this->coord ) { for( i = 0; i < this->ncoord; i++ ) { result += astGetObjSize( this->coord[ i ] ); } result += astTSizeOf( this->coord ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Stc member function (over-rides the protected astGetAttrib * method inherited from the Region class). * Description: * This function returns a pointer to the value of a specified * attribute for a Stc, formatted as a character string. * Parameters: * this * Pointer to the Stc. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the Stc, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Stc. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ const char *result; /* Pointer value to return */ int len; /* Length of attrib string */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* RegionClass. */ /* ------------ */ if ( !strcmp( attrib, "regionclass" ) ) { result = astGetClass( this->region ); /* Not recognised. */ /* --------------- */ /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static int GetBounded( AstRegion *this_region, int *status ) { /* * Name: * GetBounded * Purpose: * Is the Region bounded? * Type: * Private function. * Synopsis: * #include "stc.h" * int GetBounded( AstRegion *this, int *status ) * Class Membership: * Stc method (over-rides the astGetBounded method inherited from * the Region class). * Description: * This function returns a flag indicating if the Region is bounded. * The implementation provided by the base Region class is suitable * for Region sub-classes representing the inside of a single closed * curve (e.g. Circle, Ellipse, Box, etc). Other sub-classes (such as * Stc, PointList, etc ) may need to provide their own implementations. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Region is bounded. Zero otherwise. */ /* Local Variables: */ AstStc *this; /* Pointer to Stc structure */ AstRegion *reg; /* Pointer to the encapsulated Region */ int neg; /* Negated flag to use */ int neg_old; /* Original Negated flag */ int result; /* Returned result */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the Stc structure. */ this = (AstStc *) this_region; /* Get the encapsulated Region, and the Negated value which should be used with it. The returned values take account of whether the supplied Stc has itself been Negated or not. The returned Region represent a region within the base Frame of the FrameSet encapsulated by the parent Region structure. */ GetRegion( this, ®, &neg, status ); /* Temporarily set the Negated attribute to the required value.*/ neg_old = astGetNegated( reg ); astSetNegated( reg, neg ); /* See if the encapsulated Region is bounded. */ result = astGetBounded( reg ); /* Re-instate the original value for the Negated attribute of the encapsulated Region. */ if( reg ) astSetNegated( reg, neg_old ); /* Free resources. */ reg = astAnnul( reg ); /* Return zero if an error occurred. */ if( !astOK ) result = 0; /* Return the required pointer. */ return result; } static AstRegion *GetDefUnc( AstRegion *this_region, int *status ) { /* * Name: * GetDefUnc * Purpose: * Obtain a pointer to the default uncertainty Region for a given Region. * Type: * Private function. * Synopsis: * #include "stc.h" * AstRegion *GetDefUnc( AstRegion *this ) * Class Membership: * Stc method (over-rides the astGetDefUnc method inherited from * the Region class). * This function returns a pointer to a Region which represents the * default uncertainty associated with a position on the boundary of the * given Region. The returned Region refers to the base Frame within the * FrameSet encapsulated by the supplied Region. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ AstRegion *result; /* Returned pointer */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the Stc structure. */ this = (AstStc *) this_region; /* If the encapsulated region has non-default uncertainty, use it as the default uncertainty for the Cmpregion. Note, the current Frame of an uncertainty Region is assumed to be the same as the base Frame in the Stc. */ if( astTestUnc( this->region ) ) { result = astGetUncFrm( this->region, AST__CURRENT ); /* Otherwise, use the parent method to determine the default uncertainty. */ } else { result = (* parent_getdefunc)( this_region, status ); } /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } static void GetRegion( AstStc *this, AstRegion **reg, int *neg, int *status ) { /* * * Name: * GetRegion * Purpose: * Get the encapsulated Region of a Stc. * Type: * Private function. * Synopsis: * #include "region.h" * void GetRegion( AstStc *this, AstRegion **reg, int *neg, int *status ) * Class Membership: * Stc member function * Description: * This function returns a pointer to a Region which is equivalent to * the supplied Stc. If the Stc has been negated, then the returned * "negated" flag will be set such that it represents the negated Stc. * * The current Frames in returned encapsulated Region will be equivalent * to the base Frame in the FrameSet encapsulated by the parent Region * structure. * Parameters: * this * Pointer to the Stc. * reg * Address of a location to receive a pointer to the encapsulated * Region. The current Frame in this region will be equivalent to * the base Frame in the FrameSet * neg * The value of the Negated attribute to be used with reg. * status * Pointer to the inherited status variable. * Notes: * - Any changes made to the encapsulated Region using the returned * pointer will be reflected in the supplied Stc. */ /* Initialise */ if( reg ) *reg = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Return the component Region pointers. */ if( reg ) *reg = astClone( this->region ); /* Initialise the other returned items. Note, the Stc initialiser stored a deep copy of the supplied encapsulated Region, and so we do not need to worry about attributes of the Region having been changed after the creation of the Stc. This is different to the CmpMap class which merely clones its supplied component pointers and so has to save copies of the original Invert settings within the CmpMap structure. */ if( neg ) *neg = astGetNegated( this->region ); /* If the Stc has been inverted, we modify the boolean operator and negation flags so that they reflect the inverted Stc. */ if( astGetNegated( this ) && neg ) *neg = *neg ? 0 : 1; } static const char *GetRegionClass( AstStc *this, int *status ){ /* *+ * Name: * astGetRegionClass * Purpose: * Get the value of a RegionClass attribute for a Stc. * Type: * Protected function. * Synopsis: * #include "stc.h" * const char *astGetRegionClass( AstStc *this ) * Class Membership: * Stc virtual function * Description: * This function returns a pointer to the value of the RegionClass * attribute for a Stc. * Parameters: * this * Pointer to the Stc. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the Stc, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Stc. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain and return the class of the encapsulated Region. */ return astGetClass( ((AstStc *) this)->region ); } static AstKeyMap *GetStcCoord( AstStc *this, int icoord, int *status ){ /* *++ * Name: c astGetStcCoord f AST_GETSTCCOORD * Purpose: * Return information about an AstroCoords element stored in an Stc. * Type: * Public virtual function. * Synopsis: c #include "specframe.h" c AstKeyMap *astGetStcCoord( AstStc *this, int icoord ) f RESULT = AST_GETSTCCOORD( THIS, ICOORD, STATUS ) * Class Membership: * Stc method. * Description: * When any sub-class of Stc is created, the constructor function * allows one or more AstroCoords elements to be stored within the Stc. * This function allows any one of these AstroCoords elements to be * retrieved. The format of the returned information is the same as * that used to pass the original information to the Stc constructor. * That is, the information is returned in a KeyMap structure * containing elements with one or more of the keys given by symbolic * constants AST__STCNAME, AST__STCVALUE, AST__STCERROR, AST__STCRES, * AST__STCSIZE and AST__STCPIXSZ. * * If the coordinate system represented by the Stc has been changed * since it was created (for instance, by changing its System * attribute), then the sizes and positions in the returned KeyMap * will reflect the change in coordinate system. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Stc. c icoord f ICOORD = INTEGER (Given) * The index of the AstroCoords element required. The first has index * one. The number of AstroCoords elements in the Stc can be found using c function astGetStcNcoord. f function AST_GETSTCNCOORD. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetStcCoord() f AST_GETSTCCOORD = INTEGER * A pointer to a new KeyMap containing the required information. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstFrame *frm; AstKeyMap *result; AstMapping *map; AstMapping *smap; AstObject *obj; AstRegion *reg; AstRegion *rereg; AstRegion *srereg; int ikey; int nc; /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the supplied index. */ nc = astGetStcNCoord( this ); if( icoord < 1 || icoord > nc ) { astError( AST__STCIND, "astGetStcCoord(%s): Supplied AstroCoords " "index (%d) is invalid.", status, astGetClass( this ), icoord ); if( icoord < 1 ) { astError( AST__STCIND, "The index of the first AstroCoord " "element is one, not zero." , status); } else if( nc == 0 ) { astError( AST__STCIND, "There are no AstroCoords elements in " "the supplied %s.", status, astGetClass( this ) ); } else if( nc == 1 ) { astError( AST__STCIND, "There is 1 AstroCoords element in " "the supplied %s.", status, astGetClass( this ) ); } else { astError( AST__STCIND, "There are %d AstroCoords elements in " "the supplied %s.", status, nc, astGetClass( this ) ); } /* If the index is OK, initialise the returned KeyMap to be a copy of the KeyMap holding information about the required AstroCoords element.*/ } else { result = astCopy( this->coord[ icoord - 1 ] ); /* The Regions stored within this KeyMap describe regions within the base Frame of the parent Region structure. If the Mapping from base to current Frame in the parent Region structure is not a UnitMap, we need to change these to represent regions within the current Frame of the parent Region structure. */ map = astGetMapping( ((AstRegion *)this)->frameset, AST__BASE, AST__CURRENT ); smap = astSimplify( map ); frm = astGetFrame( ((AstRegion *)this)->frameset, AST__CURRENT ); /* If the Frame represented by the Region has changed, erase the Names element since they may no longer be correct. */ if( !astIsAUnitMap( smap ) ) astMapRemove( result, AST__STCNAME ); /* Loop round keys for which a Region may be stored in the KeyMap. */ for( ikey = 0; ikey < NREG; ikey++ ) { /* If the KeyMap contains a Region for this key, get a pointer to it. */ if( astMapGet0A( result, regkey[ ikey ], &obj ) ){ reg = (AstRegion *) obj; /* Sets its RegionFS attribute so that the encapsulated FrameSet will be included in any dump of the Region. This is needed since the returned Region pointer will have no parent Region from which the FrameSet can be determined. */ astSetRegionFS( reg, 1 ); /* If necessary, remap the Region into the current Frame, and simplify. */ if( !astIsAUnitMap( smap ) ) { rereg = astMapRegion( reg, smap, frm ); srereg = astSimplify( rereg ); rereg = astAnnul( rereg ); } else { srereg = astClone( reg ); } /* Replace the Region in the KeyMap with the remapped Region. */ astMapPut0A( result, regkey[ ikey ], srereg, NULL ); /* Free resources */ reg = astAnnul( reg ); srereg = astAnnul( srereg ); } } frm = astAnnul( frm ); map = astAnnul( map ); smap = astAnnul( smap ); /* Annul the returned KeyMap if an error has occurred. */ if( !astOK ) result = astAnnul( result ); } /* Return the pointer */ return result; } static int GetStcNCoord( AstStc *this, int *status ){ /* *++ * Name: c astGetStcNCoord f AST_GETSTCNCOORD * Purpose: * Return the number of AstroCoords elements stored in an Stc. * Type: * Public virtual function. * Synopsis: c #include "stc.h" c int astGetStcNCoord( AstStc *this ) f RESULT = AST_GETSTCNCOORD( THIS, STATUS ) * Class Membership: * Stc method. * Description: * This function returns the number of AstroCoords elements stored in * an Stc. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Stc. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetStcNCoord() f AST_GETSTCNCOORD = INTEGER * The number of AstroCoords elements stored in the Stc. * Notes: * - Zero will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Return the required value. */ return astOK ? this->ncoord : 0; } static AstRegion *GetStcRegion( AstStc *this, int *status ) { /* *++ * Name: c astGetStcRegion f AST_GETSTCREGION * Purpose: * Obtain a copy of the encapsulated Region within a Stc. * Type: * Public virtual function. * Synopsis: c #include "stc.h" c AstRegion *astGetStcRegion( AstStc *this ) f RESULT = AST_GETSTCREGION( THIS, STATUS ) * Class Membership: * Region method. * Description: * This function returns a pointer to a deep copy of the Region * supplied when the Stc was created. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Stc. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetStcRegion() f AST_GETSTCREGION = INTEGER * A pointer to a deep copy of the Region encapsulated within the * supplied Stc. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return a pointer to a copy of the encapsulated Region. */ return astCopy( this->region ); } static int GetUseDefs( AstObject *this_object, int *status ) { /* * Name: * GetUseDefs * Purpose: * Get the value of the UseDefs attribute for a Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * int GetUseDefs( AstObject *this_object, int *status ) { * Class Membership: * Stc member function (over-rides the protected astGetUseDefs * method inherited from the Region class). * Description: * This function returns the value of the UseDefs attribute for a * Stc, supplying a suitable default. * Parameters: * this * Pointer to the Stc. * status * Pointer to the inherited status variable. * Returned Value: * - The USeDefs value. */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ int result; /* Value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* If the UseDefs value for the Stc has been set explicitly, use the Get method inherited from the parent Region class to get its value. */ if( astTestUseDefs( this ) ) { result = (*parent_getusedefs)( this_object, status ); /* Otherwise, supply a default value equal to the UseDefs value of the encapsulated Region. */ } else { result = astGetUseDefs( this->region ); } /* Return the result. */ return result; } void astInitStcVtab_( AstStcVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitStcVtab * Purpose: * Initialise a virtual function table for a Stc. * Type: * Protected function. * Synopsis: * #include "stc.h" * void astInitStcVtab( AstStcVtab *vtab, const char *name ) * Class Membership: * Stc vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Stc class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstRegionVtab *region; /* Pointer to Region component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitRegionVtab( (AstRegionVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAStc) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstRegionVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->GetRegionClass = GetRegionClass; vtab->GetStcRegion = GetStcRegion; vtab->GetStcCoord = GetStcCoord; vtab->GetStcNCoord = GetStcNCoord; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; region = (AstRegionVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_transform = mapping->Transform; mapping->Transform = Transform; parent_simplify = mapping->Simplify; mapping->Simplify = Simplify; parent_setregfs = region->SetRegFS; region->SetRegFS = SetRegFS; parent_equal = object->Equal; object->Equal = Equal; parent_clearclosed = region->ClearClosed; region->ClearClosed = ClearClosed; parent_setclosed = region->SetClosed; region->SetClosed = SetClosed; region->TestClosed = TestClosed; region->GetClosed = GetClosed; parent_regsetattrib = region->RegSetAttrib; region->RegSetAttrib = RegSetAttrib; parent_regclearattrib = region->RegClearAttrib; region->RegClearAttrib = RegClearAttrib; parent_clearnegated = region->ClearNegated; region->ClearNegated = ClearNegated; parent_setnegated = region->SetNegated; region->SetNegated = SetNegated; region->TestNegated = TestNegated; region->GetNegated = GetNegated; parent_setmeshsize = region->SetMeshSize; region->SetMeshSize = SetMeshSize; parent_clearmeshsize = region->ClearMeshSize; region->ClearMeshSize = ClearMeshSize; region->TestMeshSize = TestMeshSize; region->GetMeshSize = GetMeshSize; parent_setfillfactor = region->SetFillFactor; region->SetFillFactor = SetFillFactor; parent_clearfillfactor = region->ClearFillFactor; region->ClearFillFactor = ClearFillFactor; region->TestFillFactor = TestFillFactor; region->GetFillFactor = GetFillFactor; parent_getusedefs = object->GetUseDefs; object->GetUseDefs = GetUseDefs; parent_getdefunc = region->GetDefUnc; region->GetDefUnc = GetDefUnc; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ region->Overlap = Overlap; region->OverlapX = OverlapX; region->RegBaseBox = RegBaseBox; region->RegBaseMesh = RegBaseMesh; region->RegBasePick = RegBasePick; region->RegPins = RegPins; region->GetBounded = GetBounded; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "Stc", "An IVOA Space-Time-Coords object" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static AstKeyMap *MakeAstroCoordsKeyMap( AstRegion *reg, AstKeyMap *coord, const char *class, int *status ){ /* * Name: * MakeAstroCoordsKeyMap * Purpose: * Create a new KeyMap holding Regions describing a supplied * AstroCoords element. * Type: * Private function. * Synopsis: * #include "stc.h" * AstKeyMap *MakeAstroCoordsKeyMap( AstRegion *reg, AstKeyMap *coord, * const char *class, int *status ) * Class Membership: * Stc member function * Description: * This function returns a pointer to a new KeyMap containing elements * which correspond to the components of an STC AstroCoords element. * The element with key AST__STCNAME holds a vector of character * strings containing the names associated with each of the axies. * The other elements of the returned KeyMap such as AST__STCERROR, * AST__STCRES, etc, hold pointers to Regions describing the error * box, resolution, etc, in the Frame of the supplied Region "reg". * Parameters: * reg * Pointer to the Region in which the AstroCoords is defined. * coordId * An ID (not a pointer) to a KeyMap defining a single * element, having elements with keys given by constants AST__STCNAME, * AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. Any of these elements may be omitted, but no other * elements should be included. If supplied, the AST__STCNAME element * should be a vector of character string pointers holding the "Name" * item for each axis. Any other supplied elements should be scalar * elements, each holding a pointer to a Region describing the * associated item of ancillary information (error, resolution, size, * pixel size or value). These Regions should refer to the coordinate * system represented by "region". * class * Pointer to a string holding the STC class name. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to the new KeyMap. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *frm; /* Pointer to current Frame */ AstFrameSet *fs; /* Pointer to conversion FrameSet */ AstKeyMap *result; /* Pointer value to return */ AstMapping *map; /* Pointer to conversion Mapping */ AstObject *obj; /* Pointer to Object stored in supplied KeyMap */ AstRegion *areg; /* Pointer to remapped Region */ AstRegion *sareg; /* Pointer to simplified remapped Region */ const char *key; /* Current key */ int j; /* Index of key within KeyMap */ int naxes; /* Number of axes in region */ int nkey; /* Number of keys in supplied KeyMap */ int nv; /* Number of values in KeyMap element */ int type; /* Data type of entry */ /* Initialise. */ result = NULL; /* Check the global error status. */ if( !astOK ) return result; /* Confirm it is a genuine KeyMap pointer. */ if( !astIsAKeyMap( coord ) && astOK ) { astError( AST__STCKEY, "astInitStc(%s): Supplied pointer is for " "a %s, not a KeyMap.", status, class, astGetClass( coord ) ); } /* Initialise the new KeyMap to be a copy of the supplied KeyMap. */ result = astCopy( coord ); /* Check the supplied KeyMap is usable. */ naxes = astGetNaxes( reg ); nkey = astMapSize( result ); for( j = 0; j < nkey; j++ ) { key = astMapKey( result, j ); if( key ) { nv = astMapLength( result, key ); type = astMapType( result, key ); /* Check no unknown keys are present in the KeyMap. */ if( strcmp( key, AST__STCNAME ) && strcmp( key, AST__STCVALUE ) && strcmp( key, AST__STCERROR ) && strcmp( key, AST__STCRES ) && strcmp( key, AST__STCSIZE ) && strcmp( key, AST__STCPIXSZ ) ) { astError( AST__STCKEY, "astInitStc(%s): Unknown key " "\"%s\" supplied in an AstroCoords list.", status, class, key ); break; /* Check that the "Name" element is a vector of "naxes" strings. */ } else if( !strcmp( key, AST__STCNAME ) ) { if( nv != naxes ) { astError( AST__STCKEY, "astInitStc(%s): %d \"%s\" " "values supplied in an AstroCoords list, but " "the Stc has %d axes. ", status, class, nv, key, naxes ); break; } else if( type != AST__STRINGTYPE ) { astError( AST__STCKEY, "astInitStc(%s): The \"%s\" " "values supplied in an AstroCoords list are " "not character strings. ", status, class, key ); break; } /* Check that all other elements are scalar. */ } else if( nv != 1 ) { astError( AST__STCKEY, "astInitStc(%s): %d \"%s\" " "values supplied in an AstroCoords list, but " "only one is allowed. ", status, class, nv, key ); break; /* Check that all other elements are AST Object pointers. */ } else if( type != AST__OBJECTTYPE ) { astError( AST__STCKEY, "astInitStc(%s): The \"%s\" " "value supplied in an AstroCoords list is " "not an AST Object pointer. ", status, class, key ); break; /* Check that the Object pointers are not NULL. */ } else { astMapGet0A( result, key, &obj ); if( astOK ) { if( !obj ) { astError( AST__STCKEY, "astInitStc(%s): The \"%s\" " "value supplied in an AstroCoords list is " "a NULL pointer. ", status, class, key ); break; /* Check that the Object pointers are Region pointers. */ } else if( !astIsARegion( obj ) ){ astError( AST__STCKEY, "astInitStc(%s): The \"%s\" " "value supplied in an AstroCoords list is " "a %s, not a Region. ", status, class, key, astGetClass(obj) ); obj = astAnnul( obj ); break; /* Check that the Region pointers can be converted to the coordinate system represented by the supplied Region. */ } else { fs = astConvert( obj, reg, "" ); if( !fs ) { obj = astAnnul( obj ); astError( AST__STCKEY, "astInitStc(%s): The \"%s\" " "value supplied in an AstroCoords list " "cannot be converted to the coordinate " "system of its parent Stc object.", status, class, key ); break; /* If necessary, map the Region into the same frame as the supplied Region, and replace the Region in the returned KeyMap with the remapped Region. Also set the RegionFS attribute to indicate that the FrameSet in the Region does not need to be dumped if it contains a UnitMap. */ } else { map = astGetMapping( fs, AST__BASE, AST__CURRENT ); if( !astIsAUnitMap( map ) ) { frm = astGetFrame( fs, AST__CURRENT ); areg = astMapRegion( (AstRegion *) obj, map, frm ); sareg = astSimplify( areg ); astSetRegionFS( sareg, 0 ); astMapPut0A( result, key, sareg, NULL ); areg = astAnnul( areg ); sareg = astAnnul( sareg ); frm = astAnnul( frm ); } else { astSetRegionFS( (AstRegion *) obj, 0 ); } map = astAnnul( map ); fs = astAnnul( fs ); } obj = astAnnul( obj ); } } } } } /* Free the returned KeyMap if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result */ return result; } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * Stc member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstStc *this; /* Pointer to STC structure */ int i; /* Loop count */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the STC structure. */ this = (AstStc *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->region, mode, extra, fail ); for( i = 0; i < this->ncoord; i++ ) { if( !result ) result = astManageLock( this->coord[ i ], mode, extra, fail ); } return result; } #endif static int Overlap( AstRegion *this, AstRegion *that, int *status ){ /* * Name: * Overlap * Purpose: * Test if two regions overlap each other. * Type: * Private function. * Synopsis: * #include "stc.h" * int Overlap( AstRegion *this, AstRegion *that, int *status ) * Class Membership: * Stc member function (over-rides the astOverlap method inherited * from the Region class). * Description: * This function returns an integer value indicating if the two * supplied Regions overlap. The two Regions are converted to a commnon * coordinate system before performing the check. If this conversion is * not possible (for instance because the two Regions represent areas in * different domains), then the check cannot be performed and a zero value * is returned to indicate this. * Parameters: * this * Pointer to the first Region. * that * Pointer to the second Region. * status * Pointer to the inherited status variable. * Returned Value: * astOverlap() * A value indicating if there is any overlap between the two Regions. * Possible values are: * * 0 - The check could not be performed because the second Region * could not be mapped into the coordinate system of the first * Region. * * 1 - There is no overlap between the two Regions. * * 2 - The first Region is completely inside the second Region. * * 3 - The second Region is completely inside the first Region. * * 4 - There is partial overlap between the two Regions. * * 5 - The Regions are identical. * * 6 - The second Region is the negation of the first Region. * Notes: * - The returned values 5 and 6 do not check the value of the Closed * attribute in the two Regions. * - A value of zero will be returned if this function is invoked with the * AST error status set, or if it should fail for any reason. */ /* Check the inherited status. */ if ( !astOK ) return 0; /* Invoke the "astOverlap" method on the encapsulated Region. */ return astOverlap( ((AstStc *)this)->region, that ); } static int OverlapX( AstRegion *that, AstRegion *this, int *status ){ /* * Name: * OverlapX * Purpose: * Test if two regions overlap each other. * Type: * Private function. * Synopsis: * #include "stc.h" * int OverlapX( AstRegion *that, AstRegion *this ) * Class Membership: * Stc member function (over-rides the astOverlapX method inherited * from the Region class). * Description: * This function performs the processing for the public astOverlap * method and has exactly the same interface except that the order * of the two arguments is swapped. This is a trick to allow * the astOverlap method to be over-ridden by derived classes on * the basis of the class of either of its two arguments. * * See the astOverlap method for details of the interface. */ /* Local Variables: */ int result; /* Check the inherited status. */ if ( !astOK ) return 0; /* Invoke the "astOverlapX" method on the encapsulated Region. */ result = astOverlap( ((AstStc *)that)->region, this ); /* Swap the returned values 2 and 3 to take account of the swapping of the regions.*/ if( result == 2 ) { result = 3; } else if( result == 3 ) { result = 2; } /* Return the result. */ return result; } static void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ){ /* * Name: * RegBaseBox * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "stc.h" * void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * Stc member function (over-rides the astRegBaseBox protected * method inherited from the Region class). * Description: * This function returns the upper and lower axis bounds of a Region in * the base Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if( !astOK ) return; /* Invoke the method on the encapsulated Region. */ astRegBaseBox( ((AstStc *)this)->region, lbnd, ubnd ); } static AstPointSet *RegBaseMesh( AstRegion *this, int *status ){ /* * Name: * RegBaseMesh * Purpose: * Create a new PointSet containing a mesh of points on the boundary of a * Region in its base Frame. * Type: * Private function. * Synopsis: * #include "stc.h" * AstPointSet *astRegBaseMesh( AstRegion *this, int *status ) * Class Membership: * Stc member function (over-rides the astRegBaseMesh protected * method inherited from the Region class). * Description: * This function creates a new PointSet containing a mesh of points on the * boundary of the Region. The points refer to the base Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the PointSet. Annul the pointer using astAnnul when it * is no longer needed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Check the global error status. */ if( !astOK ) return NULL; /* Invoke the astRegMesh method on the encapsulated Region. This returns a mesh in the current Frame of the encapsulated Region which is the same as the base Frame of the Stc Region. */ return astRegMesh( ((AstStc *)this)->region ); } static AstRegion *RegBasePick( AstRegion *this_region, int naxes, const int *axes, int *status ){ /* * Name: * RegBasePick * Purpose: * Return a Region formed by picking selected base Frame axes from the * supplied Region. * Type: * Private function. * Synopsis: * #include "stc.h" * AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes, * int *status ) * Class Membership: * Stc member function (over-rides the astRegBasePick protected * method inherited from the Region class). * Description: * This function attempts to return a Region that is spanned by selected * axes from the base Frame of the encapsulated FrameSet of the supplied * Region. This may or may not be possible, depending on the class of * Region. If it is not possible a NULL pointer is returned. * Parameters: * this * Pointer to the Region. * naxes * The number of base Frame axes to select. * axes * An array holding the zero-based indices of the base Frame axes * that are to be selected. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the Region, or NULL if no region can be formed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Invoke the astRegBaePick method on the encapsulated Region. */ return astRegBasePick( ((AstStc *)this_region)->region, naxes, axes ); } static void RegClearAttrib( AstRegion *this_region, const char *attrib, char **base_attrib, int *status ) { /* * Name: * RegClearAttrib * Purpose: * Clear an attribute value for a Region. * Type: * Protected function. * Synopsis: * #include "stc.h" * void RegClearAttrib( AstRegion *this, const char *attrib, * char **base_attrib, int *status ) * Class Membership: * Stc method (over-rides the astRegClearAttrib method inherited from * the Region class). * Description: * This function clears the value of an attribute in both the base and * current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * attrib * Pointer to a null terminated string containing an attribute name. * NOTE, IT SHOULD BE ENTIRELY LOWER CASE. * base_attrib * Address of a location at which to return a pointer to the null * terminated string holding the name of the attribute which was * cleared in the base Frame of the encapsulated FrameSet. This may * differ from the supplied name if the supplied name contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstStc *this; char *batt; int rep; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the Stc structure. */ this = (AstStc *) this_region; /* Use the RegClearAttrib method inherited from the parent class to clear the attribute in the current and base Frames in the FrameSet encapsulated by the parent Region structure. */ (*parent_regclearattrib)( this_region, attrib, &batt, status ); /* Now clear the base Frame attribute in the encapsulated Region (the current Frame within the encapsulated Region is equivalent to the base Frame in the parent Region structure). Annul any "attribute unknown" error that results from attempting to do this. */ if( astOK ) { rep = astReporting( 0 ); astRegClearAttrib( this->region, batt, NULL ); if( astStatus == AST__BADAT ) astClearStatus; astReporting( rep ); } /* If required, return the base Frame attribute name, otherwise free it. */ if( base_attrib ) { *base_attrib = batt; } else { batt = astFree( batt ); } } static int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, int **mask, int *status ){ /* * Name: * RegPins * Purpose: * Check if a set of points fall on the boundary of a given Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, * int **mask, int *status ) * Class Membership: * Stc member function (over-rides the astRegPins protected * method inherited from the Region class). * Description: * This function returns a flag indicating if the supplied set of * points all fall on the boundary of the given Stc. * * Some tolerance is allowed, as specified by the uncertainty Region * stored in the supplied Stc "this", and the supplied uncertainty * Region "unc" which describes the uncertainty of the supplied points. * Parameters: * this * Pointer to the Stc. * pset * Pointer to the PointSet. The points are assumed to refer to the * base Frame of the FrameSet encapsulated by "this". * unc * Pointer to a Region representing the uncertainties in the points * given by "pset". The Region is assumed to represent the base Frame * of the FrameSet encapsulated by "this". Zero uncertainity is assumed * if NULL is supplied. * mask * Pointer to location at which to return a pointer to a newly * allocated dynamic array of ints. The number of elements in this * array is equal to the value of the Npoint attribute of "pset". * Each element in the returned array is set to 1 if the * corresponding position in "pset" is on the boundary of the Region * and is set to zero otherwise. A NULL value may be supplied * in which case no array is created. If created, the array should * be freed using astFree when no longer needed. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the points all fall on the boundary of the given * Region, to within the tolerance specified. Zero otherwise. */ /* Check the global error status. */ if( !astOK ) return 0; /* Invoke the method on the encapsulated Region. */ return astRegPins( ((AstStc *)this)->region, pset, unc, mask ); } static void RegSetAttrib( AstRegion *this_region, const char *setting, char **base_setting, int *status ) { /* * Name: * RegSetAttrib * Purpose: * Set an attribute value for a Region. * Type: * Private function. * Synopsis: * #include "stc.h" * void RegSetAttrib( AstRegion *this, const char *setting, * char **base_setting, int *status ) * Class Membership: * Stc method (over-rides the astRegSetAttrib method inherited from * the Region class). * Description: * This function assigns an attribute value to both the base and * current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * setting * Pointer to a null terminated attribute setting string. NOTE, IT * SHOULD BE ENTIRELY LOWER CASE. The supplied string will be * interpreted using the public interpretation implemented by * astSetAttrib. This can be different to the interpretation of the * protected accessor functions. For instance, the public * interpretation of an unqualified floating point value for the * Epoch attribute is to interpet the value as a gregorian year, * but the protected interpretation is to interpret the value as an * MJD. * base_setting * Address of a location at which to return a pointer to the null * terminated attribute setting string which was applied to the * base Frame of the encapsulated FrameSet. This may differ from * the supplied setting if the supplied setting contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstKeyMap *keymap; AstObject *obj; AstRegion *reg; AstStc *this; char *bset; int i; int ikey; int rep; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the Stc structure. */ this = (AstStc *) this_region; /* Use the RegSetAttrib method inherited from the parent class to apply the setting to the current and base Frames in the FrameSet encapsulated by the parent Region structure. */ (*parent_regsetattrib)( this_region, setting, &bset, status ); /* Now apply the base Frame setting to the encapsulated Region (the current Frame within the encapsulated Region is equivalent to the base Frame in the parent Region structure). Annul any "attribute unknown" error that results from attempting to do this. Also do any AstroCoords in the Stc. */ if( astOK ) { rep = astReporting( 0 ); astRegSetAttrib( this->region, bset, NULL ); if( astStatus == AST__BADAT ) astClearStatus; /* Loop round all AstroCoords elements. */ for( i = 0; i < this->ncoord; i++ ) { /* Get a pointer to the KeyMap holding a description of the current AstroCoords element. */ keymap = this->coord[ i ]; /* Loop round all the elements of this KeyMap which may hold a Region pointer. */ for( ikey = 0; ikey < NREG; ikey++ ) { /* If the KeyMap contains a Region for this key, get a pointer to it. */ if( astMapGet0A( keymap, regkey[ ikey ], &obj ) ){ reg = (AstRegion *) obj; /* Modify it by applying the attribute setting. */ astRegSetAttrib( reg, bset, NULL ); if( astStatus == AST__BADAT ) astClearStatus; /* Annul the pointer. */ reg = astAnnul( reg ); } } } astReporting( rep ); } /* If required, return the base Frame setting string, otherwise free it. */ if( base_setting ) { *base_setting = bset; } else { bset = astFree( bset ); } } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * Stc member function (over-rides the astSetAttrib method inherited * from the Region class). * Description: * This function assigns an attribute value for a Stc, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the Stc. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. */ /* Local Vaiables: */ AstStc *this; /* Pointer to the Stc structure */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* Obtain the length of the setting string. */ len = strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* (none as yet) */ /* Read-only attributes. */ /* --------------------- */ /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* Use this macro to report an error if a read-only attribute has been specified. */ if ( MATCH( "regionclass" ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } /* Undefine macros local to this function. */ #undef MATCH } static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) { /* * Name: * SetRegFS * Purpose: * Stores a new FrameSet in a Region * Type: * Private function. * Synopsis: * #include "stc.h" * void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) * Class Membership: * Stc method (over-rides the astSetRegFS method inherited from * the Region class). * Description: * This function creates a new FrameSet and stores it in the supplied * Region. The new FrameSet contains two copies of the supplied * Frame, connected by a UnitMap. * Parameters: * this * Pointer to the Region. * frm * The Frame to use. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRegion *creg; /* Pointer to encapsulated Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the parent method to store the FrameSet in the parent Region structure. */ (* parent_setregfs)( this_region, frm, status ); /* If the encapsulated Region has a dummy FrameSet use this method recursively to give it the same FrameSet. */ creg = ((AstStc *) this_region )->region; if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm ); } static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { /* * Name: * Simplify * Purpose: * Simplify a Region. * Type: * Private function. * Synopsis: * #include "region.h" * AstMapping *Simplify( AstMapping *this, int *status ) * Class Membership: * Stc method (over-rides the astSimplify method inherited from * the Region class). * Description: * This function simplifies a Stc to eliminate redundant * computational steps, or to merge separate steps which can be * performed more efficiently in a single operation. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A new pointer to the (possibly simplified) Region. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstFrame *frm; /* Current Frame */ AstKeyMap *keymap; /* KeyMap holding stroCoords element */ AstMapping *map; /* Base->current Mapping */ AstObject *obj; /* Pointer to object retrieved from keymap */ AstRegion *newreg; /* New encapsulated Region */ AstRegion *reg; /* AstroCoords Region pointer */ AstRegion *treg; /* Temporary Region pointer */ AstStc *stc; /* Returned Stc Structure. */ AstStc *temp; /* Temporary Stc pointer */ int i; /* Index of current AstroCoords element */ int ikey; /* Index of key to be tested */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Invoke the Simplify method of the parent Region class. This simplifies the FrameSet and uncertainty Region in the parent Region structure. */ stc = (AstStc *) (AstRegion *) (* parent_simplify)( this_mapping, status ); /* If the Stc is negated, we can perform a simplication by transferring the negated state from the Stc itself to the encapsulated Region. */ if( astGetNegated( stc ) ) { /* Ensure that modifying "stc" will not modify the supplied Stc, by creating a copy of the supplied Stc, if this has not already been done. */ if( stc == (AstStc *) this_mapping ) { temp = (AstStc *) astCopy( stc ); (void) astAnnul( stc ); stc = temp; } /* Modify "temp" by negating both the Stc structure and its encapsulated Region. */ astNegate( stc ); astNegate( stc->region ); } /* Get the base->current Mapping from the parent Region structure, and the current Frame. */ map = astGetMapping( ((AstRegion *) stc)->frameset, AST__BASE, AST__CURRENT ); frm = astGetFrame( ((AstRegion *) stc)->frameset, AST__CURRENT ); /* We may be able to perform some more simplication on the encapsulated Region itself. If the above mapping is not a unit map, remap the encapsulated Region into the current Frame of the parent Region structure and simplify it. This transfers complication from the Mapping in the parent Region structure to the encapsulated Region. */ if( !astIsAUnitMap( map ) ) { treg = astMapRegion( stc->region, map, frm ); newreg = astSimplify( treg ); treg = astAnnul( treg ); /* If the base->current Mapping in the parent Region structure is a unit map, simplification of the whole Stc is possible if the encapsulated Region (without any remapping) can be simplied. */ } else { newreg = astSimplify( stc->region ); } /* If the encapsulated Region has been changed, store it in the returned Stc. */ if( newreg != stc->region ) { /* Ensure that modifying "stc" will not modify the supplied Stc, by creating a copy of the supplied Stc, if this has not already been done. */ if( stc == (AstStc *) this_mapping ) { temp = (AstStc *) astCopy( stc ); (void) astAnnul( stc ); stc = temp; } /* Store the new region in "stc", annulling the existing Region. */ if( stc ) { (void) astAnnul( stc->region ); stc->region = astClone( newreg ); } /* The encapsulated Region now represents an area in the current Frame represented by the supplied Stc. Since the encapsulated Region is defined as being in the base Frame of the FrameSet in the parent Region structure, the parent FrameSet should just be a UnitMap. Modify it appropriately (if it not already a UnitMap). */ if( !astIsAUnitMap( map ) ) astSetRegFS( stc, frm ); } /* Free resources */ newreg = astAnnul( newreg ); /* Now we do a similar process on any Regions held within an AstroCoords elements. Loop round all AstroCoords elements. */ if( stc ) { for( i = 0; i < stc->ncoord; i++ ) { /* Get a pointewr to the KeyMap holding a description of the current AstroCoords element. */ keymap = stc->coord[ i ]; /* Loop round all the elements of this KeyMap which may hold a Region pointer. */ for( ikey = 0; ikey < NREG; ikey++ ) { /* If the KeyMap contains a Region for this key, get a pointer to it. */ if( astMapGet0A( keymap, regkey[ ikey ], &obj ) ){ reg = (AstRegion *) obj; /* We have two tasks now, firstly to ensure that this AstroCoords Region describes an area in the base Frame of the FrameSet in the parent Region structure (which may have been changed by the earlier simplications performed by this function), and secondly, to attempt to simplify the Region. The Stc structure addressed by the "stc" pointer will have a current Frame given by "frm". This will also be its base Frame, and the base->current Mapping will consequently be a UnitMap. The Mapping from the original base Frame to the new base Frame is given by "map". Unless this is a UnitMap, we need to remap the Region.*/ if( !astIsAUnitMap( map ) ) { treg = astMapRegion( reg, map, frm ); } else { treg = astClone( reg ); } /* Now attempt to simplify the Region.*/ newreg = astSimplify( treg ); /* If the Region has been changed by either of these steps, we need to store the modified Region back in the "stc" structure which is being returned. But we need to be careful we do not modify the supplied Stc structure. */ if( newreg != reg ) { if( stc == (AstStc *) this_mapping ) { temp = astCopy( stc ); (void) astAnnul( stc ); stc = temp; keymap = temp->coord[ i ]; } astMapPut0A( keymap, regkey[ ikey ], newreg, regcom[ ikey ] ); } /* Free resources */ reg = astAnnul( reg ); treg = astAnnul( treg ); newreg = astAnnul( newreg ); } } } } /* Free resources */ map = astAnnul( map ); frm = astAnnul( frm ); /* If an error occurred, annul the returned Mapping. */ if ( !astOK ) stc = astAnnul( stc ); /* Return the result. */ return (AstMapping *) stc; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a Stc. * Type: * Private function. * Synopsis: * #include "stc.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Stc member function (over-rides the astTestAttrib protected * method inherited from the Region class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a Stc's attributes. * Parameters: * this * Pointer to the Stc. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ int len; /* Length of attrib string */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then return zero. */ if ( !strcmp( attrib, "regionclass" ) ) { result = 0; /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a Stc to transform a set of points. * Type: * Private function. * Synopsis: * #include "stc.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * Stc member function (over-rides the astTransform method inherited * from the Region class). * Description: * This function takes a Stc and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required Region. * This implies applying each of the Stc's encapsulated Region in turn, * either in series or in parallel. * Parameters: * this * Pointer to the Stc. * in * Pointer to the PointSet associated with the input coordinate values. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the Stc being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPointSet *ps; /* Pointer to PointSet */ AstPointSet *pset_tmp; /* Pointer to PointSet holding base Frame positions*/ AstPointSet *result; /* Pointer to output PointSet */ AstRegion *reg; /* Pointer to encapsulated Region */ AstStc *this; /* Pointer to the Stc structure */ double **ptr; /* Pointer to axis values */ double **ptr_out; /* Pointer to output coordinate data */ int coord; /* Zero-based index for coordinates */ int good; /* Is the point inside the Stc? */ int ncoord_out; /* No. of coordinates per output point */ int ncoord_tmp; /* No. of coordinates per base Frame point */ int neg; /* Negated value for encapsulated Region */ int neg_old; /* Original Negated flag */ int npoint; /* No. of points */ int point; /* Loop counter for points */ int rep; /* Original error reporting status */ int status_value; /* AST status value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a Pointer to the Stc structure */ this = (AstStc *) this_mapping; /* Get the encapsulated Region, and the Negated value which should be used with it. The returned values take account of whether the supplied Stc has itself been Negated or not. The returned Region represent a region within the base Frame of the FrameSet encapsulated by the parent Region structure. */ GetRegion( this, ®, &neg, status ); /* Temporarily set the Negated attribute to the required value.*/ neg_old = astGetNegated( reg ); astSetNegated( reg, neg ); /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Region class. This function validates all arguments and generates an output PointSet if necessary, containing a copy of the input PointSet. */ result = (*parent_transform)( this_mapping, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* First use the encapsulated FrameSet in the parent Region structure to transform the supplied positions from the current Frame in the encapsulated FrameSet (the Frame represented by the Stc), to the base Frame (the Frame in which the encapsulated Region are defined). Note, the returned pointer may be a clone of the "in" pointer, and so we must be carefull not to modify the contents of the returned PointSet. */ pset_tmp = astRegTransform( this, in, 0, NULL, NULL ); /* Now transform this PointSet using the encapsulated Region. */ ps = astTransform( reg, pset_tmp, 0, NULL ); /* Determine the numbers of points and coordinates per point for these base Frame PointSets and obtain pointers for accessing the base Frame and output coordinate values. */ npoint = astGetNpoint( pset_tmp ); ncoord_tmp = astGetNcoord( pset_tmp ); ptr = astGetPoints( ps ); ncoord_out = astGetNcoord( result ); ptr_out = astGetPoints( result ); /* Perform coordinate arithmetic. */ /* ------------------------------ */ if ( astOK ) { for ( point = 0; point < npoint; point++ ) { good = 0; for ( coord = 0; coord < ncoord_tmp; coord++ ) { if( ptr[ coord ][ point ] != AST__BAD ) { good = 1; break; } } if( !good ) { for ( coord = 0; coord < ncoord_out; coord++ ) { ptr_out[ coord ][ point ] = AST__BAD; } } } } /* Re-instate the original value for the Negated attribute of the encapsulated Region. Do this even if an error has occurred. */ status_value = astStatus; astClearStatus; rep = astReporting( 0 ); if( reg ) astSetNegated( reg, neg_old ); astReporting( rep ); astSetStatus( status_value ); /* Free resources. */ reg = astAnnul( reg ); ps = astAnnul( ps ); pset_tmp = astAnnul( pset_tmp ); /* If an error occurred, clean up by deleting the output PointSet (if allocated by this function) and setting a NULL result pointer. */ if ( !astOK ) { if ( !out ) result = astDelete( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; } /* Stc Attributes: */ /* =============== */ /* *att++ * Name: * RegionClass * Purpose: * The AST class name of the Region encapsulated within an Stc * Type: * Public attribute. * Synopsis: * String, read-only. * Description: * This is a read-only attribute giving the AST class name of the * Region encapsulated within an Stc (that is, the class of the Region * which was supplied when the Stc was created). * Applicability: * Stc * All Stc objects this attribute. *att-- */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Stc objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Stc objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Regions within the Stc. */ /* Local Variables: */ AstStc *in; /* Pointer to input Stc */ AstStc *out; /* Pointer to output Stc */ int i; /* AstroCoords index */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output Stcs. */ in = (AstStc *) objin; out = (AstStc *) objout; /* For safety, start by clearing any references to the input component Regions, etc, from the output Stc. */ out->region = NULL; out->coord = NULL; out->ncoord = 0; /* Make a copy of the Region and store a pointer to it in the output Stc structure. */ out->region = astCopy( in->region ); /* Copy any memory holding AstroCoords values */ if( in->coord && in->ncoord ) { out->ncoord = in->ncoord; out->coord = astMalloc( sizeof(AstKeyMap *) * (size_t)in->ncoord ); if( out->coord ) { for( i = 0; i < in->ncoord; i++ ) { out->coord[ i ] = astCopy( in->coord[ i ] ); } } } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Stc objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Stc objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstStc *this; /* Pointer to Stc */ int i; /* AstroCoords index */ /* Obtain a pointer to the Stc structure. */ this = (AstStc *) obj; /* Annul the pointer to the encapsulated Region. */ this->region = astAnnul( this->region ); /* Free any memory holding AstroCoords values */ if( this->coord ) { for( i = 0; i < this->ncoord; i++ ) { this->coord[ i ] = astAnnul( this->coord[ i ] ); } this->coord = astFree( this->coord ); } } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Stc objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Stc class to an output Channel. * Parameters: * this * Pointer to the Stc whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define COMMENT_LEN 150 /* Maximum length of a comment string */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstStc *this; /* Pointer to the Stc structure */ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment string */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */ int ico; /* Loop counter for KeyMaps */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Stc structure. */ this = (AstStc *) this_object; /* Write out values representing the instance variables for the Stc class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Encapsulated Region. */ /* -------------------- */ astWriteObject( channel, "Region", 1, 1, this->region, "STC Region" ); /* AstroCoords info */ /* ---------------- */ astWriteInt( channel, "Ncoord", ( this->ncoord != 0 ), 0, this->ncoord, "Number of AstroCoords elements" ); for ( ico = 1; ico <= this->ncoord; ico++ ) { (void) sprintf( key, "Coord%d", ico ); (void) sprintf( comment, "AstroCoords number %d", ico ); astWriteObject( channel, key, 1, 1, this->coord[ ico - 1 ], comment ); } /* Undefine macros local to this function. */ #undef COMMENT_LEN #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAStc and astCheckStc functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Stc,Region) astMAKE_CHECK(Stc) AstStc *astInitStc_( void *mem, size_t size, int init, AstStcVtab *vtab, const char *name, AstRegion *region, int ncoords, AstKeyMap **coords, int *status ) { /* *+ * Name: * astInitStc * Purpose: * Initialise a Stc. * Type: * Protected function. * Synopsis: * #include "stc.h" * AstStc *astInitStc( void *mem, size_t size, int init, AstStcVtab *vtab, * const char *name, AstRegion *region, int ncoords, * AstKeyMap **coords ) * Class Membership: * Stc initialiser. * Description: * This function is provided for use by class implementations to initialise * a new Stc object. It allocates memory (if necessary) to * accommodate the Stc plus any additional data associated with the * derived class. It then initialises a Stc structure at the start * of this memory. If the "init" flag is set, it also initialises the * contents of a virtual function table for a Stc at the start of * the memory passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Stc is to be initialised. * This must be of sufficient size to accommodate the Stc data * (sizeof(Stc)) plus any data used by the derived class. If a * value of NULL is given, this function will allocate the memory itself * using the "size" parameter to determine its size. * size * The amount of memory used by the Stc (plus derived class * data). This will be used to allocate memory if a value of NULL is * given for the "mem" parameter. This value is also stored in the * Stc structure, so a valid value must be supplied even if not * required for allocating memory. * init * A logical flag indicating if the Stc's virtual function table * is to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new Stc. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * region * Pointer to the Region represented by the Stc. * ncoords * Number of KeyMap pointers supplied in "coords". Can be zero. * Ignored if "coords" is NULL. * coords * Pointer to an array of "ncoords" KeyMap pointers, or NULL if * "ncoords" is zero. Each KeyMap defines defines a single * element, and should have elements with keys given by constants * AST__STCNAME, AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. Any of these elements may be omitted, but no other * elements should be included. If supplied, the AST__STCNAME element * should be a vector of character string pointers holding the "Name" * item for each axis. Any other supplied elements should be scalar * elements, each holding a pointer to a Region describing the * associated item of ancillary information (error, resolution, size, * pixel size or value). These Regions should describe a volume within * the coordinate system represented by "region". * Returned Value: * A pointer to the new Stc. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstMapping *frm; /* Current Frame in supplied Stc */ AstMapping *map; /* Base -> Current Mapping in supplied Stc */ AstRegion *reg; /* Copy of supplied Region */ AstStc *new; /* Pointer to new Stc */ int i; /* AstroCoords index */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitStcVtab( vtab, name ); /* Initialise. */ new = NULL; /* If the supplied Region is an Stc, create a new Region by mapping the encapsulated Region within the supplied Stc into the current Frame of the Stc. */ if( astIsAStc( region ) ) { map = astGetMapping( region->frameset, AST__BASE, AST__CURRENT ); frm = astGetFrame( region->frameset, AST__CURRENT ); reg = astMapRegion( ((AstStc *) region)->region, map, frm ); frm = astAnnul( frm ); map = astAnnul( map ); /* Otherwise, just take a copy of the supplied Region. */ } else { reg = astCopy( region ); } /* Initialise a Region structure (the parent class) as the first component within the Stc structure, allocating memory if necessary. A NULL PointSet is suppled as the encapsulated Region will perform the function of defining the Region shape. The base Frame of the FrameSet in the parent Region structure will be the same as the current Frames of the FrameSets in the two encapsulated Region. */ if ( astOK ) { new = (AstStc *) astInitRegion( mem, size, 0, (AstRegionVtab *) vtab, name, reg, NULL, NULL ); /* Initialise the Stc data. */ /* --------------------------- */ /* Store a pointer to the encapsulated Region. */ new->region = astClone( reg ); /* No AstroCoords info as yet. */ new->ncoord = 0; new->coord = NULL; /* Transfer attributes from the encapsulated region to the parent region. */ astRegOverlay( new, reg, 1 ); if( astTestIdent( reg ) ) astSetIdent( new, astGetIdent( reg ) ); /* If the base->current Mapping in the FrameSet within the encapsulated Region is a UnitMap, then the FrameSet does not need to be included in the Dump of the new Stc. Set the RegionFS attribute of the encapsulated Region to zero to flag this. Note, we do this after the previous class to astRegOverlay because we do not want this zero value for RegionFS to be copied into the new Stc object. */ astSetRegionFS( reg, 0 ); /* For each supplied AstroCoords, create a new KeyMap holding Regions representing the various elements of the AstroCoords, and store the new KeyMap in the Stc structure. */ if( coords && ncoords > 0 ) { new->ncoord = ncoords; new->coord = astMalloc( sizeof( AstKeyMap *)*(size_t) ncoords ); if( new->coord ) { for( i = 0; i < ncoords; i++ ) { new->coord[ i ] = MakeAstroCoordsKeyMap( reg, coords[ i ], name, status ); } } } /* If an error occurred, clean up deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Free resources */ reg = astAnnul( reg ); /* Return a pointer to the new object. */ return new; } AstStc *astLoadStc_( void *mem, size_t size, AstStcVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadStc * Purpose: * Load a Stc. * Type: * Protected function. * Synopsis: * #include "stc.h" * AstStc *astLoadStc( void *mem, size_t size, AstStcVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * Stc loader. * Description: * This function is provided to load a new Stc using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Stc structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a Stc at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the Stc is to be * loaded. This must be of sufficient size to accommodate the * Stc data (sizeof(Stc)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Stc (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Stc structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstStc) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Stc. If this is NULL, a pointer to * the (static) virtual function table for the Stc class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Stc" is used instead. * Returned Value: * A pointer to the new Stc. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstFrame *f1; /* Base Frame in parent Region */ AstObject *obj; /* Pointer to Object retrieved from KeyMap */ AstRegion *creg; /* Pointer to encapsulated Region */ AstStc *new; /* Pointer to the new Stc */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */ int ico; /* Loop counter for AstroCoords */ int ikey; /* Index of KeyMap */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Stc. In this case the Stc belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstStc ); vtab = &class_vtab; name = "Stc"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitStcVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Stc. */ new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Stc" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Encapsulated Region. */ /* -------------------- */ new->region = astReadObject( channel, "region", NULL ); /* Get a pointer to the base Frame in the FrameSet encapsulated by the parent Region structure. */ f1 = astGetFrame( ((AstRegion *) new)->frameset, AST__BASE ); /* If the encapsulated Region has a dummy FrameSet rather than the correct FrameSet, the correct FrameSet will have copies of the base Frame of the new Stc as both its current and base Frames, connected by a UnitMap (this is equivalent to a FrameSet containing a single Frame). However if the new Stc being loaded has itself got a dummy FrameSet, then we do not do this since we do not yet know what the correct FrameSet is. In this case we wait until the parent Region invokes the astSetRegFS method on the new Stc. */ if( !astRegDummyFS( new ) ) { creg = new->region; if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 ); } /* AstroCoords info */ /* ---------------- */ /* The number of AstroCoords described in the new Stc. */ new->ncoord = astReadInt( channel, "ncoord", 0 ); if( new->ncoord < 0 ) new->ncoord = 0; /* Read back each KeyMap describing these AstroCoords. */ new->coord = astMalloc( sizeof( AstKeyMap *) * (size_t) new->ncoord ); for( ico = 1; ico <= new->ncoord; ico++ ) { (void) sprintf( key, "coord%d", ico ); new->coord[ ico - 1 ] = astReadObject( channel, key, NULL ); /* Ensure the Regions within the KeyMap do not have dummy FrameSets. */ if( new->coord[ ico - 1 ] && !astRegDummyFS( new ) ) { for( ikey = 0; ikey < NREG; ikey++ ) { if( astMapGet0A( new->coord[ ico - 1 ], regkey[ ikey ], &obj ) ){ creg = (AstRegion *) obj; if( astRegDummyFS( creg ) ) { astSetRegFS( creg, f1 ); astMapPut0A( new->coord[ ico - 1 ], regkey[ ikey ], creg, regcom[ ikey ] ); } creg = astAnnul( creg ); } } } } /* Free resources */ f1 = astAnnul( f1 ); /* If an error occurred, clean up by deleting the new Stc. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Stc pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ const char *astGetRegionClass_( AstStc *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Stc,GetRegionClass))( this, status ); } AstRegion *astGetStcRegion_( AstStc *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Stc,GetStcRegion))( this, status ); } AstKeyMap *astGetStcCoord_( AstStc *this, int icoord, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Stc,GetStcCoord))( this, icoord, status ); } int astGetStcNCoord_( AstStc *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Stc,GetStcNCoord))( this, status ); } ./ast-7.3.3/fframeset.c0000644000175000017500000001431412262533650013265 0ustar olesoles/* *+ * Name: * fframeset.c * Purpose: * Define a FORTRAN 77 interface to the AST FrameSet class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the FrameSet class. * Routines Defined: * AST_ADDFRAME * AST_ADDVARIANT * AST_MIRRORVARIANTS * AST_FRAMESET * AST_GETFRAME * AST_GETMAPPING * AST_ISAFRAMESET * AST_REMAPFRAME * AST_REMOVEFRAME * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 1-AUG-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "mapping.h" /* C interface to the Mapping class */ #include "frame.h" /* C interface to the Frame class */ #include "frameset.h" /* C interface to the FrameSet class */ F77_SUBROUTINE(ast_addframe)( INTEGER(THIS), INTEGER(IFRAME), INTEGER(MAP), INTEGER(FRAME), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) GENPTR_INTEGER(MAP) GENPTR_INTEGER(FRAME) astAt( "AST_ADDFRAME", NULL, 0 ); astWatchSTATUS( astAddFrame( astI2P( *THIS ), *IFRAME, astI2P( *MAP ), astI2P( *FRAME ) ); ) } F77_INTEGER_FUNCTION(ast_frameset)( INTEGER(FRAME), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_FRAMESET", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astFrameSet( astI2P( *FRAME ), "%s", options ) ); astFree( options ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_getframe)( INTEGER(THIS), INTEGER(IFRAME), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) F77_INTEGER_TYPE(RESULT); astAt( "AST_GETFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astGetFrame( astI2P( *THIS ), *IFRAME ) ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_getmapping)( INTEGER(THIS), INTEGER(IFRAME1), INTEGER(IFRAME2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME1) GENPTR_INTEGER(IFRAME2) F77_INTEGER_TYPE(RESULT); astAt( "AST_GETMAPPING", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astGetMapping( astI2P( *THIS ), *IFRAME1, *IFRAME2 ) ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isaframeset)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAFRAMESET", NULL, 0 ); astWatchSTATUS( RESULT = astIsAFrameSet( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_remapframe)( INTEGER(THIS), INTEGER(IFRAME), INTEGER(MAP), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) GENPTR_INTEGER(MAP) astAt( "AST_REMAPFRAME", NULL, 0 ); astWatchSTATUS( astRemapFrame( astI2P( *THIS ), *IFRAME, astI2P( *MAP ) ); ) } F77_SUBROUTINE(ast_removeframe)( INTEGER(THIS), INTEGER(IFRAME), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) astAt( "AST_REMOVEFRAME", NULL, 0 ); astWatchSTATUS( astRemoveFrame( astI2P( *THIS ), *IFRAME ); ) } F77_SUBROUTINE(ast_addvariant)( INTEGER(THIS), INTEGER(MAP), CHARACTER(NAME), INTEGER(STATUS) TRAIL(NAME) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(MAP) GENPTR_CHARACTER(NAME) char *name; astAt( "AST_ADDVARIANT", NULL, 0 ); astWatchSTATUS( name = astString( NAME, NAME_length ); astAddVariant( astI2P( *THIS ), astI2P( *MAP ), name ); name = astFree( name ); ) } F77_SUBROUTINE(ast_mirrorvariants)( INTEGER(THIS), INTEGER(IFRAME), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(IFRAME) astAt( "AST_MIRRORVARIANTS", NULL, 0 ); astWatchSTATUS( astMirrorVariants( astI2P( *THIS ), *IFRAME ); ) } ./ast-7.3.3/ast_link.in0000644000175000017500000004436312262533650013310 0ustar olesoles # N.B. the previous line should be blank. #++ # Name: # ast_link # Purpose: # Link a program with the AST library. # Type of Module: # Shell script. # Description: # This command should be used when building programs which use the AST # library, in order to generate the correct arguments to allow the compiler # to link your program. The arguments generated are written to standard # output but may be substituted into the compiler command line in the # standard UNIX way using backward quotes (see below). # # By default, it is assumed that you are building a stand-alone program # which does not produce graphical output. However, switches are provided # for linking other types of program. # Invocation: #c cc program.c -L/star/lib `ast_link [switches]` -o program #f f77 program.f -L/star/lib `ast_link [switches]` -o program # Switches: # The following switches may optionally be given to this command to # modify its behaviour: # # # - ``-csla'': Ignored. Provided for backward compatibility only. # # - ``-fsla'': Ignored. Provided for backward compatibility only. # # - ``-ems'': Requests that the program be linked so that error messages # produced by the AST library are delivered via the Starlink EMS (Error # Message Service) library (Starlink System Note SSN/4). By default, # error messages are simply written to standard error. # # - ``-drama'': Requests that the program be linked so that error messages # produced by the AST library are delivered via the DRAMA Ers (Error # Reporting Service) library. By default, error messages are simply # written to standard error. # # - ``-grf'': Requests that no arguments be generated to specify which # 2D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new graphics system yourself and wish to provide your own arguments for # linking with it. This switch differs from the other ``grf'' switches in # that it assumes that your graphics module implements the complete # interface required by the current version of AST. If future versions of # AST introduce new functions to the graphics interface, this switch will # cause ``unresolved symbol'' errors to occur during linking, warning you # that you need to implement new functions in your graphics module. To # avoid such errors, you can use one of the other, version-specific, # switches in place of the ``-grf'' switch, but these will cause run-time # errors to be reported if any AST function is invoked which requires # facilities not in the implemented interface. # # - ``-grf_v2.0'': This switch is equivalent to the ``-mygrf'' switch. # It indicates that you want to link with your own graphics module # which implements the 2D graphics interface required by V2.0 of AST. # # - ``-grf_v3.2'': Indicates that you want to link with your own # graphics module which implements the 2D graphics interface required by # V3.2 of AST. # # - ``-grf_v5.6'': Indicates that you want to link with your own # graphics module which implements the 2D graphics interface required by # V5.6 of AST. # # - ``-myerr'': Requests that no arguments be generated to specify how # error messages produced by the AST library should be delivered. You # should use this option only if you have implemented an interface to a # new error delivery system yourself and wish to provide your own # arguments for linking with it. # # - ``-mygrf'': This switch has been superceeded by the ``-grf'' switch, # but is retained in order to allow applications to be linked with a # graphics module which implements the 2D interface used by AST V2.0. It # is equivalent to the ``-grf_v2.0'' switch. # # - ``-pgp'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no 2D graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via # the standard (or ``native'') version of the PGPLOT graphics # package. By default, no 2D graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # # - ``-grf3d'': Requests that no arguments be generated to specify which # 3D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new 3D graphics system yourself and wish to provide your own arguments # for linking with it. # # - ``-pgp3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no 3D graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via # the standard (or ``native'') version of the PGPLOT graphics # package. By default, no 3D graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # SOFA & PAL: # The AST distribution includes bundled copies of the IAU SOFA and # Starlink PAL libraries. These will be used for fundamental # positional astronomy calculations unless the "--with-external_pal" # option was used when AST was configured. If "--with-external_pal" # is used, this script will include "-lpal" in the returned list of # linking options, and the user should then ensure that extrnal copies # of the PAL and SOFA libraries are available (SOFA functions are used # within PAL). # Examples: #c cc display.c -L/star/lib `ast_link -pgplot` -o display #c Compiles and links a C program called ``display'' which uses #c the standard version of PGPLOT for graphical output. #c cc plotit.c -L. -L/star/lib `ast_link -grf` -lgrf -o plotit #c Compiles and links a C program ``plotit''. The ``-grf'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by the current version of AST. #c Here, this interface is supplied by means of the ``-lgrf'' library #c reference. #c cc plotit.c -L. -L/star/lib `ast_link -grf_v2.0` -lgrf -o plotit #c Compiles and links a C program ``plotit''. The ``-grf_v2.0'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by version 2.0 of AST. #c Here, this interface is supplied by means of the ``-lgrf'' library #c reference. #f f77 display.f -L/star/lib `ast_link -pgplot` -o display #f Compiles and links a Fortran program called ``display'' which uses #f the standard version of PGPLOT for graphical output. #f f77 plotit.f -L. -L/star/lib `ast_link -grf` -lgrf -o plotit #f Compiles and links a Fortran program ``plotit''. The ``-grf'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by the current version of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. #f f77 plotit.f -L. -L/star/lib `ast_link -grf_v2.0` -lgrf -o plotit #f Compiles and links a Fortran program ``plotit''. The ``-grf_v2.0'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by version 2.0 of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. # Copyright: # Copyright (C) 1997-2006 Council for the Central Laboratory of the Research Councils # Copyright (C) 2007-2008 Science & Technology Facilities Council. # All Rights Reserved. # Authors: # RFWS: R.F. Warren-Smith (STARLINK) # DSB: David S. Berry (STARLINK) # TIMJ: Tim Jenness (JAC, Hawaii) # {enter_new_authors_here} # History: # 11-JUN-1996 (RFWS): # Original version. # 11-NOV-1996 (RFWS): # Added switches. # 18-NOV-1997 (RFWS): # Adapted prologue for document extraction. # 28-SEP-1998 (RFWS): # Distinguish between -pgp and -pgplot options. # 12-JAN-2001 (DSB): # Move terminating "}" in function "find" onto a new line to # avoid error when run under bash 2.04.11(1) (redhat 7). # 3-MAY-2001 (DSB): # Added a terminating ";" to the "done" statement at the end of # the "find" function, so that ast_link can be used on Debian Linux. # 23-JAN-2004 (DSB): # Added switches to support older grf implementations. # 24-AUG-2004 (DSB): # Removed f77='y' from -ems case. # 21-APR-2005 (DSB): # Added "-fsla" option. # 16-JUN-2006 (DSB): # Ignore "-fsla" and "-clsa" options, and always use PAL. # 26-JUN-2007 (DSB): # Added "-grf3d", "-pgplot3d" and "-pgp3d" flags. # 13-NOV-2008 (TIMJ): # Add -drama option for DRAMA Ers support. # 3-MAR-2011 (DSB): # Added grf 5.6 options. # {enter_further_changes_here} # Bugs: # {note_any_bugs_here} #-- # This line is edited during configuration of this script to define a list # of the libraries that must be linked in order to resolve Fortran 77 # references made from within a C main program. Typically, these will arise # from libraries written in Fortran which the AST library (or the C # program) calls. The value here is worked out by the autoconf macro # AC_FC_LIBRARY_LDFLAGS. flibs='@FCLIBS@' # This function searches the directory path specified in PATH, looking for # an executable file which is not a directory. If found, it echos the full # file name to standard output. Otherwise, it outputs nothing. find() { IFS=':'; for d in $PATH; do f="${d:=.}/${1}" test -x "${f}" -a ! -d "${f}" && echo "${f}" && break done; } # Initialise linking options. err='' grf='' grf3d='' sla='' f77='' # Interpret command line switches. # -------------------------------- while :; do case "${1}" in # -csla - Previously used to request C version of SLALIB. Now ignored. -csla) # sla='c' shift;; # -fsla - Previously used to request Fortran version of SLALIB. Now ignored. -fsla) # sla='f' shift;; # -ems - Requests error reporting through EMS. -ems) err='ems' shift;; # -drama - Requests error reporting through DRAMA Ers. -drama) err='drama' shift;; # -myerr - Requests no error reporting. -myerr) err='my' shift;; # -grf - Requests no 2D graphics. -grf) grf='current' shift;; # -mygrf - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -mygrf) grf='v2.0' shift;; # -grf_v2.0 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -grf_v2.0) grf='v2.0' shift;; # -grf_v3.2 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V3.2. -grf_v3.2) grf='v3.2' shift;; # -grf_v5.6 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V5.6. -grf_v5.6) grf='v5.6' shift;; # -pgp - Requests 2D graphical output through Starlink PGPLOT. -pgp) grf='pgp' shift;; # -pgplot - Requests 2D graphical output through native PGPLOT. -pgplot) grf='pgplot' shift;; # -grf3d - Requests no 3D graphics. -grf3d) grf3d='current' shift;; # -pgp3d - Requests 3D graphical output through Starlink PGPLOT. -pgp3d) grf3d='pgp' shift;; # -pgplot3d - Requests 3D graphical output through native PGPLOT. -pgplot3d) grf3d='pgplot' shift;; # Once all switches have been read, continue with the rest of the script. '') break;; # Catch unrecognised arguments and report an error. *) echo >&2 "ast_link: unknown argument \""${1}"\" given" exit 1;; esac done # Link with the main AST library. # ------------------------------- # Start forming the list of arguments with the main AST library itself. args='-last ' # Generate arguments for linking PAL. # ----------------------------------- case "@EXTERNAL_PAL@" in # If we configured --with-external_pal include a link option to pick up # an external PAL library. 1) args="${args} -lpal";; # Otherwise, use the internal PAL & SOFA libraries. *) args="${args} -last_pal";; esac # Generate arguments for linking the 2D graphics system. # ------------------------------------------------------ case "${grf}" in # If using Starlink PGPLOT, link with the AST PGPLOT interface and # the Fortran library via the PGP link script (if found). pgp) args="${args} -last_pgplot `\`find pgp_link\``" f77='y';; # If using native PGPLOT, link with the AST PGPLOT interface and the # Fortran library via the PGPLOT link script (if found). pgplot) args="${args} -last_pgplot `\`find pgplot_link\``" f77='y';; # If using own graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # If using own graphics which conform to the requirements of version 5.6 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 5.6. v5.6) :;; # If using own graphics which conform to the requirements of version 3.2 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 3.2. v3.2) args="${args} -last_grf_5.6";; # If using own graphics which conform to the requirements of version 2.0 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 2.0. v2.0) args="${args} -last_grf_3.2 -last_grf_5.6";; # Default graphics (none) requires linking with all the default (null) AST # "grf" modules. *) args="${args} -last_grf_2.0 -last_grf_3.2 -last_grf_5.6";; esac # Generate arguments for linking the 3D graphics system. # ------------------------------------------------------ case "${grf3d}" in # If using Starlink PGPLOT, link with the AST 3D PGPLOT interface and # the Fortran library via the PGP link script (if found). pgp) args="${args} -last_pgplot3d `\`find pgp_link\``" f77='y';; # If using native PGPLOT, link with the AST 3D PGPLOT interface and the # Fortran library via the PGPLOT link script (if found). pgplot) args="${args} -last_pgplot3d `\`find pgplot_link\``" f77='y';; # If using own 3D graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # Default graphics (none) requires linking with all the default (null) AST # "grf3d" modules. *) args="${args} -last_grf3d";; esac # Make a second pass through the AST library. # ------------------------------------------- # This library is a link to the main AST library and results in a second # pass to resolve any backward references generated by the other modules # used above. A different library name must be used to avoid the two passes # being merged into one (either below, or by other link scripts). args="${args} -last_pass2" # Generate arguments for linking the error reporting system. # ---------------------------------------------------------- case "${err}" in # If using EMS, link with the AST EMS interface and the EMS library via the # link script (if found). ems) args="${args} -last_ems `\`find ems_link\``";; # If using DRAMA, link with the AST DRAMA interface and the DRAMA Ers library # via the link script (if found). drama) args="${args} -last_drama -lers";; # If using own error reporting, do not produce any arguments. my) :;; # Default error reporting requires linking with the default AST "err" module. *) args="${args} -last_err";; esac # Link with the maths library. # ---------------------------- args="${args} -lm" # Link with the starmem library, if available. # -------------------------------------------- args="${args} `\`find starmem_link\``" # Resolve Fortran 77 references. # ------------------------------ # If libraries written in Fortran are being linked against, then include # additional libaries needed to resolve the references these will produce # (in the event that the main program is not Fortran). if test "${f77}" = 'y'; then args="${args} ${flibs}"; fi # Pass the resulting argument list through an awk script which eliminates # all except the last reference to each library. echo "${args}" \ | awk 'BEGIN{RS=" ";FS="\n"} {if($1)f[i++]=$1} END{for(;i--;)if(!w[f[i]]++)l=f[i]" "l;print l}' # End of script. ./ast-7.3.3/proj.h0000644000175000017500000002223112262533650012265 0ustar olesoles/*============================================================================= * * WCSLIB - an implementation of the FITS WCS proposal. * Copyright (C) 1995-2002, Mark Calabretta * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library 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 Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street,Fifth Floor, Boston, MA 02110-1301, USA * * Correspondence concerning WCSLIB may be directed to: * Internet email: mcalabre@atnf.csiro.au * Postal address: Dr. Mark Calabretta, * Australia Telescope National Facility, * P.O. Box 76, * Epping, NSW, 2121, * AUSTRALIA * * Author: Mark Calabretta, Australia Telescope National Facility * $Id$ *============================================================================= * * This version of proj.h is based on the version in wcslib-2.9, but has * been modified in the following ways by the Starlink project (e-mail: * ussc@star.rl.ac.uk): * - Support for non-ANSI C prototypes removed * - Changed the name of the WCSLIB_PROJ macro to WCSLIB_PROJ_INCLUDED * - Changed names of all functions and structures to avoid name * clashes with wcslib. * - Change the maximum number of projection parameters to 100. * - Added definition of macro WCSLIB_MXPAR, and use it to define * size of projection parameter array within AstPrjPrm structure. * - Added component "p2" to the AstPrjPrm structure to hold projection * parameters associated with the longitude axis (for use within * the tpn.c file which holds an implementation of the old "TAN with * correction terms" projection). * - Added prototypes for TPN projection functions (defined in file * tpn.c). * - Added prototypes for HPX projection functions. *===========================================================================*/ #ifndef WCSLIB_PROJ_INCLUDED #define WCSLIB_PROJ_INCLUDED #ifdef __cplusplus extern "C" { #endif #define WCSLIB_MXPAR 100 extern int npcode; extern char pcodes[26][4]; struct AstPrjPrm { char code[4]; int flag; double phi0, theta0; double r0; double *p; double *p2; double w[20]; int n; int (*astPRJfwd)(const double, const double, struct AstPrjPrm *, double *, double *); int (*astPRJrev)(const double, const double, struct AstPrjPrm *, double *, double *); }; int astPRJset(const char [], struct AstPrjPrm *); int astPRJfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astPRJrev(const double, const double, struct AstPrjPrm *, double *, double *); int astAZPset(struct AstPrjPrm *); int astAZPfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astAZPrev(const double, const double, struct AstPrjPrm *, double *, double *); int astSZPset(struct AstPrjPrm *); int astSZPfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astSZPrev(const double, const double, struct AstPrjPrm *, double *, double *); int astTANset(struct AstPrjPrm *); int astTANfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astTANrev(const double, const double, struct AstPrjPrm *, double *, double *); int astSTGset(struct AstPrjPrm *); int astSTGfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astSTGrev(const double, const double, struct AstPrjPrm *, double *, double *); int astSINset(struct AstPrjPrm *); int astSINfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astSINrev(const double, const double, struct AstPrjPrm *, double *, double *); int astARCset(struct AstPrjPrm *); int astARCfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astARCrev(const double, const double, struct AstPrjPrm *, double *, double *); int astZPNset(struct AstPrjPrm *); int astZPNfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astZPNrev(const double, const double, struct AstPrjPrm *, double *, double *); int astZEAset(struct AstPrjPrm *); int astZEAfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astZEArev(const double, const double, struct AstPrjPrm *, double *, double *); int astAIRset(struct AstPrjPrm *); int astAIRfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astAIRrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCYPset(struct AstPrjPrm *); int astCYPfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCYPrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCEAset(struct AstPrjPrm *); int astCEAfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCEArev(const double, const double, struct AstPrjPrm *, double *, double *); int astCARset(struct AstPrjPrm *); int astCARfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCARrev(const double, const double, struct AstPrjPrm *, double *, double *); int astMERset(struct AstPrjPrm *); int astMERfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astMERrev(const double, const double, struct AstPrjPrm *, double *, double *); int astSFLset(struct AstPrjPrm *); int astSFLfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astSFLrev(const double, const double, struct AstPrjPrm *, double *, double *); int astPARset(struct AstPrjPrm *); int astPARfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astPARrev(const double, const double, struct AstPrjPrm *, double *, double *); int astMOLset(struct AstPrjPrm *); int astMOLfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astMOLrev(const double, const double, struct AstPrjPrm *, double *, double *); int astAITset(struct AstPrjPrm *); int astAITfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astAITrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCOPset(struct AstPrjPrm *); int astCOPfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCOPrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCOEset(struct AstPrjPrm *); int astCOEfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCOErev(const double, const double, struct AstPrjPrm *, double *, double *); int astCODset(struct AstPrjPrm *); int astCODfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCODrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCOOset(struct AstPrjPrm *); int astCOOfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCOOrev(const double, const double, struct AstPrjPrm *, double *, double *); int astBONset(struct AstPrjPrm *); int astBONfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astBONrev(const double, const double, struct AstPrjPrm *, double *, double *); int astPCOset(struct AstPrjPrm *); int astPCOfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astPCOrev(const double, const double, struct AstPrjPrm *, double *, double *); int astTSCset(struct AstPrjPrm *); int astTSCfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astTSCrev(const double, const double, struct AstPrjPrm *, double *, double *); int astCSCset(struct AstPrjPrm *); int astCSCfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astCSCrev(const double, const double, struct AstPrjPrm *, double *, double *); int astQSCset(struct AstPrjPrm *); int astQSCfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astQSCrev(const double, const double, struct AstPrjPrm *, double *, double *); int astHPXset(struct AstPrjPrm *); int astHPXfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astHPXrev(const double, const double, struct AstPrjPrm *, double *, double *); int astTPNset(struct AstPrjPrm *); int astTPNfwd(const double, const double, struct AstPrjPrm *, double *, double *); int astTPNrev(const double, const double, struct AstPrjPrm *, double *, double *); extern const char *astPRJset_errmsg[]; extern const char *astPRJfwd_errmsg[]; extern const char *astPRJrev_errmsg[]; #ifdef __cplusplus }; #endif #endif /* WCSLIB_PROJ_INCLUDED */ ./ast-7.3.3/grf_3.2.c0000644000175000017500000000452312262533650012452 0ustar olesoles/* * Name: * grf_3.2.c * Purpose: * Implement the grf module required by AST V3.2 if no graphics system * is available. * Description: * This file implements the low level graphics functions required * by the rest of AST V3.2, except for those already defined in * grf_2.0.c (i.e. those needed by AST V2.0). These implementations * simply report an error when called. * Inheritance: * This module is not a class and does not inherit. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 23-NOV-2004 (DSB): * Original version. */ /* Header files */ /* ============ */ #include "grf.h" /* Declare the functions in this module */ #include "error.h" /* AST error reporting facilities */ #include "ast_err.h" /* AST error codes */ /* Function Prototypes */ /* =================== */ static void Report( const char * ); /* Function definitions */ /* ==================== */ int astGScales( float *alpha, float *beta ){ Report( "astGScales" ); return 0; } int astGCap( int cap, int value ){ return 0; } static void Report( const char *name ){ astError( AST__GRFER, "%s: The graphics facilities implement by %s " "(introduced at AST V3.2) are needed but are unavailable.", name, name ); astError( AST__GRFER, "Re-link using a suitable option such as '-pgplot' " "with the ast_link script, or add an implementation of this " "function to your 'grf' module." ); } ./ast-7.3.3/fstcobsdatalocation.c0000644000175000017500000000717412262533650015345 0ustar olesoles/* *+ * Name: * fstcobsdatalocation.c * Purpose: * Define a FORTRAN 77 interface to the AST StcObsDataLocation class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the StcObsDataLocation class. * Routines Defined: * AST_ISASTCOBSDATALOCATION * AST_STCOBSDATALOCATION * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-NOV-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "stcobsdatalocation.h" /* C interface to the StcObsDataLocation class */ F77_LOGICAL_FUNCTION(ast_isastcobsdatalocation)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASTCOBSDATALOCATION", NULL, 0 ); astWatchSTATUS( RESULT = astIsAStcObsDataLocation( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_stcobsdatalocation)( INTEGER(REG), INTEGER(NCOORDS), INTEGER_ARRAY(COORDS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(REG) GENPTR_INTEGER(NCOORDS) GENPTR_CHARACTER(OPTIONS) GENPTR_INTEGER_ARRAY(COORDS) AstKeyMap **coords; F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_STCOBSDATALOCATION", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } /* Convert supplied integers to pointers. */ coords = astMalloc( sizeof( AstKeyMap * )*(size_t)( *NCOORDS )); if( astOK ) { for( i = 0; i < *NCOORDS; i++ ) { coords[ i ] = (AstKeyMap *) astMakePointer( astI2P( COORDS[ i ] )); } } RESULT = astP2I( astStcObsDataLocation( astI2P( *REG ), *NCOORDS, coords, "%s", options ) ); astFree( coords ); astFree( options ); ) return RESULT; } ./ast-7.3.3/table.h0000644000175000017500000002625112262533650012410 0ustar olesoles#if !defined( TABLE_INCLUDED ) /* Include this file only once */ #define TABLE_INCLUDED /* *+ * Name: * table.h * Type: * C include file. * Purpose: * Define the interface to the Table class. * Invocation: * #include "table.h" * Description: * This include file defines the interface to the Table class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * Inheritance: * The Table class inherits from the KeyMap class. * Copyright: * Copyright (C) 2010 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-NOV-2010 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "keymap.h" /* Parent class */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif #if defined(astCLASS) /* Protected */ /* Maximum length of a column name */ #define AST__MXCOLNAMLEN 100 /* Maximum length of a key for a column cell */ #define AST__MXCOLKEYLEN ( AST__MXCOLNAMLEN + 23 ) #endif /* Type Definitions. */ /* ================= */ /* Table structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstTable { /* Attributes inherited from the parent class. */ AstKeyMap keymap; /* Parent class structure */ /* Attributes specific to objects in this class. */ int nrow; /* Mo. of rows in table */ AstKeyMap *columns; /* KeyMap holding column definitions */ AstKeyMap *parameters; /* KeyMap holding parameter definitions */ } AstTable; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstTableVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstKeyMapVtab keymap_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ AstKeyMap *(* ColumnProps)( AstTable *, int * ); AstKeyMap *(* ParameterProps)( AstTable *, int * ); const char *(* ColumnName)( AstTable *, int, int * ); const char *(* ParameterName)( AstTable *, int, int * ); const char *(* GetColumnUnit)( AstTable *, const char *, int * ); int (* GetColumnLenC)( AstTable *, const char *, int * ); int (* GetColumnLength)( AstTable *, const char *, int * ); int (* GetColumnNdim)( AstTable *, const char *, int * ); int (* GetColumnType)( AstTable *, const char *, int * ); int (* GetNcolumn)( AstTable *, int * ); int (* GetNparameter)( AstTable *, int * ); int (* GetNrow)( AstTable *, int * ); int (* HasColumn)( AstTable *, const char *, int * ); int (* HasParameter)( AstTable *, const char *, int * ); void (* AddColumn)( AstTable *, const char *, int, int, int *, const char *, int * ); void (* AddParameter)( AstTable *, const char *, int * ); void (* ColumnShape)( AstTable *, const char *, int, int *, int *, int * ); void (* PurgeRows)( AstTable *, int * ); void (* RemoveColumn)( AstTable *, const char *, int * ); void (* RemoveParameter)( AstTable *, const char *, int * ); void (* RemoveRow)( AstTable *, int, int * ); void (* SetNrow)( AstTable *, int, int * ); } AstTableVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstTableGlobals { AstTableVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstTableGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitTableGlobals_( AstTableGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Table) /* Check class membership */ astPROTO_ISA(Table) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstTable *astTable_( const char *, int *, ...); #else AstTable *astTableId_( const char *, ... )__attribute__((format(printf,1,2))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstTable *astInitTable_( void *, size_t, int, AstTableVtab *, const char *, int * ); /* Vtab initialiser. */ void astInitTableVtab_( AstTableVtab *, const char *, int * ); /* Loader. */ AstTable *astLoadTable_( void *, size_t, AstTableVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astAddColumn_( AstTable *, const char *, int, int, int *, const char *, int * ); void astAddParameter_( AstTable *, const char *, int * ); void astRemoveColumn_( AstTable *, const char *, int * ); void astRemoveParameter_( AstTable *, const char *, int * ); void astRemoveRow_( AstTable *, int, int * ); void astPurgeRows_( AstTable *, int * ); const char *astColumnName_( AstTable *, int, int * ); const char *astParameterName_( AstTable *, int, int * ); void astColumnShape_( AstTable *, const char *, int, int *, int *, int * ); int astHasColumn_( AstTable *, const char *, int * ); int astHasParameter_( AstTable *, const char *, int * ); #if defined(astCLASS) /* Protected */ AstKeyMap *astColumnProps_( AstTable *, int * ); AstKeyMap *astParameterProps_( AstTable *, int * ); const char *astGetColumnUnit_( AstTable *, const char *, int * ); int astGetColumnLenC_( AstTable *, const char *, int * ); int astGetColumnLength_( AstTable *, const char *, int * ); int astGetColumnNdim_( AstTable *, const char *, int * ); int astGetColumnType_( AstTable *, const char *, int * ); int astGetNcolumn_( AstTable *, int * ); int astGetNparameter_( AstTable *, int * ); int astGetNrow_( AstTable *, int * ); void astSetNrow_( AstTable *, int, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckTable(this) astINVOKE_CHECK(Table,this,0) #define astVerifyTable(this) astINVOKE_CHECK(Table,this,1) /* Test class membership. */ #define astIsATable(this) astINVOKE_ISA(Table,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astTable astINVOKE(F,astTable_) #else #define astTable astINVOKE(F,astTableId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitTable(mem,size,init,vtab,name) \ astINVOKE(O,astInitTable_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitTableVtab(vtab,name) astINVOKE(V,astInitTableVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadTable(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadTable_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckTable to validate Table pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astAddColumn(this,name,type,ndim,dims,unit) astINVOKE(V,astAddColumn_(astCheckTable(this),name,type,ndim,dims,unit, STATUS_PTR)) #define astAddParameter(this,name) astINVOKE(V,astAddParameter_(astCheckTable(this),name,STATUS_PTR)) #define astRemoveColumn(this,name) astINVOKE(V,astRemoveColumn_(astCheckTable(this),name,STATUS_PTR)) #define astRemoveParameter(this,name) astINVOKE(V,astRemoveParameter_(astCheckTable(this),name,STATUS_PTR)) #define astRemoveRow(this,index) astINVOKE(V,astRemoveRow_(astCheckTable(this),index,STATUS_PTR)) #define astPurgeRows(this) astINVOKE(V,astPurgeRows_(astCheckTable(this),STATUS_PTR)) #define astColumnName(this,index) astINVOKE(V,astColumnName_(astCheckTable(this),index,STATUS_PTR)) #define astParameterName(this,index) astINVOKE(V,astParameterName_(astCheckTable(this),index,STATUS_PTR)) #define astColumnShape(this,column,mxdim,ndim,dims) astINVOKE(V,astColumnShape_(astCheckTable(this),column,mxdim,ndim,dims,STATUS_PTR)) #define astHasColumn(this,column) astINVOKE(V,astHasColumn_(astCheckTable(this),column,STATUS_PTR)) #define astHasParameter(this,param) astINVOKE(V,astHasParameter_(astCheckTable(this),param,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astColumnProps(this) \ astINVOKE(O,astColumnProps_(astCheckTable(this),STATUS_PTR)) #define astParameterProps(this) \ astINVOKE(O,astParameterProps_(astCheckTable(this),STATUS_PTR)) #define astGetNcolumn(this) \ astINVOKE(V,astGetNcolumn_(astCheckTable(this),STATUS_PTR)) #define astGetNparameter(this) \ astINVOKE(V,astGetNparameter_(astCheckTable(this),STATUS_PTR)) #define astGetNrow(this) \ astINVOKE(V,astGetNrow_(astCheckTable(this),STATUS_PTR)) #define astSetNrow(this,value) \ astINVOKE(V,astSetNrow_(astCheckTable(this),value,STATUS_PTR)) #define astGetColumnLenC(this,column) \ astINVOKE(V,astGetColumnLenC_(astCheckTable(this),column,STATUS_PTR)) #define astGetColumnLength(this,column) \ astINVOKE(V,astGetColumnLength_(astCheckTable(this),column,STATUS_PTR)) #define astGetColumnNdim(this,column) \ astINVOKE(V,astGetColumnNdim_(astCheckTable(this),column,STATUS_PTR)) #define astGetColumnType(this,column) \ astINVOKE(V,astGetColumnType_(astCheckTable(this),column,STATUS_PTR)) #define astGetColumnUnit(this,column) \ astINVOKE(V,astGetColumnUnit_(astCheckTable(this),column,STATUS_PTR)) #endif #endif ./ast-7.3.3/fframe.c0000644000175000017500000003450312262533650012553 0ustar olesoles/* *+ * Name: * fframe.c * Purpose: * Define a FORTRAN 77 interface to the AST Frame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Frame class. * Routines Defined: * AST_ANGLE * AST_AXANGLE * AST_AXDISTANCE * AST_AXOFFSET * AST_CONVERT * AST_DISTANCE * AST_FORMAT * AST_FRAME * AST_GETACTIVEUNIT * AST_INTERSECT * AST_ISAFRAME * AST_NORM * AST_OFFSET * AST_OFFSET2 * AST_PERMAXES * AST_PICKAXES * AST_RESOLVE * AST_SETACTIVEUNIT * AST_UNFORMAT * Copyright: * Copyright (C) 1997-2009 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 23-JUL-1996 (RFWS): * Original version. * 16-SEP-1996 (RFWS): * Added AST_DISTANCE and AST_OFFSET. * 25-FEB-1998 (RFWS): * Added AST_UNFORMAT. * 21-JUN-2001 (DSB): * Added AST_ANGLE and AST_OFFSET2. * 29-AUG-2001 (DSB): * Added AST_AXDISTANCE and AST_AXOFFSET. * 9-SEP-2001 (DSB): * Added AST_RESOLVE and AST_BEAR. * 21-SEP-2001 (DSB): * Replaced AST_BEAR by AST_AXANGLE. * 17-DEC-2002 (DSB): * Added AST_GETACTIVEUNIT and AST_SETACTIVEUNIT. * 14-JAN-2009 (DSB): * Added AST_INTERSECT. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "mapping.h" /* C interface to the Mapping class */ #include "frame.h" /* C interface to the Frame class */ F77_INTEGER_FUNCTION(ast_convert)( INTEGER(FROM), INTEGER(TO), CHARACTER(NAMELIST), INTEGER(STATUS) TRAIL(NAMELIST) ) { GENPTR_INTEGER(FROM) GENPTR_INTEGER(TO) GENPTR_INTEGER(NAMELIST) F77_INTEGER_TYPE(RESULT); char *namelist; astAt( "AST_CONVERT", NULL, 0 ); astWatchSTATUS( namelist = astString( NAMELIST, NAMELIST_length ); RESULT = astP2I( astConvert( astI2P( *FROM ), astI2P( *TO ), namelist ) ); namelist = astFree( namelist ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_angle)( INTEGER(THIS), DOUBLE_ARRAY(A), DOUBLE_ARRAY(B), DOUBLE_ARRAY(C), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(A) GENPTR_DOUBLE_ARRAY(B) GENPTR_DOUBLE_ARRAY(C) F77_DOUBLE_TYPE(RESULT); astAt( "AST_ANGLE", NULL, 0 ); astWatchSTATUS( RESULT = astAngle( astI2P( *THIS ), A, B, C ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_axangle)( INTEGER(THIS), DOUBLE_ARRAY(A), DOUBLE_ARRAY(B), INTEGER(AXIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(A) GENPTR_DOUBLE_ARRAY(B) GENPTR_INTEGER(AXIS) F77_DOUBLE_TYPE(RESULT); astAt( "AST_AXANGLE", NULL, 0 ); astWatchSTATUS( RESULT = astAxAngle( astI2P( *THIS ), A, B, *AXIS ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_distance)( INTEGER(THIS), DOUBLE_ARRAY(POINT1), DOUBLE_ARRAY(POINT2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE_ARRAY(POINT2) F77_DOUBLE_TYPE(RESULT); astAt( "AST_DISTANCE", NULL, 0 ); astWatchSTATUS( RESULT = astDistance( astI2P( *THIS ), POINT1, POINT2 ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_axdistance)( INTEGER(THIS), INTEGER(AXIS), DOUBLE(V1), DOUBLE(V2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(AXIS) GENPTR_DOUBLE(V1) GENPTR_DOUBLE(V2) F77_DOUBLE_TYPE(RESULT); astAt( "AST_AXDISTANCE", NULL, 0 ); astWatchSTATUS( RESULT = astAxDistance( astI2P( *THIS ), *AXIS, *V1, *V2 ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_axoffset)( INTEGER(THIS), INTEGER(AXIS), DOUBLE(V1), DOUBLE(DIST), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(AXIS) GENPTR_DOUBLE(V1) GENPTR_DOUBLE(DIST) F77_DOUBLE_TYPE(RESULT); astAt( "AST_AXOFFSET", NULL, 0 ); astWatchSTATUS( RESULT = astAxOffset( astI2P( *THIS ), *AXIS, *V1, *DIST ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_findframe)( INTEGER(TARGET), INTEGER(TEMPLATE), CHARACTER(NAMELIST), INTEGER(STATUS) TRAIL(NAMELIST) ) { GENPTR_INTEGER(TARGET) GENPTR_INTEGER(TEMPLATE) GENPTR_INTEGER(NAMELIST) F77_INTEGER_TYPE(RESULT); char *namelist; astAt( "AST_FINDFRAME", NULL, 0 ); astWatchSTATUS( namelist = astString( NAMELIST, NAMELIST_length ); RESULT = astP2I( astFindFrame( astI2P( *TARGET ), astI2P( *TEMPLATE ), namelist ) ); ) return RESULT; } F77_SUBROUTINE(ast_matchaxes)( INTEGER(FRM1), INTEGER(FRM2), INTEGER_ARRAY(AXES), INTEGER(STATUS) ) { GENPTR_INTEGER(FRM1) GENPTR_INTEGER(FRM2) GENPTR_INTEGER_ARRAY(AXES) astAt( "AST_MATCHAXES", NULL, 0 ); astWatchSTATUS( astMatchAxes( astI2P( *FRM1 ), astI2P( *FRM2 ), AXES ); ) } /* NO_CHAR_FUNCTION indicates that the f77.h method of returning a character result doesn't work, so add an extra argument instead and wrap this function up in a normal FORTRAN 77 function (in the file frame.f). */ #if NO_CHAR_FUNCTION F77_SUBROUTINE(ast_format_a)( CHARACTER(RESULT), #else F77_SUBROUTINE(ast_format)( CHARACTER_RETURN_VALUE(RESULT), #endif INTEGER(THIS), INTEGER(AXIS), DOUBLE(VALUE), INTEGER(STATUS) #if NO_CHAR_FUNCTION TRAIL(RESULT) #endif ) { GENPTR_CHARACTER(RESULT) GENPTR_INTEGER(THIS) GENPTR_INTEGER(AXIS) GENPTR_DOUBLE(VALUE) const char *result; int i; astAt( "AST_FORMAT", NULL, 0 ); astWatchSTATUS( result = astFormat( astI2P( *THIS ), *AXIS, *VALUE ); i = 0; if ( astOK ) { /* Copy result */ for ( ; result[ i ] && i < RESULT_length; i++ ) { RESULT[ i ] = result[ i ]; } } while ( i < RESULT_length ) RESULT[ i++ ] = ' '; /* Pad with blanks */ ) } F77_INTEGER_FUNCTION(ast_frame)( INTEGER(NAXES), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NAXES) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_FRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astFrame( *NAXES, "%s", options ) ); (void) astFree( options ); ) return RESULT; } F77_LOGICAL_FUNCTION(ast_isaframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsAFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_LOGICAL_FUNCTION(ast_getactiveunit)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_GETACTIVEUNIT", NULL, 0 ); astWatchSTATUS( RESULT = astGetActiveUnit( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_setactiveunit)( INTEGER(THIS), LOGICAL(VALUE), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_LOGICAL(VALUE) astAt( "AST_SETACTIVEUNIT", NULL, 0 ); astWatchSTATUS( astSetActiveUnit( astI2P( *THIS ), F77_ISTRUE( *VALUE ) ? 1 : 0 ); ) } F77_SUBROUTINE(ast_norm)( INTEGER(THIS), DOUBLE_ARRAY(VALUE), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(VALUE) astAt( "AST_NORM", NULL, 0 ); astWatchSTATUS( astNorm( astI2P( *THIS ), VALUE ); ) } F77_SUBROUTINE(ast_offset)( INTEGER(THIS), DOUBLE_ARRAY(POINT1), DOUBLE_ARRAY(POINT2), DOUBLE(OFFSET), DOUBLE_ARRAY(POINT3), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE_ARRAY(POINT2) GENPTR_DOUBLE(OFFSET) GENPTR_DOUBLE_ARRAY(POINT3) astAt( "AST_OFFSET", NULL, 0 ); astWatchSTATUS( astOffset( astI2P( *THIS ), POINT1, POINT2, *OFFSET, POINT3 ); ) } F77_DOUBLE_FUNCTION(ast_offset2)( INTEGER(THIS), DOUBLE_ARRAY(POINT1), DOUBLE(ANGLE), DOUBLE(OFFSET), DOUBLE_ARRAY(POINT2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE(ANGLE) GENPTR_DOUBLE(OFFSET) GENPTR_DOUBLE_ARRAY(POINT2) F77_DOUBLE_TYPE(RESULT); astAt( "AST_OFFSET2", NULL, 0 ); astWatchSTATUS( RESULT = astOffset2( astI2P( *THIS ), POINT1, *ANGLE, *OFFSET, POINT2 ); ) return RESULT; } F77_SUBROUTINE(ast_resolve)( INTEGER(THIS), DOUBLE_ARRAY(POINT1), DOUBLE_ARRAY(POINT2), DOUBLE_ARRAY(POINT3), DOUBLE_ARRAY(POINT4), DOUBLE(D1), DOUBLE(D2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE_ARRAY(POINT2) GENPTR_DOUBLE_ARRAY(POINT3) GENPTR_DOUBLE_ARRAY(POINT4) GENPTR_DOUBLE(D1) GENPTR_DOUBLE(D2) astAt( "AST_RESOLVE", NULL, 0 ); astWatchSTATUS( astResolve( astI2P( *THIS ), POINT1, POINT2, POINT3, POINT4, D1, D2 ); ) } F77_SUBROUTINE(ast_intersect)( INTEGER(THIS), DOUBLE_ARRAY(A1), DOUBLE_ARRAY(A2), DOUBLE_ARRAY(B1), DOUBLE_ARRAY(B2), DOUBLE_ARRAY(CROSS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(A1) GENPTR_DOUBLE_ARRAY(A2) GENPTR_DOUBLE_ARRAY(B1) GENPTR_DOUBLE_ARRAY(B2) GENPTR_DOUBLE_ARRAY(CROSS) astAt( "AST_INTERSECT", NULL, 0 ); astWatchSTATUS( astIntersect( astI2P( *THIS ), A1, A2, B1, B2, CROSS ); ) } F77_SUBROUTINE(ast_permaxes)( INTEGER(THIS), INTEGER_ARRAY(PERM), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER_ARRAY(PERM) astAt( "AST_PERMAXES", NULL, 0 ); astWatchSTATUS( astPermAxes( astI2P( *THIS ), PERM ); ) } F77_INTEGER_FUNCTION(ast_pickaxes)( INTEGER(THIS), INTEGER(NAXES), INTEGER_ARRAY(AXES), INTEGER(MAP), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(NAXES) GENPTR_INTEGER_ARRAY(AXES) GENPTR_INTEGER(MAP) F77_INTEGER_TYPE(RESULT); AstMapping *map; astAt( "AST_PICKAXES", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astPickAxes( astI2P( *THIS ), *NAXES, AXES, &map ) ); *MAP = astP2I( map ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_unformat)( INTEGER(THIS), INTEGER(AXIS), CHARACTER(STRING), DOUBLE(VALUE), INTEGER(STATUS) TRAIL(STRING) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(AXIS) GENPTR_CHARACTER(STRING) GENPTR_DOUBLE(VALUE) GENPTR_INTEGER(STATUS) F77_INTEGER_TYPE(RESULT); char *string; double value; astAt( "AST_UNFORMAT", NULL, 0 ); astWatchSTATUS( string = astString( STRING, STRING_length ); RESULT = astUnformat( astI2P( *THIS ), *AXIS, string, &value ); *VALUE = value; (void) astFree( string ); ) return RESULT; } ./ast-7.3.3/table.c0000644000175000017500000052460712262533650012413 0ustar olesoles/* *class++ * Name: * Table * Purpose: * A 2-dimensional table of values. * Constructor Function: c astTable f AST_TABLE * Description: * The Table class is a type of KeyMap that represents a two-dimensional * table of values. The c astMapGet... and astMapPut... f AST_MAPGET... and AST_MAPPUT... * methods provided by the KeyMap class should be used for storing and * retrieving values from individual cells within a Table. Each entry * in the KeyMap represents a single cell of the table and has an * associated key of the form "(i)" where "" is the * upper-case name of a table column and "i" is the row index (the * first row is row 1). Keys of this form should always be used when * using KeyMap methods to access entries within a Table. * * Columns must be declared using the c astAddColumn f AST_ADDCOLUMN * method before values can be stored within them. This also fixes the * type and shape of the values that may be stored in any cell of the * column. Cells may contain scalar or vector values of any data type * supported by the KeyMap class. Multi-dimensional arrays may also be * stored, but these must be vectorised when storing and retrieving * them within a table cell. All cells within a single column must * have the same type and shape, as specified when the column is added * to the Table. * * Tables may have parameters that describe global properties of the * entire table. These are stored as entries in the parent KeyMap and * can be access using the get and set method of the KeyMap class. * However, parameters must be declared using the c astAddParameter f AST_ADDPARAMETER * method before being accessed. * * Note - since accessing entries within a KeyMap is a relatively slow * process, it is not recommended to use the Table class to store * very large tables. * Inheritance: * The Table class inherits from the KeyMap class. * Attributes: * In addition to those attributes common to all KeyMaps, every * Table also has the following attributes: * * - ColumnLenC(column): The largest string length of any value in a column * - ColumnLength(column): The number of elements in each value in a column * - ColumnNdim(column): The number of axes spanned by each value in a column * - ColumnType(column): The data type of each value in a column * - ColumnUnit(column): The unit string describing each value in a column * - Ncolumn: The number of columns currently in the Table * - Nrow: The number of rows currently in the Table * - Nparameter: The number of global parameters currently in the Table * Functions: c In addition to those functions applicable to all KeyMaps, the c following functions may also be applied to all Tables: f In addition to those routines applicable to all KeyMaps, the f following routines may also be applied to all Tables: * c - astAddColumn: Add a new column definition to a Table c - astAddParameter: Add a new global parameter definition to a Table c - astColumnName: Return the name of the column with a given index c - astColumnShape: Return the shape of the values in a named column c - astHasColumn: Checks if a column exists in a Table c - astHasParameter: Checks if a global parameter exists in a Table c - astParameterName: Return the name of the parameter with a given index c - astPurgeRows: Remove all empty rows from a Table c - astRemoveColumn: Remove a column from a Table c - astRemoveParameter: Remove a global parameter from a Table c - astRemoveRow: Remove a row from a Table f - AST_ADDCOLUMN: Add a new column definition to a Table f - AST_ADDPARAMETER: Add a new global parameter definition to a Table f - AST_COLUMNNAME: Return the name of the column with a given index f - AST_COLUMNSHAPE: Return the shape of the values in a named column f - AST_HASCOLUMN: Checks if a column exists in a Table f - AST_HASPARAMETER: Checks if a global parameter exists in a Table f - AST_PARAMETERNAME: Return the name of the parameter with a given index f - AST_PURGEROWS: Remove all empty rows from a Table f - AST_REMOVECOLUMN: Remove a column from a Table f - AST_REMOVEPARAMETER: Remove a global parameter from a Table f - AST_REMOVEROW: Remove a row from a Table * Copyright: * Copyright (C) 2010-2011 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-NOV-2010 (DSB): * Original version. * 13-MAY-2011 (DSB): * Added support for table parameters. * 16-NOV-2013 (DSB): * Fix bug in forming keys in GetColumnLenC. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Table /* Fixed KeyMap entry names */ #define LENGTH "Length" #define NAME "Name" #define NROW "Nrow" #define SHAPE "Shape" #define SIZE "Size" #define TYPE "Type" #define UNIT "Unit" /* A function macro that puts quotes around a value */ #define STRING(w) #w /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "keymap.h" /* Coordinate keymaps (parent class) */ #include "channel.h" /* I/O channels */ #include "table.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static void (* parent_setkeycase)( AstKeyMap *, int, int * ); static void (* parent_clearkeycase)( AstKeyMap *, int * ); static int (* parent_equal)( AstObject *, AstObject *, int * ); static int (* parent_getobjsize)( AstObject *, int * ); static int (* parent_mapget0a)( AstKeyMap *, const char *, AstObject * *, int *); static int (* parent_mapget0c)( AstKeyMap *, const char *, const char **, int *); static int (* parent_mapget0d)( AstKeyMap *, const char *, double *, int *); static int (* parent_mapget0f)( AstKeyMap *, const char *, float *, int *); static int (* parent_mapget0i)( AstKeyMap *, const char *, int *, int *); static int (* parent_mapget0p)( AstKeyMap *, const char *, void **, int *); static int (* parent_mapget0b)( AstKeyMap *, const char *, unsigned char *, int *); static int (* parent_mapget0s)( AstKeyMap *, const char *, short int *, int *); static int (* parent_mapget1a)( AstKeyMap *, const char *, int, int *, AstObject **, int * ); static int (* parent_mapget1c)( AstKeyMap *, const char *, int, int, int *, char *, int * ); static int (* parent_mapget1d)( AstKeyMap *, const char *, int, int *, double *, int * ); static int (* parent_mapget1f)( AstKeyMap *, const char *, int, int *, float *, int * ); static int (* parent_mapget1i)( AstKeyMap *, const char *, int, int *, int *, int * ); static int (* parent_mapget1p)( AstKeyMap *, const char *, int, int *, void **, int * ); static int (* parent_mapget1s)( AstKeyMap *, const char *, int, int *, short int *, int * ); static int (* parent_mapget1b)( AstKeyMap *, const char *, int, int *, unsigned char *, int * ); static int (* parent_mapgetelema)( AstKeyMap *, const char *, int, AstObject **, int * ); static int (* parent_mapgetelemc)( AstKeyMap *, const char *, int, int, char *, int * ); static int (* parent_mapgetelemd)( AstKeyMap *, const char *, int, double *, int * ); static int (* parent_mapgetelemf)( AstKeyMap *, const char *, int, float *, int * ); static int (* parent_mapgetelemi)( AstKeyMap *, const char *, int, int *, int * ); static int (* parent_mapgetelemp)( AstKeyMap *, const char *, int, void **, int * ); static int (* parent_mapgetelems)( AstKeyMap *, const char *, int, short int *, int * ); static int (* parent_mapgetelemb)( AstKeyMap *, const char *, int, unsigned char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_mapput0a)( AstKeyMap *, const char *, AstObject *, const char *, int *); static void (* parent_mapput0c)( AstKeyMap *, const char *, const char *, const char *, int *); static void (* parent_mapput0d)( AstKeyMap *, const char *, double, const char *, int *); static void (* parent_mapput0f)( AstKeyMap *, const char *, float, const char *, int *); static void (* parent_mapput0i)( AstKeyMap *, const char *, int, const char *, int *); static void (* parent_mapput0p)( AstKeyMap *, const char *, void *, const char *, int *); static void (* parent_mapput0b)( AstKeyMap *, const char *, unsigned char, const char *, int *); static void (* parent_mapput0s)( AstKeyMap *, const char *, short int, const char *, int *); static void (* parent_mapput1a)( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * ); static void (* parent_mapput1c)( AstKeyMap *, const char *, int, const char *const [], const char *, int * ); static void (* parent_mapput1d)( AstKeyMap *, const char *, int, const double *, const char *, int * ); static void (* parent_mapput1f)( AstKeyMap *, const char *, int, const float *, const char *, int * ); static void (* parent_mapput1i)( AstKeyMap *, const char *, int, const int *, const char *, int * ); static void (* parent_mapput1p)( AstKeyMap *, const char *, int, void *const [], const char *, int * ); static void (* parent_mapput1b)( AstKeyMap *, const char *, int, const unsigned char *, const char *, int * ); static void (* parent_mapput1s)( AstKeyMap *, const char *, int, const short int *, const char *, int * ); static void (* parent_mapputelema)( AstKeyMap *, const char *, int, AstObject *, int * ); static void (* parent_mapputelemc)( AstKeyMap *, const char *, int, const char *, int * ); static void (* parent_mapputelemd)( AstKeyMap *, const char *, int, double, int * ); static void (* parent_mapputelemf)( AstKeyMap *, const char *, int, float, int * ); static void (* parent_mapputelemi)( AstKeyMap *, const char *, int, int, int * ); static void (* parent_mapputelemp)( AstKeyMap *, const char *, int, void *, int * ); static void (* parent_mapputelemb)( AstKeyMap *, const char *, int, unsigned char, int * ); static void (* parent_mapputelems)( AstKeyMap *, const char *, int, short int, int * ); static void (* parent_mapremove)( AstKeyMap *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_mapputu)( AstKeyMap *, const char *, const char *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Table) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(Table,Class_Init) #define class_vtab astGLOBAL(Table,Class_Vtab) #define getattrib_buff astGLOBAL(Table,GetAttrib_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstTableVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstTable *astTableId_( const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstKeyMap *ColumnProps( AstTable *, int * ); static AstKeyMap *ParameterProps( AstTable *, int * ); static const char *ColumnName( AstTable *, int index, int * ); static const char *ParameterName( AstTable *, int index, int * ); static const char *GetColumnUnit( AstTable *, const char *, int * ); static const char *TypeString( int ); static int Equal( AstObject *, AstObject *, int * ); static int GetColumnLenC( AstTable *, const char *, int * ); static int GetColumnLength( AstTable *, const char *, int * ); static int GetColumnNdim( AstTable *, const char *, int * ); static int GetColumnType( AstTable *, const char *, int * ); static int GetNcolumn( AstTable *, int * ); static int GetNparameter( AstTable *, int * ); static int GetObjSize( AstObject *, int * ); static int HasColumn( AstTable *, const char *, int *); static int HasParameter( AstTable *, const char *, int *); static int MapGet0A( AstKeyMap *, const char *, AstObject **, int * ); static int MapGet0B( AstKeyMap *, const char *, unsigned char *, int * ); static int MapGet0C( AstKeyMap *, const char *, const char **, int * ); static int MapGet0D( AstKeyMap *, const char *, double *, int * ); static int MapGet0F( AstKeyMap *, const char *, float *, int * ); static int MapGet0I( AstKeyMap *, const char *, int *, int * ); static int MapGet0P( AstKeyMap *, const char *, void **, int * ); static int MapGet0S( AstKeyMap *, const char *, short int *, int * ); static int MapGet1A( AstKeyMap *, const char *, int, int *, AstObject **, int * ); static int MapGet1B( AstKeyMap *, const char *, int, int *, unsigned char *, int * ); static int MapGet1C( AstKeyMap *, const char *, int, int, int *, char *, int * ); static int MapGet1D( AstKeyMap *, const char *, int, int *, double *, int * ); static int MapGet1F( AstKeyMap *, const char *, int, int *, float *, int * ); static int MapGet1I( AstKeyMap *, const char *, int, int *, int *, int * ); static int MapGet1P( AstKeyMap *, const char *, int, int *, void **, int * ); static int MapGet1S( AstKeyMap *, const char *, int, int *, short int *, int * ); static int MapGetElemA( AstKeyMap *, const char *, int, AstObject **, int * ); static int MapGetElemB( AstKeyMap *, const char *, int, unsigned char *, int * ); static int MapGetElemC( AstKeyMap *, const char *, int, int, char *, int * ); static int MapGetElemD( AstKeyMap *, const char *, int, double *, int * ); static int MapGetElemF( AstKeyMap *, const char *, int, float *, int * ); static int MapGetElemI( AstKeyMap *, const char *, int, int *, int * ); static int MapGetElemP( AstKeyMap *, const char *, int, void **, int * ); static int MapGetElemS( AstKeyMap *, const char *, int, short int *, int * ); static int ParseKey( AstTable *, const char *, int, char *, int *, AstKeyMap **, const char *, int * ); static void AddColumn( AstTable *, const char *, int, int, int *, const char *, int * ); static void AddParameter( AstTable *, const char *, int * ); static void ColumnShape( AstTable *, const char *, int, int *, int *, int *); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void MapPut0A( AstKeyMap *, const char *, AstObject *, const char *, int * ); static void MapPut0B( AstKeyMap *, const char *, unsigned char, const char *, int * ); static void MapPut0C( AstKeyMap *, const char *, const char *, const char *, int * ); static void MapPut0D( AstKeyMap *, const char *, double, const char *, int * ); static void MapPut0F( AstKeyMap *, const char *, float, const char *, int * ); static void MapPut0I( AstKeyMap *, const char *, int, const char *, int * ); static void MapPut0P( AstKeyMap *, const char *, void *, const char *, int * ); static void MapPut0S( AstKeyMap *, const char *, short int, const char *, int * ); static void MapPut1A( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * ); static void MapPut1B( AstKeyMap *, const char *, int, const unsigned char *, const char *, int * ); static void MapPut1C( AstKeyMap *, const char *, int, const char *const [], const char *, int * ); static void MapPut1D( AstKeyMap *, const char *, int, const double *, const char *, int * ); static void MapPut1F( AstKeyMap *, const char *, int, const float *, const char *, int * ); static void MapPut1I( AstKeyMap *, const char *, int, const int *, const char *, int * ); static void MapPut1P( AstKeyMap *, const char *, int, void *const [], const char *, int * ); static void MapPut1S( AstKeyMap *, const char *, int, const short int *, const char *, int * ); static void MapPutElemA( AstKeyMap *, const char *, int, AstObject *, int * ); static void MapPutElemB( AstKeyMap *, const char *, int, unsigned char, int * ); static void MapPutElemC( AstKeyMap *, const char *, int, const char *, int * ); static void MapPutElemD( AstKeyMap *, const char *, int, double, int * ); static void MapPutElemF( AstKeyMap *, const char *, int, float, int * ); static void MapPutElemI( AstKeyMap *, const char *, int, int, int * ); static void MapPutElemP( AstKeyMap *, const char *, int, void *, int * ); static void MapPutElemS( AstKeyMap *, const char *, int, short int, int * ); static void MapPutU( AstKeyMap *, const char *, const char *, int * ); static void PurgeRows( AstTable *, int * ); static void RemoveColumn( AstTable *, const char *, int * ); static void RemoveParameter( AstTable *, const char *, int * ); static void RemoveRow( AstTable *, int, int * ); static void SetKeyCase( AstKeyMap *, int, int * ); static void ClearKeyCase( AstKeyMap *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif static const char *GetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static int GetNrow( AstTable *, int * ); static void SetNrow( AstTable *, int, int * ); static int GetNcolumn( AstTable *, int * ); static int GetNparameter( AstTable *, int * ); /* Member functions. */ /* ================= */ static void AddColumn( AstTable *this, const char *name, int type, int ndim, int *dims, const char *unit, int *status ) { /* *++ * Name: c astAddColumn f AST_ADDCOLUMN * Purpose: * Add a new column definition to a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astAddColumn( AstTable *this, const char *name, int type, int ndim, c int *dims, const char *unit ) f CALL AST_ADDCOLUMN( THIS, NAME, TYPE, NDIM, DIMS, UNIT, STATUS ) * Class Membership: * Table method. * Description: * Adds the definition of a new column to the supplied table. Initially, * the column is empty. Values may be added subsequently using the * methods of the KeyMap class. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c name f NAME = CHARACTER * ( * ) (Given) * The column name. Trailing spaces are ignored (all other spaces * are significant). The supplied string is converted to upper case. c type f TYPE = INTEGER (Given) * The data type associated with the column. See "Applicability:" * below. c ndim f NDIM = INTEGER (Given) * The number of dimensions spanned by the values stored in a single * cell of the column. Zero if the column holds scalar values. c dims f DIMS( NDIM ) = INTEGER (Given) * An array holding the the lengths of each of the axes spanned by * the values stored in a single cell of the column. Ignored if the * column holds scalara values. c unit f UNIT = CHARACTER * ( * ) (Given) * A string specifying the units of the column. Supply a blank * string if the column is unitless. f STATUS = INTEGER (Given and Returned) f The global status. * Applicability: * Table * Tables can hold columns with any of the following data types - * AST__INTTYPE (for integer), AST__SINTTYPE (for c short int), f INTEGER*2), * AST__BYTETYPE (for c unsigned bytes - i.e. unsigned chars), f bytes), * AST__DOUBLETYPE (for double * precision floating point), AST__FLOATTYPE (for single * precision floating point), AST__STRINGTYPE (for character string), * AST__OBJECTTYPE (for AST Object pointer), AST__POINTERTYPE (for * arbitrary C pointer) or AST__UNDEFTYPE (for undefined values * created by c astMapPutU). f AST_MAPPUTU). * FitsTable * FitsTables can hold columns with any of the following data types - * AST__INTTYPE (for integer), AST__SINTTYPE (for c short int), f INTEGER*2), * AST__BYTETYPE (for c unsigned bytes - i.e. unsigned chars), f bytes), * AST__DOUBLETYPE (for double * precision floating point), AST__FLOATTYPE (for single * precision floating point), AST__STRINGTYPE (for character string). * Notes: * - This c function f routine * returns without action if a column already exists in the Table * with the supplied name and properties. However an error is * reported if any of the properties differ. *-- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding all column details */ AstKeyMap *col_km; /* KeyMap holding new column details */ const char *oldunit; /* Pointer to the old coumn unit string */ int *olddims; /* Shape of pre-existing column */ int idim; /* Axis index */ int namlen; /* Used length of "name" */ int nval; /* Number of values returned */ int oldtype; /* Data type of pre-existing column */ /* Check the global error status. */ if ( !astOK ) return; /* Verify supplied values. */ namlen = astChrLen( name ); if( namlen == 0 ) { astError( AST__BADKEY, "astAddColumn(%s): Illegal blank column name " "supplied.", status, astGetClass( this ) ); } else if( namlen > AST__MXCOLNAMLEN ) { astError( AST__BADKEY, "astAddColumn(%s): Column name '%s' is too " "long (must be no more than %d characters).", status, astGetClass( this ), name, AST__MXCOLNAMLEN ); } else if( ndim < 0 ) { astError( AST__NAXIN, "astAddColumn(%s): No of axes (%d) for values in " "new column %s is invalid.", status, astGetClass( this ), ndim, name ); } else if( TypeString( type ) == NULL ) { astError( AST__NAXIN, "astAddColumn(%s): Bad data type supplied (%d) " "for new column %s.", status, astGetClass( this ), type, name ); } else { for( idim = 0; idim < ndim; idim++ ) { if( dims[ idim ] < 1 ) { astError( AST__DIMIN, "astAddColumn(%s): Length of axis %d (%d) " "for new column %s is invalid.", status, astGetClass( this ), idim + 1, dims[ idim ], name ); break; } } } /* If there is already a column with the given name, check its properties match the supplied properties. */ if( astOK ) { cols = astColumnProps( this ); if( astMapGet0A( cols, name, &col_km ) ) { astMapGet0I( col_km, TYPE, &oldtype ); if( oldtype != type && astOK ) { astError( AST__OLDCOL, "astAddColumn(%s): A column called " "%s already exists in the table with a different " "data type (%s).", status, astGetClass( this ), name, TypeString( oldtype ) ); } if( !astMapGet0C( col_km, UNIT, &oldunit ) ) oldunit = ""; if( strcmp( oldunit, unit ) && astOK ) { astError( AST__OLDCOL, "astAddColumn(%s): A column called " "%s already exists in the table with a different " "unit string ('%s').", status, astGetClass( this ), name, oldunit ); } if( ndim != astMapLength( col_km, SHAPE ) && astOK ) { astError( AST__OLDCOL, "astAddColumn(%s): A column called " "%s already exists in the table with a different " "number of axes (%d).", status, astGetClass( this ), name, astMapLength( col_km, SHAPE ) ); } if( ndim > 0 && astOK ) { olddims = astMalloc( sizeof( int )*ndim ); (void) astMapGet1I( col_km, SHAPE, ndim, &nval, olddims ); for( idim = 0; idim < ndim && astOK; idim++ ) { if( dims[ idim ] != olddims[ idim ] ) { astError( AST__OLDCOL, "astAddColumn(%s): A column called " "%s already exists in the table with a different " "shape.", status, astGetClass( this ), name ); } } olddims = astFree( olddims ); } /* Otherwise, add a new column to the table. */ } else { /* Add a suitable entry describing the column to the Columns KeyMap. */ col_km = astKeyMap( " ", status ); astMapPut0C( col_km, NAME, name, NULL ); astMapPut0I( col_km, TYPE, type, NULL ); if( ndim ) astMapPut1I( col_km, SHAPE, ndim, dims, NULL ); astMapPut0C( col_km, UNIT, unit, NULL ); /* Put the column KeyMap into the KeyMap holding details of all columns. Use the column name as the key. */ astMapPut0A( cols, name, col_km, NULL ); } /* Annul the local KeyMap pointers. */ col_km = astAnnul( col_km ); cols = astAnnul( cols ); } } static void AddParameter( AstTable *this, const char *name, int *status ) { /* *++ * Name: c astAddParameter f AST_ADDPARAMETER * Purpose: * Add a new global parameter definition to a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astAddParameter( AstTable *this, const char *name ) f CALL AST_ADDPARAMETER( THIS, NAME, STATUS ) * Class Membership: * Table method. * Description: * Adds the definition of a new global parameter to the supplied * table. Note, this does not store a value for the parameter. To get * or set the parameter value, the methods of the paremt KeyMap class * should be used, using the name of the parameter as the key. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c name f NAME = CHARACTER * ( * ) (Given) * The parameter name. Trailing spaces are ignored (all other spaces * are significant). The supplied string is converted to upper case. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Unlike columns, the definition of a parameter does not specify its type, * size or dimensionality. *-- */ /* Local Variables: */ AstKeyMap *pars; /* KeyMap holding all parameter details */ int namlen; /* Used length of "name" */ /* Check the global error status. */ if ( !astOK ) return; /* Verify supplied values. */ namlen = astChrLen( name ); if( namlen == 0 ) { astError( AST__BADKEY, "astAddParameter(%s): Illegal blank parameter name " "supplied.", status, astGetClass( this ) ); } else if( namlen > AST__MXCOLNAMLEN ) { astError( AST__BADKEY, "astAddParameter(%s): Parameter name '%s' is too " "long (must be no more than %d characters).", status, astGetClass( this ), name, AST__MXCOLNAMLEN ); } /* Do nothing if there is already a parameter with the given name. */ if( astOK ) { pars = astParameterProps( this ); if( !astMapHasKey( pars, name ) ) { /* Add a suitable entry to the Parameters KeyMap. The value is arbitrary and currently unused. */ astMapPut0I( pars, name, 1, NULL ); } /* Annul the local KeyMap pointer. */ pars = astAnnul( pars ); } } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void ClearAttrib( AstObject *this, const char *attrib ) * Class Membership: * Table member function (over-rides the astClearAttrib protected * method inherited from the KeyMap class). * Description: * This function clears the value of a specified attribute for a * Table, so that the default value will subsequently be used. * Parameters: * this * Pointer to the Table. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. */ /* Local Variables: */ AstTable *this; int nc; int len; /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Table structure. */ this = (AstTable *) this_object; /* Get the length of the attribute string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* None yet */ /* Define a macro to see if the attribute string matches any of the read-only column attributes of this class. */ #define MATCH(attr) \ ( nc = 0, ( 0 == astSscanf( attrib, attr "(%*s)%n", &nc ) ) && \ ( nc >= len ) ) /* If the name was not recognised, test if it matches any of the read-only attributes of this class. If it does, then report an error. */ if ( !strcmp( attrib, "nrow" ) || !strcmp( attrib, "ncolumn" ) || !strcmp( attrib, "nparameter" ) || MATCH( "columnlenc" ) || MATCH( "columnlength" ) || MATCH( "columnndim" ) || MATCH( "columntype" ) || MATCH( "columnunit" ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } #undef MATCH } static void ClearKeyCase( AstKeyMap *this, int *status ) { /* * Name: * ClearKeyCase * Purpose: * Clear the KeyCase attribute value for a Table. * Type: * Private function. * Synopsis: * #include "keymape.h" * void ClearKeyCase( AstKeyMap *this, int *status ) * Class Membership: * Table member function (over-rides the astClearKeyCase protected * method inherited from the KeyMap class). * Description: * This function clears the value of the KeyCase attribute for a * Table. For a Table, the KeyCase attribute cannot be changed so this * function exits without action. * Parameters: * this * Pointer to the Table. */ } static const char *ColumnName( AstTable *this, int index, int *status ) { /* *++ * Name: c astColumnName f AST_COLUMNNAME * Purpose: * Get the name of the column at a given index within the Table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c const char *astColumnName( AstTable *this, int index ) f RESULT = AST_COLUMNNAME( THIS, INDEX, STATUS ) * Class Membership: * Table method. * Description: * This function returns a string holding the name of the column with * the given index within the Table. * * This function is intended primarily as a means of iterating round all * the columns in a Table. For this purpose, the number of columns in * the Table is given by the Ncolumn attribute of the Table. This function * could then be called in a loop, with the index value going from c zero to one less than Ncolumn. f one to Ncolumn. * * Note, the index associated with a column decreases monotonically with * the age of the column: the oldest Column in the Table will have index * one, and the Column added most recently to the Table will have the * largest index. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c index f INDEX = INTEGER (Given) * The index into the list of columns. The first column has index * one, and the last has index "Ncolumn". f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astColumnName() c A pointer to a null-terminated string containing the f AST_COLUMNNAME = CHARACTER * ( AST__SZCHR ) f The * upper case column name. * Notes: c - The returned pointer is guaranteed to remain valid and the c string to which it points will not be over-written for a total c of 50 successive invocations of this function. After this, the c memory containing the string may be re-used, so a copy of the c string should be made if it is needed for longer than this. c - A NULL pointer will be returned if this function is invoked c with the AST error status set, or if it should fail for any c reason. f - A blank string will be returned if this function is invoked f with STATUS set to an error value, or if it should fail for any f reason. *-- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ const char *result; /* Check the global error status. */ if ( !astOK ) return NULL; /* Get apointer to the KeyMap holding all column definitions. */ cols = astColumnProps( this ); /* Issue a more useful error message than that issued by astMapKey if the index is invalid. */ if( index < 1 || index > astMapSize( cols ) ) { astError( AST__MPIND, "astColumnName(%s): Cannot find column " "%d (zero-based) of the %s - invalid index.", status, astGetClass( this ), index, astGetClass( this ) ); } /* Get the column name. */ result = astMapKey( cols, index - 1 ); /* Free resources. */ cols = astAnnul( cols ); /* Return a pointer to the required column name. */ return result; } static AstKeyMap *ColumnProps( AstTable *this, int *status ) { /* *+ * Name: * astColumnProps * Purpose: * Returns a pointer to the KeyMap holding column properties. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * AstKeyMap *astColumnProps( AstTable *this ) * Class Membership: * Table method. * Description: * This function returns a pointer to the KeyMap that holds * definitions of all the coumns added to the Table. * Parameters: * this * Pointer to the Table. * Returned Value: * A pointer to the KeyMap. It shpould be annulled using astAnnul * when no longer needed. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return a cloned pointer to the required KeyMap. */ return astClone( this->columns ); } static void ColumnShape( AstTable *this, const char *column, int mxdim, int *ndim, int *dims, int *status ){ /* *++ * Name: c astColumnShape f AST_COLUMNSHAPE * Purpose: * Returns the shape of the values in a named column. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astColumnShape( AstTable *this, const char *column, int mxdim, c int *ndim, int *dims ) f CALL AST_COLUMNSHAPE( THIS, COLUMN, MXDIM, NDIM, DIMS, STATUS ) * Class Membership: * Table method. * Description: c This function f This routine * returns the number of dimensions spaned by each value in a named * column of a Table, together with the length of each dimension. * These are the values supplied when the column was created using c astAddColumn. f AST_ADDCOLUMN. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c column f COLUMN = CHARACTER * ( * ) (Given) * The character string holding the upper case name of the column. Trailing * spaces are ignored. c mxdim f MXDIM = INTEGER (Given) * The length of the c "dims" array. f DIMS array. c ndim f NDIM = INTEGER (Returned) c Pointer to an int in which to return the f The * number of dimensions spanned by values in the named column. * This will be zero if the column contains scalar values. c dims f DIMS( MXDIM ) = INTEGER (Returned) c Pointer to an f An * array in which to return the length of each dimension. Any * excess trailing elements will be filled with the value 1. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - No error is reported if the requested column cannot be found in the * given Table. A value of zero is returned for c "ndim" and the supplied values in "dims" f NDIM and the supplied values in DIMS * are left unchanged. * - A value of zero is returned for c "ndim" f NDIM * if an error occurs. *-- */ /* Local Variables: */ AstKeyMap *cols; /* Pointer to KeyMap holding all column info */ AstKeyMap *col_km; /* Pointer to KeyMap holding requested column info */ int idim; /* Axis index */ /* Initialise */ *ndim = 0; /* Check the inherited status. */ if( !astOK ) return; /* Get the KeyMap holding information about the requested column. */ cols = astColumnProps( this ); if( astMapGet0A( cols, column, &col_km ) ) { /* Get the shape of the column values. */ (void) astMapGet1I( col_km, SHAPE, mxdim, ndim, dims ); /* Fill excess array elements with 1. */ for( idim = *ndim; idim < mxdim; idim++ ) dims[ idim ] = 1; /* Free resources. */ col_km = astAnnul( col_km ); } cols = astAnnul( cols ); /* If an error has occurred, set ndim to zero. */ if( !astOK ) *ndim = 0; } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two Tables are equivalent. * Type: * Private function. * Synopsis: * #include "table.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * Table member function (over-rides the astEqual protected * method inherited from the astKeyMap class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two Tables are equivalent. * Parameters: * this * Pointer to the first Object (a Table). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the Tables are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstKeyMap *this_km; AstKeyMap *that_km; AstTable *that; AstTable *this; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two Table structures. */ this = (AstTable *) this_object; that = (AstTable *) that_object; /* Check the second object is a Table. We know the first is a Table since we have arrived at this implementation of the virtual function. */ if( astIsATable( that ) ) { /* Check the Tables are equal when compared as KeyMaps. */ if( (*parent_equal)( this_object, that_object, status ) ) { /* Check the Columns KeyMaps are equal. */ this_km = astColumnProps( this ); that_km = astColumnProps( that ); result = astEqual( this_km, that_km ); this_km = astAnnul( this_km ); that_km = astAnnul( that_km ); /* Check the Parameter KeyMaps are equal. */ this_km = astParameterProps( this ); that_km = astParameterProps( that ); result = astEqual( this_km, that_km ); this_km = astAnnul( this_km ); that_km = astAnnul( that_km ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a Table. * Type: * Private function. * Synopsis: * #include "table.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Table member function (over-rides the protected astGetAttrib * method inherited from the KeyMap class). * Description: * This function returns a pointer to the value of a specified * attribute for a Table, formatted as a character string. * Parameters: * this * Pointer to the Table. * attrib * Pointer to a null terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the Table, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Table. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char cname[ AST__MXCOLNAMLEN + 1 ]; /* Column name */ AstTable *this; /* Pointer to the Table structure */ const char *result; /* Pointer value to return */ int ival; /* Int attribute value */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the Table structure. */ this = (AstTable *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null terminated string in an appropriate format. Set "result" to point at the result string. */ /* Table properties */ /* ================ */ /* Ncolumn */ /* ------- */ if( !strcmp( attrib, "ncolumn" ) ) { ival = astGetNcolumn( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nrow */ /* ---- */ } else if( !strcmp( attrib, "nrow" ) ) { ival = astGetNrow( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nparameter */ /* ---------- */ } else if( !strcmp( attrib, "nparameter" ) ) { ival = astGetNparameter( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Column properties */ /* ================= */ /* A macro that gives the scannf pattern to test for a given column property. Needed since the buffer length is defined by a macro (AST__MXCOLNAMLEN). */ #define PATTERN(cnam,blen) #cnam "(%" STRING(blen) "[^()])%n" /* ColumnNdim */ } else if ( nc = 0, ( 1 == astSscanf( attrib, PATTERN(columnndim,AST__MXCOLNAMLEN), cname, &nc ) ) && ( nc >= len ) ) { ival = astGetColumnNdim( this, cname ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ColumnLenC */ } else if ( nc = 0, ( 1 == astSscanf( attrib, PATTERN(columnlenc,AST__MXCOLNAMLEN), cname, &nc ) ) && ( nc >= len ) ) { ival = astGetColumnLenC( this, cname ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ColumnType */ } else if ( nc = 0, ( 1 == astSscanf( attrib, PATTERN(columntype,AST__MXCOLNAMLEN), cname, &nc ) ) && ( nc >= len ) ) { ival = astGetColumnType( this, cname ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ColumnLength */ } else if ( nc = 0, ( 1 == astSscanf( attrib, PATTERN(columnlength,AST__MXCOLNAMLEN), cname, &nc ) ) && ( nc >= len ) ) { ival = astGetColumnLength( this, cname ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* ColumnUnit */ } else if ( nc = 0, ( 1 == astSscanf( attrib, PATTERN(columnunit,AST__MXCOLNAMLEN), cname, &nc ) ) && ( nc >= len ) ) { result = astGetColumnUnit( this, cname ); #undef PATTERN /* Unknown attributes */ /* ================== */ /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static int GetColumnLenC( AstTable *this, const char *column, int *status ) { /* *+ * Name: * astGetColumnLenC * Purpose: * Get the maximum formatted length of any value in a column. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetColumnLenC( AstTable *this, const char *column ) * Class Membership: * Table method. * Description: * This function returns the minimum length which a character variable * must have in order to be able to store the longest value currently * present (at any row) in a specified column of the supplied Table. If * the named column holds vector values, then the returned value is * the length of the longest element of the vector value. * Parameters: * this * Pointer to the Table. * column * The character string holding the upper-case name of the column. * Trailing spaces are ignored. An error is reported if the supplied * column is not found in the Table. * Returned Value: * The length (i.e. number of characters) of the longest formatted * value associated with the named column. This does not include the * trailing null character. * Notes: * - Automatic data type conversion occurs if the named column holds * numerical values. * - An error will be reported if named column does not exist or cannot * be formatted as a character * string. * - A function value of zero will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ char key[ AST__MXCOLKEYLEN ]; /* Current cell key string */ int irow; /* Current row index */ int len; /* Length needed to format current cell */ int nrow; /* Number of rows in table */ int result; /* Returned value */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get the KeyMap holding information about all columns. */ cols = astColumnProps( this ); /* Check the table contains the requested column. */ if( astMapHasKey( cols, column ) ) { /* Loop round all rows in the table. */ nrow = astGetNrow( this ); for( irow = 1; irow <= nrow; irow++ ) { /* Format the cell name. */ sprintf( key, "%.*s(%d)", (int) astChrLen(column), column, irow ); /* Get the maximum length needed to format a string in the current row/column. */ len = astMapLenC( this, key ); /* Return the largest value found for any row. */ if( len > result ) result = len; } /* Report an error if the column does not exist. */ } else if( astOK ) { astError( AST__BADCOL, "astGetColumnLenC(%s): No column named '%s' " "exists in the table.", status, astGetClass( this ), column ); } /* Free resources */ cols = astAnnul( cols ); /* Return AST__BADTYPE if an error occurred. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static int GetColumnLength( AstTable *this, const char *column, int *status ) { /* *+ * Name: * astGetColumnLength * Purpose: * Get the number of elements in each value in a column. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetColumnLength( AstTable *this, const char *column ) * Class Membership: * Table method. * Description: * This function returns the number of elements in each value stored * in a named column. Each value can be a scalar (in which case the * ColumnLength attribute has a value of 1), or a multi-dimensional * array ( in which case the ColumnLength value is equal to the * product of the array dimensions). * Parameters: * this * Pointer to the Table. * column * The character string holding the upper-case name of the column. * Trailing spaces are ignored. An error is reported if the supplied * column is not found in the Table. * Returned Value: * The number of elements in each column value. * Notes: * - An error will be reported if named column does not exist or cannot * be formatted as a character * string. * - A function value of zero will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ AstKeyMap *col_km; /* KeyMap holding requested column definition */ AstKeyMap *cols; /* KeyMap holding all column definitions */ int *dims; /* Pointer to array holding dimensions */ int idim; /* Index of dimension */ int ndim; /* Number of dimensions */ int result; /* Returned value */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get the KeyMap holding information about all columns. */ cols = astColumnProps( this ); /* Get the KeyMap holding information about the requested column. */ if( astMapGet0A( cols, column, &col_km ) ) { /* If the Column properties includes the length, return it. Otherwise, calculate the length and store it in the KeyMap as a column property. */ if( ! astMapGet0I( col_km, LENGTH, &result ) ) { /* Get the number of axes spanned by each column value, and allocate an array big enough to hold the dimensions of these axes. */ ndim = astMapLength( col_km, SHAPE ); dims = astMalloc( sizeof( int )*ndim ); if( astOK ) { /* Get the dimensions. */ astMapGet1I( col_km, SHAPE, ndim, &ndim, dims ); /* Find the number of elements. */ result = 1; for( idim = 0; idim < ndim; idim++ ) { result *= dims[ idim ]; } /* Store the result in the column KeyMap. */ astMapPut0I( col_km, LENGTH, result, NULL ); } dims = astFree( dims ); } /* Free resources */ col_km = astAnnul( col_km ); /* Report an error if the column does not exist. */ } else if( astOK ) { astError( AST__BADCOL, "astGetColumnLength(%s): No column named '%s' " "exists in the table.", status, astGetClass( this ), column ); } /* Free resources */ cols = astAnnul( cols ); /* Return AST__BADTYPE if an error occurred. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static int GetColumnNdim( AstTable *this, const char *column, int *status ) { /* *+ * Name: * astGetColumnNdim * Purpose: * Get the number of dimensions for a column in a Table. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetColumnNdim( AstTable *this, const char *column ) * Class Membership: * Table method. * Description: * This function attribute holds the number of axes spanned by each value * in a column. If each cell in the column is a scalar, ColumnNdim will * be zero. If each cell in the column is a 1D spectrum, ColumnNdim will * be one. If each cell in the column is a 2D image, ColumnNdim will be * two, etc. * Parameters: * this * Pointer to the Table. * column * The character string holding the upper-case name of the column. * Trailing spaces are ignored. An error is reported if the supplied * column is not found in the Table. * Returned Value: * The number of dimensions - zero for a scalar. * Notes: * - A function value of zero will be returned if an error has * already occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ AstKeyMap *col_km; /* Pointer to KeyMap holding column info */ int result; /* Returned value */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get the KeyMap holding information about all columns. */ cols = astColumnProps( this ); /* Get the KeyMap holding information about the requested column. */ if( astMapGet0A( cols, column, &col_km ) ) { /* Get the number of dimensions. */ result = astMapLength( col_km, SHAPE ); /* Free resources */ col_km = astAnnul( col_km ); /* Report an error if the column does not exist. */ } else if( astOK ) { astError( AST__BADCOL, "astGetColumnNdim(%s): No column named '%s' " "exists in the table.", status, astGetClass( this ), column ); } cols = astAnnul( cols ); /* Return AST__BADTYPE if an error occurred. */ if( !astOK ) result = 0; /* Return the result. */ return result; } static int GetColumnType( AstTable *this, const char *column, int *status ) { /* *+ * Name: * astGetColumnType * Purpose: * Get the data type of a column in a Table. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetColumnType( AstTable *this, const char *column ) * Class Membership: * Table method. * Description: * This function returns a value indicating the data type of a * named column in a Table. This is the data type which was used * when the column was added to the Table using astAddColumn. * Parameters: * this * Pointer to the Table. * column * The character string holding the upper-case name of the column. * Trailing spaces are ignored. An error is reported if the supplied * column is not found in the Table. * Returned Value: * One of AST__INTTYPE (for integer), AST__SINTTYPE (for short int), * AST__BYTETYPE (for unsigned bytes - i.e. unsigned chars), * AST__DOUBLETYPE (for double precision floating point), * AST__FLOATTYPE (for single precision floating point), AST__STRINGTYPE * (for character string), AST__OBJECTTYPE (for AST Object pointer), * AST__POINTERTYPE (for arbitrary C pointer) or AST__UNDEFTYPE (for * undefined values created by astMapPutU). * Notes: * - A function value of AST__BADTYPE will be returned if an error has * already occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ AstKeyMap *cols; /* Pointer to KeyMap holding all column info */ AstKeyMap *col_km; /* Pointer to KeyMap holding requested column info */ int result; /* Returned value */ /* Initialise */ result = AST__BADTYPE; /* Check the global error status. */ if ( !astOK ) return result; /* Get the KeyMap holding information about the requested column. */ cols = astColumnProps( this ); if( astMapGet0A( cols, column, &col_km ) ) { /* Get the column data type. */ (void) astMapGet0I( col_km, TYPE, &result ); /* Annul the KeyMap pointer. */ col_km = astAnnul( col_km ); /* Report an error if the column does not exist. */ } else if( astOK ) { astError( AST__BADCOL, "astGetColumnType(%s): No column named '%s' " "exists in the table.", status, astGetClass( this ), column ); } cols = astAnnul( cols ); /* Return AST__BADTYPE if an error occurred. */ if( !astOK ) result = AST__BADTYPE; /* Return the result. */ return result; } static const char *GetColumnUnit( AstTable *this, const char *column, int *status ) { /* *+ * Name: * astGetColumnUnit * Purpose: * Get the unit string for a column in a Table. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * const char *astGetColumnUnit( AstTable *this, const char *column ) * Class Membership: * Table method. * Description: * This function returns the unit string for a named column in a Table. * This is the unit string that was provided when the column was added to * the Table using astAddColumn. * Parameters: * this * Pointer to the Table. * column * The character string holding the upper-case name of the column. * Trailing spaces are ignored. An error is reported if the supplied * column is not found in the Table. * Returned Value: * A pointer to a null-terminated string containing the column units. *- */ /* Local Variables: */ AstKeyMap *col_km; /* Pointer to KeyMap holding requested column info */ AstKeyMap *cols; /* Pointer to KeyMap holding all column info */ const char *result; /* Returned value */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get the KeyMap holding information about the requested column. */ cols = astColumnProps( this ); if( astMapGet0A( cols, column, &col_km ) ) { /* Get the column unit string. */ (void) astMapGet0C( col_km, UNIT, &result ); /* Annul the KeyMap pointer. */ col_km = astAnnul( col_km ); /* Report an error if the column does not exist. */ } else if( astOK ) { astError( AST__BADCOL, "astGetColumnUnit(%s): No column named '%s' " "exists in the table.", status, astGetClass( this ), column ); } cols = astAnnul( cols ); /* Return NULL if an error occurred. */ if( !astOK ) result = NULL; /* Return the result. */ return result; } static int GetNcolumn( AstTable *this, int *status ) { /* *+ * Name: * astGetNcolumn * Purpose: * Get the number of columns in a Table. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetNcolumn( AstTable *this ) * Class Membership: * Table method. * Description: * This function returns the number of columns currently in the Table. * Parameters: * this * Pointer to the Table. * Returned Value: * Number of columns. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstKeyMap *cols; int result; /* Check the global error status. */ if ( !astOK ) return 0; /* Get a pointer to the KeyMap holding the column definitions. */ cols = astColumnProps( this ); /* Get the number of column definitions in the KeyMap. */ result = astMapSize( cols ); /* Annul the KeyMap pointer. */ cols = astAnnul( cols ); /* Return the result. */ return result; } static int GetNparameter( AstTable *this, int *status ) { /* *+ * Name: * astGetNparameter * Purpose: * Get the number of global parameters in a Table. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * int astGetNparameter( AstTable *this ) * Class Membership: * Table method. * Description: * This function returns the number of global parameters currently in the Table. * Parameters: * this * Pointer to the Table. * Returned Value: * Number of parameters. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstKeyMap *pars; int result; /* Check the global error status. */ if ( !astOK ) return 0; /* Get a pointer to the KeyMap holding the parameter definitions. */ pars = astParameterProps( this ); /* Get the number of parameter definitions in the KeyMap. */ result = astMapSize( pars ); /* Annul the KeyMap pointer. */ pars = astAnnul( pars ); /* Return the result. */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "table.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * Table member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied Tables, * in bytes. * Parameters: * this * Pointer to the Table. * status * Pointer to the inherited status variable. * Returned Value: * The Table size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstKeyMap *km; /* KeyMap holding column/parameter definitions */ AstTable *this; /* Pointer to Table structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the Table structure. */ this = (AstTable *) this_object; /* Invoke the GetObjSize method inherited from the parent KeyMap class, and then add on any components of the class structure defined by this class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); km = astColumnProps( this ); result += astGetObjSize( km ); km = astAnnul( km ); km = astParameterProps( this ); result += astGetObjSize( km ); km = astAnnul( km ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int HasColumn( AstTable *this, const char *column, int *status ){ /* *++ * Name: c astHasColumn f AST_HASCOLUMN * Purpose: * Returns a flag indicating if a column is present in a Table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c int astHasColumn( AstTable *this, const char *column ) f RESULT = AST_HASCOLUMN( THIS, COLUMN, STATUS ) * Class Membership: * Table method. * Description: c This function f This routine * returns a flag indicating if a named column exists in a Table, for * instance, by having been added to to the Table using c astAddColumn. f AST_ADDCOLUMN. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c column f COLUMN = CHARACTER * ( * ) (Given) * The character string holding the upper case name of the column. Trailing * spaces are ignored. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - A value of c zero f .FALSE. * is returned for if an error occurs. *-- */ /* Local Variables: */ AstKeyMap *cols; int result; /* Initialise */ result = 0; /* Check the inherited status. */ if( !astOK ) return result; /* Get the KeyMap holding information about all columns. */ cols = astColumnProps( this ); /* Seeif it contains an entry for the named column. */ result = astMapHasKey( cols, column ); /* Free resources. */ cols = astAnnul( cols ); /* If an error has occurred, return zero. */ if( !astOK ) result = 0; return result; } static int HasParameter( AstTable *this, const char *parameter, int *status ){ /* *++ * Name: c astHasParameter f AST_HASPARAMETER * Purpose: * Returns a flag indicating if a named global parameter is present in a Table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c int astHasParameter( AstTable *this, const char *parameter ) f RESULT = AST_HASPARAMETER( THIS, PARAMETER, STATUS ) * Class Membership: * Table method. * Description: c This function f This routine * returns a flag indicating if a named parameter exists in a Table, for * instance, by having been added to to the Table using c astAddParameter. f AST_ADDPARAMETER. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c parameter f PARAMETER = CHARACTER * ( * ) (Given) * The character string holding the upper case name of the parameter. Trailing * spaces are ignored. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - A value of c zero f .FALSE. * is returned for if an error occurs. *-- */ /* Local Variables: */ AstKeyMap *pars; int result; /* Initialise */ result = 0; /* Check the inherited status. */ if( !astOK ) return result; /* Get the KeyMap holding information about all parameters. */ pars = astParameterProps( this ); /* See if it contains an entry for the named parameter. */ result = astMapHasKey( pars, parameter ); /* Free resources. */ pars = astAnnul( pars ); /* If an error has occurred, return zero. */ if( !astOK ) result = 0; return result; } void astInitTableVtab_( AstTableVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitTableVtab * Purpose: * Initialise a virtual function table for a Table. * Type: * Protected function. * Synopsis: * #include "table.h" * void astInitTableVtab( AstTableVtab *vtab, const char *name ) * Class Membership: * Table vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Table class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstKeyMapVtab *keymap; /* Pointer to KeyMap component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitKeyMapVtab( (AstKeyMapVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsATable) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstKeyMapVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->AddColumn = AddColumn; vtab->AddParameter = AddParameter; vtab->ColumnName = ColumnName; vtab->ParameterName = ParameterName; vtab->ColumnProps = ColumnProps; vtab->ColumnShape = ColumnShape; vtab->GetColumnLenC = GetColumnLenC; vtab->GetColumnLength = GetColumnLength; vtab->GetColumnNdim = GetColumnNdim; vtab->GetColumnType = GetColumnType; vtab->GetColumnUnit = GetColumnUnit; vtab->GetNcolumn = GetNcolumn; vtab->GetNparameter = GetNparameter; vtab->GetNrow = GetNrow; vtab->HasColumn = HasColumn; vtab->HasParameter = HasParameter; vtab->ParameterProps = ParameterProps; vtab->PurgeRows = PurgeRows; vtab->RemoveColumn = RemoveColumn; vtab->RemoveParameter = RemoveParameter; vtab->RemoveRow = RemoveRow; vtab->SetNrow = SetNrow; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; keymap = (AstKeyMapVtab *) vtab; parent_equal = object->Equal; object->Equal = Equal; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_mapremove = keymap->MapRemove; /* Define convenience macros for overriding methods inherited from the parent KeyMap class using all data type supported by KeyMap. */ #define OVERRIDE(method,code,methodlc,codelc) \ parent_##methodlc##codelc = keymap->method##code; \ keymap->method##code = method##code; \ #define OVERRIDE_METHOD(method,methodlc) \ OVERRIDE(method,A,methodlc,a) \ OVERRIDE(method,P,methodlc,p) \ OVERRIDE(method,C,methodlc,c) \ OVERRIDE(method,D,methodlc,d) \ OVERRIDE(method,F,methodlc,f) \ OVERRIDE(method,I,methodlc,i) \ OVERRIDE(method,S,methodlc,s) \ OVERRIDE(method,B,methodlc,b) /* Use these macros to override the required methods. */ OVERRIDE_METHOD(MapPut0,mapput0) OVERRIDE_METHOD(MapGet0,mapget0) OVERRIDE_METHOD(MapPut1,mapput1) OVERRIDE_METHOD(MapGet1,mapget1) OVERRIDE_METHOD(MapPutElem,mapputelem) OVERRIDE_METHOD(MapGetElem,mapgetelem) OVERRIDE(MapPut,U,mapput,u) OVERRIDE(SetKeyCase,,setkeycase,) OVERRIDE(ClearKeyCase,,clearkeycase,) /* Remove the macros. */ #undef OVERRIDE_METHOD #undef OVERRIDE /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "Table", "Two-dimensional table of data values" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * Table member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstTable *this; /* Pointer to Table structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the Table structure. */ this = (AstTable *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result && this->columns ) result = astManageLock( this->columns, mode, extra, fail ); if( !result && this->parameters ) result = astManageLock( this->parameters, mode, extra, fail ); /* Return the result. */ return result; } #endif /* * Name: * MapGet0 * Purpose: * Get a scalar value from a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int MapGet0( AstKeyMap *this, const char *key, type *value ); * Class Membership: * Table member function (over-rides the astMapGet0 method inherited * from the KeyMap class). * Description: * This is a set of functions for retrieving a scalar value from a * cell of a Table. You should replace in the generic function name * MapGet0 by an appropriate 1-character type code (see the "Data * Type Codes" section in the astMapGet0 docs). The stored value is * converted to the data type indiced by before being returned (an * error is reported if it is not possible to convert the stored value * to the requested data type). * Parameters: * this * Pointer to the Table. * key * A character string identifying the cell from which the value is * to be retrieved. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * value * A pointer to a buffer in which to return the requested value. * If the requested cell is not found, or if it is found but has an * undefined value (see astMapPutU), then the contents of the buffer * on entry to this function will be unchanged on exit. For pointer * types ("A" and "C"), the buffer should be a suitable pointer, and * the address of this pointer should be supplied as the "value" * parameter. * status * Pointer to inherited status value. * Returned Value: * A non-zero value is returned if the requested key name was found, and * does not have an undefined value (see astMapPutU). Zero is returned * otherwise. * Notes: * - No error is reported if the requested cell cannot be found in the * given KeyMap, but a zero value will be returned as the function value. * The supplied buffer will be returned unchanged. * - Key names are case insensitive, and white space is considered * significant. * - If the stored value is a vector value, then the first value in * the vector will be returned. * - A string pointer returned by astMapGet0C is guaranteed to remain * valid and the string to which it points will not be over-written for * a total of 50 successive invocations of this function. After this, * the memory containing the string may be re-used, so a copy of * the string should be made if it is needed for longer than this. * - If the returned value is an AST Object pointer, the Object's reference * count is incremented by this call. Any subsequent changes made to * the Object using the returned pointer will be reflected in any * any other active pointers for the Object. The returned pointer * should be annulled using astAnnul when it is no longer needed. */ /* Define a macro to implement the function for a specific data type. */ #define MAKE_MAPGET0(X,Xlc,Xtype,Itype) \ static int MapGet0##X( AstKeyMap *this_keymap, const char *key, Xtype *value, \ int *status ) { \ \ /* Local Variables: */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ int result; /* Returned flag */ \ \ /* Initialise */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to get the value of hte parameter. */ \ if( astHasParameter( this, key ) ) { \ result = (*parent_mapget0##Xlc)( this_keymap, key, value, status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, astGetKeyError( this ), colname, &irow, \ NULL, "astMapGet0" #X, status ) ) { \ \ /* If the row index is larger than the current number of rows in the \ table, do nothing more. */ \ if( irow <= astGetNrow( this ) ){ \ \ /* Use the astMapGet0 method in the parent keyMap class to get the \ cell contents. */ \ result = (*parent_mapget0##Xlc)( this_keymap, key, value, status ); \ } \ } \ \ /* If an error occurred, return zero. */ \ if( !astOK ) result = 0; \ \ /* Return the result.*/ \ return result; \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPGET0(I,i,int,AST__INTTYPE) MAKE_MAPGET0(D,d,double,AST__DOUBLETYPE) MAKE_MAPGET0(F,f,float,AST__FLOATTYPE) MAKE_MAPGET0(C,c,const char *,AST__STRINGTYPE) MAKE_MAPGET0(A,a,AstObject *,AST__OBJECTTYPE) MAKE_MAPGET0(P,p,void *,AST__POINTERTYPE) MAKE_MAPGET0(S,s,short int,AST__SINTTYPE) MAKE_MAPGET0(B,b,unsigned char,AST__BYTETYPE) /* Undefine the macro. */ #undef MAKE_MAPGET0 /* * Name: * MapGet1 * Purpose: * Get a vector value from a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int MapGet1( AstKeyMap *this, const char *key, int mxval, * int *nval, type *value ) * int MapGet1C( AstKeyMap *this, const char *key, int l, int mxval, * int *nval, const char *value ) * Class Membership: * Table member function (over-rides the astMapGet1 method inherited * from the KeyMap class). * Description: * This is a set of functions for retrieving a vector value from a * cell of a Table. You should replace in the generic function name * MapGet1 by an appropriate 1-character type code (see the "Data * Type Codes" section in the astMapGet1 docs). The stored value is * converted to the data type indiced by before being returned (an * error is reported if it is not possible to convert the stored value * to the requested data type). * * Note, the MapGet1C function has an extra parameter "l" which * specifies the maximum length of each string to be stored in the * "value" buffer (see the "astMapGet1C" docs). * Parameters: * this * Pointer to the Table. * key * A character string identifying the cell from which the value is * to be retrieved. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * mxval * The number of elements in the "value" array. * nval * The address of an integer in which to put the number of elements * stored in the "value" array. Any unused elements of the array are * left unchanged. * value * A pointer to an array in which to return the requested values. * If the requested cell is not found, or if it is found but has an * undefined value (see astMapPutU), then the contents of the buffer * on entry to this function will be unchanged on exit. * status * Pointer to inherited status value. * Returned Value: * A non-zero value is returned if the requested key name was found, and * does not have an undefined value (see astMapPutU). Zero is returned * otherwise. * MapGet1C: * The "value" buffer supplied to the MapGet1C function should be a * pointer to a character array with "mxval*l" elements, where "l" is * the maximum length of a string to be returned. The value of "l" * should be supplied as an extra parameter following "key" when * invoking MapGet1C, and should include space for a terminating * null character. * Notes: * - No error is reported if the requested cell cannot be found in the * given KeyMap, but a zero value will be returned as the function value. * The supplied buffer will be returned unchanged. * - Key names are case insensitive, and white space is considered * significant. * - If the stored value is a scalar value, then the value will be * returned in the first element of the supplied array, and "nval" * will be returned set to 1. */ /* Define a macro to implement the function for a specific data type (excluding "C" since that needs an extra parameter). */ #define MAKE_MAPGET1(X,Xlc,Xtype,Itype) \ static int MapGet1##X( AstKeyMap *this_keymap, const char *key, int mxval, int *nval, \ Xtype *value, int *status ) { \ \ /* Local Variables: */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ int result; /* Returned flag */ \ \ /* Initialise */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to get the value of hte parameter. */ \ if( astHasParameter( this, key ) ) { \ result = (*parent_mapget1##Xlc)( this_keymap, key, mxval, nval, \ value, status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, astGetKeyError( this ), colname, &irow, \ NULL, "astMapGet1" #X, status ) ) { \ \ /* If the row index is larger than the current number of rows in the \ table, do nothing more. */ \ if( irow <= astGetNrow( this ) ){ \ \ /* Use the astMapGet1 method in the parent keyMap class to get the \ cell contents. */ \ result = (*parent_mapget1##Xlc)( this_keymap, key, mxval, nval, \ value, status ); \ } \ } \ \ /* If an error occurred, return zero. */ \ if( !astOK ) result = 0; \ \ /* Return the result.*/ \ return result; \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPGET1(I,i,int,AST__INTTYPE) MAKE_MAPGET1(D,d,double,AST__DOUBLETYPE) MAKE_MAPGET1(F,f,float,AST__FLOATTYPE) MAKE_MAPGET1(A,a,AstObject *,AST__OBJECTTYPE) MAKE_MAPGET1(P,p,void *,AST__POINTERTYPE) MAKE_MAPGET1(S,s,short int,AST__SINTTYPE) MAKE_MAPGET1(B,b,unsigned char,AST__BYTETYPE) /* Undefine the macro. */ #undef MAKE_MAPGET1 static int MapGet1C( AstKeyMap *this_keymap, const char *key, int l, int mxval, int *nval, char *value, int *status ) { /* * Name: * MapGet1C * Purpose: * Get a vector value from a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int MapGet1C( AstKeyMap *this, const char *key, int l, int mxval, * int *nval, const char *value ) * Class Membership: * Table member function (over-rides the astMapGet1C method inherited * from the KeyMap class). * Description: * This is the implementation of MapGet1 for = "C". We * cannot use the MAKE_MAPGET1 macro for this because the string * version of this function has an extra parameter giving the maximum * length of each string which can be stored in the supplied buffer. * Parameters: * (see MapGet1) */ /* Local Variables: */ AstTable *this; /* Pointer to Table structure */ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ int irow; /* Row index within key string */ int result; /* Returned flag */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the Table structure. */ this = (AstTable *) this_keymap; /* If the key is the name of a global table parameter, use the parent method to get the value of hte parameter. */ if( astHasParameter( this, key ) ) { result = (*parent_mapget1c)( this_keymap, key, l, mxval, nval, value, status ); /* Check the supplied key looks like a table cell key, and get the the column name and the row number. Also checks that the table contains a column with the specified name. */ } else if( ParseKey( this, key, astGetKeyError( this ), colname, &irow, NULL, "astMapGet1C", status ) ) { /* If the row index is larger than the current number of rows in the table, do nothing more. */ if( irow <= astGetNrow( this ) ){ /* Use the astMapGet1 method in the parent keyMap class to get the cell contents. */ result = (*parent_mapget1c)( this_keymap, key, l, mxval, nval, value, status ); } } /* If an error occurred, return zero. */ if( !astOK ) result = 0; /* Return the result.*/ return result; } /* * Name: * MapGetElem * Purpose: * Get a single element of a vector value from a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int MapGetElem( AstKeyMap *this, const char *key, int elem, * type *value, int *status ) * int MapGetElemC( AstKeyMap *this, const char *key, int l, int elem, * char *value, int *status ) * Class Membership: * Table member function (over-rides the astMapGetElem method inherited * from the KeyMap class). * Description: * This is a set of functions for retrieving a single element of a vector * value from a cell of a Table. You should replace in the generic * function name MapGetElem by an appropriate 1-character type code * (see the "Data Type Codes" section in the astMapGetElem docs). The * stored value is converted to the data type indiced by before being * returned (an error is reported if it is not possible to convert the * stored value to the requested data type). * * Note, the MapGetElemC function has an extra parameter "l" which * specifies the maximum length of each string to be stored in the * "value" buffer (see the "MapGetElemC" docs). * Parameters: * this * Pointer to the Table. * key * A character string identifying the cell from which the value is * to be retrieved. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * elem * The index of the vector element to modify, starting at zero. * If the index is outside the range of the vector, an error will * be reported. * value * A pointer to a buffer in which to return the requested values. * If the requested cell is not found, or if it is found but has an * undefined value (see astMapPutU), then the contents of the buffer * on entry to this function will be unchanged on exit. * status * Pointer to inherited status value. * Returned Value: * A non-zero value is returned if the requested key name was found, and * does not have an undefined value (see astMapPutU). Zero is returned * otherwise. * MapGetElemC: * The "value" buffer supplied to the MapGetElemC function should be a * pointer to a character array with "l" elements, where "l" is * the maximum length of a string to be returned. The value of "l" * should be supplied as an extra parameter following "key" when * invoking MapGetElemC, and should include space for a terminating * null character. * Notes: * - No error is reported if the requested cell cannot be found in the * given KeyMap, but a zero value will be returned as the function value. * The supplied buffer will be returned unchanged. * - Key names are case insensitive, and white space is considered * significant. * - If the stored value is a scalar value, then the value will be * returned in the first element of the supplied array, and "nval" * will be returned set to 1. */ /* Define a macro to implement the function for a specific data type (excluding "C" since that needs an extra parameter). */ #define MAKE_MAPGETELEM(X,Xlc,Xtype,Itype) \ static int MapGetElem##X( AstKeyMap *this_keymap, const char *key, int elem, \ Xtype *value, int *status ) { \ \ /* Local Variables: */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ int result; /* Returned flag */ \ \ /* Initialise */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to get the value of hte parameter. */ \ if( astHasParameter( this, key ) ) { \ result = (*parent_mapgetelem##Xlc)( this_keymap, key, elem, \ value, status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, astGetKeyError( this ), colname, &irow, \ NULL, "astMapGetElem" #X, status ) ) { \ \ /* If the row index is larger than the current number of rows in the \ table, do nothing more. */ \ if( irow <= astGetNrow( this ) ){ \ \ /* Use the astMapGetElem method in the parent keyMap class to get the \ cell contents. */ \ result = (*parent_mapgetelem##Xlc)( this_keymap, key, elem, \ value, status ); \ } \ } \ \ /* If an error occurred, return zero. */ \ if( !astOK ) result = 0; \ \ /* Return the result.*/ \ return result; \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPGETELEM(I,i,int,AST__INTTYPE) MAKE_MAPGETELEM(D,d,double,AST__DOUBLETYPE) MAKE_MAPGETELEM(F,f,float,AST__FLOATTYPE) MAKE_MAPGETELEM(A,a,AstObject *,AST__OBJECTTYPE) MAKE_MAPGETELEM(P,p,void *,AST__POINTERTYPE) MAKE_MAPGETELEM(S,s,short int,AST__SINTTYPE) MAKE_MAPGETELEM(B,b,unsigned char,AST__BYTETYPE) /* Undefine the macro. */ #undef MAKE_MAPGETELEM static int MapGetElemC( AstKeyMap *this_keymap, const char *key, int l, int elem, char *value, int *status ) { /* * Name: * MapGetElemC * Purpose: * Get a single element of a vector value from a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int MapGetElemC( AstKeyMap *this, const char *key, int l, int elem, * char *value, int *status ) * Class Membership: * Table member function (over-rides the astMapGetElemC method inherited * from the KeyMap class). * Description: * This is the implementation of MapGetElem for = "C". We * cannot use the MAKE_MAPGETELEM macro for this because the string * version of this function has an extra parameter giving the maximum * length of each string which can be stored in the supplied buffer. * Parameters: * (see MapGetElem) */ /* Local Variables: */ AstTable *this; /* Pointer to Table structure */ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ int irow; /* Row index within key string */ int result; /* Returned flag */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the Table structure. */ this = (AstTable *) this_keymap; /* If the key is the name of a global table parameter, use the parent method to get the value of hte parameter. */ if( astHasParameter( this, key ) ) { result = (*parent_mapgetelemc)( this_keymap, key, l, elem, value, status ); /* Check the supplied key looks like a table cell key, and get the the column name and the row number. Also checks that the table contains a column with the specified name. */ } else if( ParseKey( this, key, astGetKeyError( this ), colname, &irow, NULL, "astMapGetElemC", status ) ) { /* If the row index is larger than the current number of rows in the table, do nothing more. */ if( irow <= astGetNrow( this ) ){ /* Use the astMapGetElem method in the parent keyMap class to get the cell contents. */ result = (*parent_mapgetelemc)( this_keymap, key, l, elem, value, status ); } } /* If an error occurred, return zero. */ if( !astOK ) result = 0; /* Return the result.*/ return result; } /* * Name: * MapPut0 * Purpose: * Stores a scalar value in a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void MapPut0( AstKeyMap *this, const char *key, type value, * const char *comment, int *status ) * Class Membership: * Table member function (over-rides the astMapPut0 method inherited * from the KeyMap class). * Description: * This is a set of functions for storing a scalar value in a cell of * a Table. You should use a function which matches the data type of the * data you wish to add to the Table by replacing in the generic * function name MapPut0 by an appropriate 1-character type code (see * the "Data Type Codes" section in the astMapPut0 docs). * Parameters: * this * Pointer to the Table in which to store the supplied value. * key * A character string identifying the cell in which the value is * to be stored. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * value * The value to be stored. The data type of this value should match * the 1-character type code appended to the function name (e.g. if * you are using astMapPut0A, the type of this value should be "pointer * to AstObject"). An error will be reported if this data type is * different to the data type assigned to the column when it was * created via astAddColumn. * comment * A pointer to a null-terminated comment string to be stored with the * value. A NULL pointer may be supplied, in which case no comment is * stored. * status * Pointer to inherited status value. * Notes: * - Key names are case insensitive, and white space is considered * significant. * - The new value will replace any old value already stored in the * Table for the specified cell. * - If the stored value is an AST Object pointer, the Object's reference * count is incremented by this call. Any subsequent changes made to * the Object using the returned pointer will be reflected in any * any other active pointers for the Object, including any obtained * later using astMapget0A. The reference count for the Object will be * decremented when the KeyMap is destroyed, or the entry is removed or * over-written with a different pointer. */ /* Define a macro to implement the function for a specific data type. */ #define MAKE_MAPPUT0(X,Xlc,Xtype,Itype,ValExp) \ static void MapPut0##X( AstKeyMap *this_keymap, const char *key, Xtype value, \ const char *comment, int *status ) { \ \ /* Local Variables: */ \ AstKeyMap *col_km; /* KeyMap holding details of the requested column */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ int type; /* Data type of the requested column */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to put the value of the parameter. */ \ if( astHasParameter( this, key ) ) { \ (*parent_mapput0##Xlc)( this_keymap, key, value, comment, status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, 1, colname, &irow, &col_km, "astMapPut0" #X, \ status ) ) { \ \ /* Check the column holds scalar values of the type implied by the \ code in the function name. */ \ (void) astMapGet0I( col_km, TYPE, &type ); \ if( type != Itype && astOK ) { \ astError( AST__BADTYP, "astMapPut0" #X "(%s): Failed to store a " \ #Xtype " value for cell \"%s\": column %s holds %s " \ "values.", status, astGetClass( this ), key, colname, \ TypeString( type ) ); \ } \ \ if( astMapHasKey( col_km, SHAPE ) && astOK ) { \ astError( AST__BADTYP, "astMapPut0" #X "(%s): Failed to store a " \ "scalar value for cell \"%s\": column %s holds vector " \ " values.", status, astGetClass( this ), key, colname ); \ } \ \ /* If the row index is larger than the current number of rows in the \ table, update the number of rows in the table. */ \ if( irow > astGetNrow( this ) ) astSetNrow( this, irow ); \ \ /* Use the astMapPut0 method in the parent keyMap class to store the \ new cell contents. */ \ (*parent_mapput0##Xlc)( this_keymap, key, value, comment, status ); \ \ /* Free resources. */ \ col_km = astAnnul( col_km ); \ } \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPPUT0(I,i,int,AST__INTTYPE,value) MAKE_MAPPUT0(D,d,double,AST__DOUBLETYPE,value) MAKE_MAPPUT0(F,f,float,AST__FLOATTYPE,value) MAKE_MAPPUT0(C,c,const char *,AST__STRINGTYPE,astStore(NULL,value,strlen(value)+1)) MAKE_MAPPUT0(A,a,AstObject *,AST__OBJECTTYPE,(value?astClone(value):NULL)) MAKE_MAPPUT0(P,p,void *,AST__POINTERTYPE,value) MAKE_MAPPUT0(S,s,short int,AST__SINTTYPE,value) MAKE_MAPPUT0(B,b,unsigned char,AST__BYTETYPE,value) /* Undefine the macro. */ #undef MAKE_MAPPUT0 /* * Name: * MapPut1 * Purpose: * Stores a vectorised value in a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void MapPut1( AstKeyMap *this, const char *key, int size, * const type value[], const char *comment, * int *status ); * Class Membership: * Table member function (over-rides the astMapPut1 method inherited * from the KeyMap class). * Description: * This is a set of functions for storing a vectorised value in a cell of * a Table. You should use a function which matches the data type of the * data you wish to add to the Table by replacing in the generic * function name MapPut1 by an appropriate 1-character type code (see * the "Data Type Codes" section in the astMapPut1 docs). * Parameters: * this * Pointer to the Table in which to store the supplied value. * key * A character string identifying the cell in which the value is * to be stored. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * size * The number of elements in the supplied array of values. * value * The value to be stored. The data type of this value should match * the 1-character type code appended to the function name (e.g. if * you are using astMapPut0A, the type of this value should be "pointer * to AstObject"). An error will be reported if this data type is * different to the data type assigned to the column when it was * created via astAddColumn. * comment * A pointer to a null-terminated comment string to be stored with the * value. A NULL pointer may be supplied, in which case no comment is * stored. * status * Pointer to inherited status value. * Notes: * - Key names are case insensitive, and white space is considered * significant. * - The new value will replace any old value already stored in the * Table for the specified cell. */ /* Define a macro to implement the function for a specific data type. */ #define MAKE_MAPPUT1(X,Xlc,Xtype,Itype,ValExp) \ static void MapPut1##X( AstKeyMap *this_keymap, const char *key, int size, \ Xtype value[], const char *comment, \ int *status ) { \ \ /* Local Variables: */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to put the value of the parameter. */ \ if( astHasParameter( this, key ) ) { \ (*parent_mapput1##Xlc)( this_keymap, key, size, value, \ comment, status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, 1, colname, &irow, NULL, "astMapPut1" #X, \ status ) ) { \ \ /* Check the column holds vector values of the type implied by the \ code in the function name. */ \ if( astGetColumnType( this, colname ) != Itype && astOK ) { \ astError( AST__BADTYP, "astMapPut1" #X "(%s): Failed to store " \ #Xtype " values for cell \"%s\": column %s holds %s values.", \ status, astGetClass( this ), key, colname, \ TypeString( astGetColumnType( this, colname ) ) ); \ } \ \ /* Check the column holds vectors with length equal to the supplied vector. */ \ if( astGetColumnLength( this, colname ) != size && astOK ) { \ astError( AST__BADTYP, "astMapPut1" #X "(%s): Failed to " \ "store a vector value for cell \"%s\": column " \ "%s needs %d values per cell but %d were supplied.", \ status, astGetClass( this ), key, colname, \ astGetColumnLength( this, colname ), size ); \ } \ \ /* If all is OK, update the number of rows in the table if required, and \ store the vector in the parent KeyMap. */ \ if( astOK ) { \ if( irow > astGetNrow( this ) ) astSetNrow( this, irow ); \ (*parent_mapput1##Xlc)( this_keymap, key, size, value, \ comment, status ); \ } \ \ } \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPPUT1(D,d,const double,AST__DOUBLETYPE,value[i]) MAKE_MAPPUT1(F,f,const float,AST__FLOATTYPE,value[i]) MAKE_MAPPUT1(I,i,const int,AST__INTTYPE,value[i]) MAKE_MAPPUT1(C,c,const char *const,AST__STRINGTYPE,astStore(NULL,value[i],strlen(value[i])+1)) MAKE_MAPPUT1(A,a,AstObject *const,AST__OBJECTTYPE,(value[i]?astClone(value[i]):NULL)) MAKE_MAPPUT1(P,p,void *const,AST__POINTERTYPE,value[i]) MAKE_MAPPUT1(S,s,const short int,AST__SINTTYPE,value[i]) MAKE_MAPPUT1(B,b,const unsigned char,AST__BYTETYPE,value[i]) /* Undefine the macro. */ #undef MAKE_MAPPUT1 /* * Name: * MapPutElem * Purpose: * Put a value into an element of a vector value in a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void MapPutElem( AstKeyMap *this, const char *key, int elem, * type *value, int *status ) * Class Membership: * Table member function (over-rides the astMapPutElem method inherited * from the KeyMap class). * Description: * This is a set of functions for storing a value in a single element * of a vector value stored in a cell of a Table. You should use a * function which matches the data type of the data you wish to add to * the Table by replacing in the generic function name MapPutElem * by an appropriate 1-character type code (see the "Data Type Codes" * section in the astMapPutElem docs). * Parameters: * this * Pointer to the Table in which to store the supplied value. * key * A character string identifying the cell in which the value is * to be stored. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * elem * The index of the vector element to modify, starting at zero. * If the index is outside the range of the vector, an error will * be reported. * value * The value to be stored. The data type of this value should match * the 1-character type code appended to the function name (e.g. if * you are using astMapPut0A, the type of this value should be "pointer * to AstObject"). An error will be reported if this data type is * different to the data type assigned to the column when it was * created via astAddColumn. * status * Pointer to inherited status value. * Notes: * - Key names are case insensitive, and white space is considered * significant. * - The new value will replace any old value already stored in the * Table for the specified cell. * - If the stored value is an AST Object pointer, the Object's reference * count is incremented by this call. Any subsequent changes made to * the Object using the returned pointer will be reflected in any * any other active pointers for the Object, including any obtained * later using astMapget0A. The reference count for the Object will be * decremented when the KeyMap is destroyed, or the entry is removed or * over-written with a different pointer. */ /* Define a macro to implement the function for a specific data type. */ #define MAKE_MAPPUTELEM(X,Xlc,Xtype,Itype) \ static void MapPutElem##X( AstKeyMap *this_keymap, const char *key, int elem, \ Xtype value, int *status ) { \ \ /* Local Variables: */ \ AstTable *this; /* Pointer to Table structure */ \ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ \ int irow; /* Row index within key string */ \ int type; /* Data type of the requested column */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Get a pointer to the Table structure. */ \ this = (AstTable *) this_keymap; \ \ /* If the key is the name of a global table parameter, use the parent \ method to put the value of the parameter. */ \ if( astHasParameter( this, key ) ) { \ (*parent_mapputelem##Xlc)( this_keymap, key, elem, value, \ status ); \ \ /* Check the supplied key looks like a table cell key, and get the \ the column name and the row number. Also checks that the table \ contains a column with the specified name. */ \ } else if( ParseKey( this, key, 1, colname, &irow, NULL, "astMapPutElem" #X, \ status ) ) { \ \ /* Check the column holds vector values of the type implied by the \ code in the function name. */ \ type = astGetColumnType( this, colname ); \ if( type != Itype && astOK ) { \ astError( AST__BADTYP, "astMapPutElem" #X "(%s): Failed to store a " \ #Xtype " value in cell \"%s\": column %s holds %s values.", \ status, astGetClass( this ), key, colname, \ TypeString( type ) ); \ } \ \ /* Check the column holds vectors with length equal to the supplied vector. */ \ if( astGetColumnLength( this, colname ) <= elem && astOK ) { \ astError( AST__BADTYP, "astMapPutElem" #X "(%s): Failed to " \ "store a value for element %d (zero-based) of " \ "cell \"%s\": column %s has only %d values per " \ "cell.", status, astGetClass( this ), elem, key, \ colname, astGetColumnLength( this, colname ) ); \ } \ \ /* If all is OK, update the number of rows in the table if required, and \ store the value in the parent KeyMap. */ \ if( astOK ) { \ if( irow > astGetNrow( this ) ) astSetNrow( this, irow ); \ (*parent_mapputelem##Xlc)( this_keymap, key, elem, value, \ status ); \ } \ } \ } /* Expand the above macro to generate a function for each required data type. */ MAKE_MAPPUTELEM(I,i,int,AST__INTTYPE) MAKE_MAPPUTELEM(D,d,double,AST__DOUBLETYPE) MAKE_MAPPUTELEM(F,f,float,AST__FLOATTYPE) MAKE_MAPPUTELEM(A,a,AstObject *,AST__OBJECTTYPE) MAKE_MAPPUTELEM(P,p,void *,AST__POINTERTYPE) MAKE_MAPPUTELEM(C,c,const char *,AST__STRINGTYPE) MAKE_MAPPUTELEM(S,s,short int,AST__SINTTYPE) MAKE_MAPPUTELEM(B,b,unsigned char,AST__BYTETYPE) /* Undefine the macro. */ #undef MAKE_MAPPUTELEM static void MapPutU( AstKeyMap *this_keymap, const char *key, const char *comment, int *status ) { /* * Name: * MapPutU * Purpose: * Stores a undefined value in a cell of a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void MapPutU( AstKeyMap *this, const char *key, const char *comment, * int *status ) * Class Membership: * Table member function (over-rides the astMapPutU method inherited * from the KeyMap class). * Description: * This function adds a new cell to a Table, but no value is stored with * the cell. The cell therefore has a special data type represented by * symbolic constant AST__UNDEFTYPE. * * An example use is to add cells with undefined values to a Table * prior to locking them with the MapLocked attribute. Such cells * can act as placeholders for values that can be added to the KeyMap * later. * Parameters: * this * Pointer to the Table in which to store the supplied value. * key * A character string identifying the cell in which the value is * to be stored. It should have the form "COLNAME(irow)", where * "COLNAME" is replaced by the name of a column that has been * defined previously using the astAddColumn method, and "irow" is * an integer row index (the first row is row 1). * comment * A pointer to a null-terminated comment string to be stored with the * value. A NULL pointer may be supplied, in which case no comment is * stored. * status * Pointer to inherited status value. * Notes: * - Key names are case insensitive, and white space is considered * significant. * - The new undefined value will replace any old value already stored in * the Table for the specified cell. */ /* Local Variables: */ AstTable *this; /* Pointer to Table structure */ char colname[ AST__MXCOLNAMLEN + 1 ]; /* Column name read from string */ int irow; /* Row index within key string */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the Table structure. */ this = (AstTable *) this_keymap; /* If the key is the name of a global table parameter, use the parent method to put the value of the parameter. */ if( astHasParameter( this, key ) ) { (*parent_mapputu)( this_keymap, key, comment, status ); /* Check the supplied key looks like a table cell key, and get the the column name and the row number. Also checks that the table contains a column with the specified name. */ } else if( ParseKey( this, key, 1, colname, &irow, NULL, "astMapPutU", status ) ) { /* If the row index is larger than the current number of rows in the table, update the number of rows in the table. */ if( irow > astGetNrow( this ) ) astSetNrow( this, irow ); /* Use the astMapPutU method in the parent keyMap class to store the new cell contents. */ (*parent_mapputu)( this_keymap, key, comment, status ); } } static const char *ParameterName( AstTable *this, int index, int *status ) { /* *++ * Name: c astParameterName f AST_PARAMETERNAME * Purpose: * Get the name of the global parameter at a given index within the Table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c const char *astParameterName( AstTable *this, int index ) f RESULT = AST_PARAMETERNAME( THIS, INDEX, STATUS ) * Class Membership: * Table method. * Description: * This function returns a string holding the name of the global parameter with * the given index within the Table. * * This function is intended primarily as a means of iterating round all * the parameters in a Table. For this purpose, the number of parameters in * the Table is given by the Nparameter attribute of the Table. This function * could then be called in a loop, with the index value going from c zero to one less than Nparameter. f one to Nparameter. * * Note, the index associated with a parameter decreases monotonically with * the age of the parameter: the oldest Parameter in the Table will have index * one, and the Parameter added most recently to the Table will have the * largest index. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c index f INDEX = INTEGER (Given) * The index into the list of parameters. The first parameter has index * one, and the last has index "Nparameter". f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astParameterName() c A pointer to a null-terminated string containing the f AST_PARAMETERNAME = CHARACTER * ( AST__SZCHR ) f The * upper case parameter name. * Notes: c - The returned pointer is guaranteed to remain valid and the c string to which it points will not be over-written for a total c of 50 successive invocations of this function. After this, the c memory containing the string may be re-used, so a copy of the c string should be made if it is needed for longer than this. c - A NULL pointer will be returned if this function is invoked c with the AST error status set, or if it should fail for any c reason. f - A blank string will be returned if this function is invoked f with STATUS set to an error value, or if it should fail for any f reason. *-- */ /* Local Variables: */ AstKeyMap *pars; /* KeyMap holding parameter definitions */ const char *result; /* Check the global error status. */ if ( !astOK ) return NULL; /* Get apointer to the KeyMap holding all parameter definitions. */ pars = astParameterProps( this ); /* Issue a more useful error message than that issued by astMapKey if the index is invalid. */ if( index < 1 || index > astMapSize( pars ) ) { astError( AST__MPIND, "astParameterName(%s): Cannot find parameter " "%d (zero-based) of the %s - invalid index.", status, astGetClass( this ), index, astGetClass( this ) ); } /* Get the parameter name. */ result = astMapKey( pars, index - 1 ); /* Free resources. */ pars = astAnnul( pars ); /* Return a pointer to the required parameter name. */ return result; } static AstKeyMap *ParameterProps( AstTable *this, int *status ) { /* *+ * Name: * astParameterProps * Purpose: * Returns a pointer to the KeyMap holding parameter properties. * Type: * Protected virtual function. * Synopsis: * #include "table.h" * AstKeyMap *astParameterProps( AstTable *this ) * Class Membership: * Table method. * Description: * This function returns a pointer to the KeyMap that holds * definitions of all the parameters added to the Table. * Parameters: * this * Pointer to the Table. * Returned Value: * A pointer to the KeyMap. It should be annulled using astAnnul * when no longer needed. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return a cloned pointer to the required KeyMap. */ return astClone( this->parameters ); } static int ParseKey( AstTable *this, const char *key, int report, char colname[ AST__MXCOLNAMLEN + 1 ], int *irow, AstKeyMap **col_km, const char *method, int *status ){ /* * Name: * ParseKey * Purpose: * Find the column name and row index in a KeyMap key. * Type: * Private function. * Synopsis: * #include "table.h" * int ParseKey( AstTable *this, const char *key, int report, * char colname[ AST__MXCOLNAMLEN + 1 ], int *irow, * AstKeyMap **col_km, const char *method, int *status ) * Class Membership: * Table member function * Description: * This function checks that the supplied KeyMap key conforms to the * format expected for Table cells: i.e. "COLNAME(irow)", where * "COLNAME" is the name of a column and "irow" is an integer row * index (the first row is row 1), An error is reported if this is * not the case. * Parameters: * this * Pointer to the table. * key * The key string to test. * report * If non-zero, an error will be reported if the key does not * correspond to a cell of an existing column. Otherwise, no * error will be reported. * colname * A buffer in which to return the column name. * irow * Address of an int in which to return the row index. * col_km * Address of a KeyMap pointer in which to return a pointer to the * KeyMap holding the information about the column. The returned * KeyMap pointer should be annulled using astAnnul when no lngerr * needed. If "col_km" is NULL, no KeyMap pointer is returned. * method * Pointer to a string holding the name of the method to include in * any error message. * status * Address of the inherited status value. * Returned Value: * Zero is returned if the key is not a valid Table cell key, or if an * error occurs. */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ int result; /* Returned flag */ int collen; /* Length of column name */ int nctot; /* Number of characters read */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Check the supplied key looks like a table cell key, and extract the column name and row number. */ nctot = 0; if( 1 == astSscanf( key, "%*[^(]%n(%d) %n", &collen, irow, &nctot ) && ( nctot >= strlen( key ) ) ) { /* Check the column name is not too long. */ if( collen > AST__MXCOLNAMLEN ) { if( report ) { astError( AST__BADKEY, "%s(%s): Failed to store a value for cell " "\"%s\": column name is too long.", status, method, astGetClass( this ), key ); } /* Check the row index is positive. */ } else if( *irow < 1 ) { if( report ) { astError( AST__BADKEY, "%s(%s): Failed to store a value for cell " "\"%s\": row index %d is invalid.", status, method, astGetClass( this ), key, *irow ); } /* If the key looks OK so far... */ } else { /* Convert the column name to upper case and store in the returned buffer. */ astChrCase( key, colname, 1, collen + 1 ); colname[ collen ] = 0; /* check that the column exists in the Table, returning a pointer to the column KeyMap is reequired. */ cols = astColumnProps( this ); if( col_km ) { result = astMapGet0A( cols, colname, col_km ); } else { result = astMapHasKey( cols, colname ); } cols = astAnnul( cols ); /* Report an error if the table does not contain the specified column. */ if( !result && astOK && report) { astError( AST__BADKEY, "%s(%s): Failed to store a value for " "cell \"%s\": the table does not contain a column " "called '%s'.", status, method, astGetClass( this ), key, colname ); } } /* Report an error if the cell key has the wrong format. */ } else if( report ) { astError( AST__BADKEY, "%s(%s): Failed to store a value for cell " "\"%s\": the cell name is invalid.", status, method, astGetClass( this ), key ); } /* Return the result.*/ return result; } static void PurgeRows( AstTable *this, int *status ) { /* *++ * Name: c astPurgeRows f AST_PURGEROWS * Purpose: * Remove all empty rows from a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astPurgeRows( AstTable *this ) f CALL AST_PURGEROWS( THIS, STATUS ) * Class Membership: * Table method. * Description: * This function removes all empty rows from the Table, renaming * the key associated with each table cell accordingly. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ char newkey[ AST__MXCOLKEYLEN + 1 ]; /* New cell key string */ char oldkey[ AST__MXCOLKEYLEN + 1 ]; /* Old cell key string */ const char *col; /* Column name */ const char *key; /* Pointer to key string */ const char *op; /* Pointer to opening parenthesis */ int *w1; /* Work space pointer */ int icol; /* Column index */ int inew; /* New row index */ int iold; /* Old row index */ int ncol; /* Number of columns in table */ int nrow; /* Number of rows in table */ int reset; /* Start a new pass through the KeyMap? */ /* Check the global error status. */ if ( !astOK ) return; /* Get the number of rows in the table. */ nrow = astGetNrow( this ); /* Create workspace to hold the number of defined values stored in each row. Initialise every row to have zero defined values. */ w1 = astCalloc( nrow, sizeof( int ) ); if( astOK ) { /* Iterate round all keys in the KeyMap. */ reset = 1; while( ( key = astMapIterate( this, reset ) ) && astOK ) { reset = 0; /* Extract the row number from the key. */ op = strchr( key, '(' ); if( !op || astSscanf( op + 1, "%d", &iold ) != 1 || iold > nrow ) { astError( AST__INTER, "astPurgeRows(%s): Illegal key '%s' " "found in a %s (internal programming error).", status, astGetClass( this ), key, astGetClass( this ) ); /* Increment the number of values in this row. Note row indices are one-based. */ } else { w1[ iold - 1 ]++; } } /* Loop round all columns in the Table. */ ncol = astGetNcolumn( this ); inew = nrow; for( icol = 1; icol <= ncol; icol++ ) { /* Get the column name */ col = astColumnName( this, icol ); /* Loop round all the old row numbers. Skip empty rows.*/ inew = 0; for( iold = 0; iold < nrow; iold++ ) { if( w1[ iold ] > 0 ) { /* Increment the row number to use in place of the old row number. If the old and new row numbers are the same, we do not need to rename the cell. */ if( iold != inew++ ) { /* For the old and new cell names */ sprintf( oldkey, "%s(%d)", col, iold + 1 ); sprintf( newkey, "%s(%d)", col, inew ); /* Rename the KeyMap entry. */ astMapRename( this, oldkey, newkey ); } } } /* If all rows were used, we do not need to check any more columns. */ if( iold == inew ) break; } /* Store the new number of rows. */ astSetNrow( this, inew ); } /* Free resources. */ w1 = astFree( w1 ); } static void RemoveColumn( AstTable *this, const char *name, int *status ) { /* *++ * Name: c astRemoveColumn f AST_REMOVECOLUMN * Purpose: * Remove a column from a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astRemoveColumn( AstTable *this, const char *name ) f CALL AST_REMOVECOLUMN( THIS, NAME, STATUS ) * Class Membership: * Table method. * Description: * This function removes a specified column from the supplied table. * The c function f routine * returns without action if the named column does not exist in the * Table (no error is reported). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c name f NAME = CHARACTER * ( * ) (Given) * The column name. Trailing spaces are ignored (all other spaces * are significant). Case is significant. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ char key[ AST__MXCOLKEYLEN + 1 ]; /* Cell key string */ int irow; /* Row index */ int namlen; /* Used length of "name" */ int nrow; /* Number of rows in table */ /* Check the global error status. */ if ( !astOK ) return; /* Verify supplied values. */ namlen = astChrLen( name ); if( namlen == 0 ) { astError( AST__BADKEY, "astRemoveColumn(%s): Illegal blank column name " "supplied.", status, astGetClass( this ) ); } /* Get the number of rows in the table. */ nrow = astGetNrow( this ); /* If there is no column with the given name in the Table, do nothing more. */ cols = astColumnProps( this ); if( astOK && astMapHasKey( cols, name ) ) { /* Remove the column description from the columns keymap. */ astMapRemove( cols, name ); /* Remove any column cells with defined values from the parent KeyMap. */ for( irow = 1; irow <= nrow; irow++ ) { sprintf( key, "%.*s(%d)", namlen, name, irow ); (*parent_mapremove)( (AstKeyMap *) this, key, status ); } } cols = astAnnul( cols ); } static void RemoveParameter( AstTable *this, const char *name, int *status ) { /* *++ * Name: c astRemoveParameter f AST_REMOVEPARAMETER * Purpose: * Remove a global parameter from a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astRemoveParameter( AstTable *this, const char *name ) f CALL AST_REMOVEPARAMETER( THIS, NAME, STATUS ) * Class Membership: * Table method. * Description: * This function removes a specified global parameter from the supplied table. * The c function f routine * returns without action if the named parameter does not exist in the * Table (no error is reported). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c name f NAME = CHARACTER * ( * ) (Given) * The parameter name. Trailing spaces are ignored (all other spaces * are significant). Case is significant. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstKeyMap *pars; /* KeyMap holding parameter definitions */ /* Check the global error status. */ if ( !astOK ) return; /* Verify supplied values. */ if( astChrLen( name ) == 0 ) { astError( AST__BADKEY, "astRemoveParameter(%s): Illegal blank parameter name " "supplied.", status, astGetClass( this ) ); } /* If there is no parameter with the given name in the Table, do nothing more. */ pars = astParameterProps( this ); if( astOK && astMapHasKey( pars, name ) ) { /* Remove the parameter description from the parameters keymap. */ astMapRemove( pars, name ); /* Remove any entry holding the parameter value from the parent KeyMap. */ (*parent_mapremove)( (AstKeyMap *) this, name, status ); } pars = astAnnul( pars ); } static void RemoveRow( AstTable *this, int index, int *status ) { /* *++ * Name: c astRemoveRow f AST_REMOVEROW * Purpose: * Remove a row from a table. * Type: * Public virtual function. * Synopsis: c #include "table.h" c void astRemoveRow( AstTable *this, int index ) f CALL AST_REMOVEROW( THIS, INDEX, STATUS ) * Class Membership: * Table method. * Description: * This function removes a specified row from the supplied table. * The c function f routine * returns without action if the row does not exist in the * Table (no error is reported). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Table. c index f INDEX = INTEGER (Given) * The index of the row to be removed. The first row has index 1. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstKeyMap *cols; /* KeyMap holding column definitions */ char key[ AST__MXCOLKEYLEN + 1 ]; /* Cell key string */ const char *col; /* Column name */ int icol; /* Column index */ int ncol; /* Number of columns in table */ int nrow; /* Number of rows in table */ /* Check the global error status. */ if ( !astOK ) return; /* Get the number of rows in the table. */ nrow = astGetNrow( this ); /* Do nothing if the specified row is out of bounds. */ if( index > 0 && index <= nrow ) { /* Loop round all columns in the table. */ cols = astColumnProps( this ); ncol = astMapSize( cols ); for( icol = 0; icol < ncol; icol++ ) { col = astMapKey( cols, icol ); /* Remove the cell of the current column at the requested row. */ sprintf( key, "%s(%d)", col, index ); (*parent_mapremove)( (AstKeyMap *) this, key, status ); } cols = astAnnul( cols ); /* If the removed row was the last row, reduce the number of rows in the Table. */ if( index == nrow ) astSetNrow( this, index - 1 ); } } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a Table. * Type: * Private function. * Synopsis: * #include "table.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * Table member function (over-rides the astSetAttrib protected * method inherited from the KeyMap class). * Description: * This function assigns an attribute value for a Table, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the Table. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstTable *this; /* Pointer to the Table structure */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Table structure. */ this = (AstTable *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* None as yet */ /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) #define MATCH2(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "(%*s) =%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* If the attribute was not recognised, use this macro to report an error if a read-only attribute has been specified. */ if ( MATCH( "ncolumn" ) || MATCH( "nparameter" ) || MATCH( "nrow" ) || MATCH2( "columnlenc" ) || MATCH2( "columnlength" ) || MATCH2( "columnndim" ) || MATCH2( "columntype" ) || MATCH2( "columnunit" ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } /* Undefine macros local to this function. */ #undef MATCH #undef MATCH2 } static void SetKeyCase( AstKeyMap *this, int keycase, int *status ) { /* * Name: * SetKeyCase * Purpose: * Set a value for the KeyCase attribute value for a Table. * Type: * Private function. * Synopsis: * #include "keymape.h" * void SetKeyCase( AstKeyMap *this, int keycase, int *status ) * Class Membership: * Table member function (over-rides the astSetKeyCase protected * method inherited from the KeyMap class). * Description: * This function assigns a new valeu to the KeyCase attribute for a * Table. For a Table, the KeyCase attribute cannot be changed so this * function exits without action. * Parameters: * this * Pointer to the Table. * keycase * The new value to set. */ } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a Table. * Type: * Private function. * Synopsis: * #include "table.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Table member function (over-rides the astTestAttrib protected * method inherited from the KeyMap class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a Table's attributes. * Parameters: * this * Pointer to the Table. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ int len; /* Length of attribute string */ int nc; /* Number of characters read by astSscanf */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get the length of the attribute string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* None as yet */ /* Define a macro to see if the attribute string matches any of the read-only column attributes of this class. */ #define MATCH(attr) \ ( nc = 0, ( 0 == astSscanf( attrib, attr "(%*s)%n", &nc ) ) && \ ( nc >= len ) ) /* If the name is not recognised, test if it matches any of the read-only attributes of this class. If it does, then return zero. */ if ( !strcmp( attrib, "ncolumn" ) || !strcmp( attrib, "nparameter" ) || !strcmp( attrib, "nrow" ) || MATCH( "columnlenc" ) || MATCH( "columnlength" ) || MATCH( "columnndim" ) || MATCH( "columntype" ) || MATCH( "columnunit" ) ) { result = 0; /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; #undef MATCH } static const char *TypeString( int type ) { /* * Name: * TypeString * Purpose: * Return a pointer to a string describing a data type. * Type: * Private function. * Synopsis: * const char *TypeString( int type ); * Description: * This function returns a pointer to a string describing a data type. * Parameters: * type * The integer data type code. * Returned Value: * Pointer to a a string descirbing the data type (typically the C * data type). */ /* Local Variables: */ const char *result; /* Compare the supplied type code against each supported value. */ if( type == AST__INTTYPE ) { result = "int"; } else if( type == AST__BYTETYPE ) { result = "byte"; } else if( type == AST__DOUBLETYPE ) { result = "double"; } else if( type == AST__STRINGTYPE ) { result = "string"; } else if( type == AST__OBJECTTYPE ) { result = "Object"; } else if( type == AST__FLOATTYPE ) { result = "float"; } else if( type == AST__POINTERTYPE ) { result = "pointer"; } else if( type == AST__SINTTYPE ) { result = "short int"; } else if( type == AST__UNDEFTYPE ) { result = "undefined"; } else { result = NULL; } /* Return the result. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* *att++ * Name: * ColumnLenC(column) * Purpose: * The largest string length of any value in a column * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the minimum length which a character variable * must have in order to be able to store the longest value currently * present (at any row) in a specified column of the supplied Table. c This does not include room for a trailing null character. * The required column name should be placed inside the parentheses in * the attribute name. If the named column holds vector values, then * the attribute value is the length of the longest element of the * vector value. * Applicability: * Table * All Tables have this attribute. * Notes: * - If the named column holds numerical values, the length returned * is the length of the largest string that would be generated if the * column values were accessed as strings. *att-- */ /* *att++ * Name: * ColumnLength(column) * Purpose: * The number of elements in each value in a column * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the number of elements in each value stored * in a named column. Each value can be a scalar (in which case the * ColumnLength attribute has a value of 1), or a multi-dimensional * array ( in which case the ColumnLength value is equal to the * product of the array dimensions). * Applicability: * Table * All Tables have this attribute. *att-- */ /* *att++ * Name: * ColumnNdim(column) * Purpose: * The number of axes spanned by each value in a column * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the number of axes spanned by each value in a * column. If each cell in the column is a scalar, ColumnNdim will be * zero. If each cell in the column is a 1D spectrum, ColumnNdim will * be one. If each cell in the column is a 2D image, ColumnNdim will be * two, etc. The required column name should be placed inside the * parentheses in the attribute name. * Applicability: * Table * All Tables have this attribute. *att-- */ /* *att++ * Name: * ColumnType(column) * Purpose: * The data type of each value in a column * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds a integer value indicating the data type of * a named column in a Table. This is the data type which was used * when the column was added to the Table using astAddColumn. The * required column name should be placed inside the parentheses in * the attribute name. * * The attribute value will be one of AST__INTTYPE (for integer), * AST__SINTTYPE (for c short int), f INTEGER*2), * AST__BYTETYPE (for c unsigned bytes - i.e. unsigned chars), f bytes), * AST__DOUBLETYPE (for double * precision floating point), AST__FLOATTYPE (for single * precision floating point), AST__STRINGTYPE (for character string), * AST__OBJECTTYPE (for AST Object pointer), AST__POINTERTYPE (for * arbitrary C pointer) or AST__UNDEFTYPE (for undefined values * created by c astMapPutU). f AST_MAPPUTU). * Applicability: * Table * All Tables have this attribute. *att-- */ /* *att++ * Name: * Ncolumn * Purpose: * The number of columns in the table. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the number of columns currently in the table. Columns * are added and removed using the c astAddColumn and astRemoveColumn f AST_ADDCOLUMN and AST_REMOVECOLUMN * functions. * Applicability: * Table * All Tables have this attribute. *att-- */ /* *att++ * Name: * Nparameter * Purpose: * The number of global parameters in the table. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the number of global parameters currently in the table. * Parameters are added and removed using the c astAddParameter and astRemoveParameter f AST_ADDPARAMETER and AST_REMOVEPARAMETER * functions. * Applicability: * Table * All Tables have this attribute. *att-- */ /* *att++ * Name: * Nrow * Purpose: * The number of rows in the table. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute holds the index of the last row to which any * contents have been added using any of the * astMapPut... * AST_MAPPUT... * functions. The first row has index 1. * Applicability: * Table * All Tables have this attribute. *att-- */ astMAKE_GET(Table,Nrow,int,0,this->nrow) astMAKE_SET(Table,Nrow,int,nrow,value) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Table objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Table objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Mappings within the Table. */ /* Local Variables: */ AstTable *in; /* Pointer to input Table */ AstTable *out; /* Pointer to output Table */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output Tables. */ in = (AstTable *) objin; out = (AstTable *) objout; /* Make copies of the component KeyMaps and store pointers to them in the output Table structure. */ out->columns = in->columns ? astCopy( in->columns ) : NULL; out->parameters = in->parameters ? astCopy( in->parameters ) : NULL; } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Table objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Table objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstTable *this; /* Pointer to Table */ /* Obtain a pointer to the Table structure. */ this = (AstTable *) obj; /* Annul the pointers to the component KeyMaps. */ if( this->columns ) this->columns = astAnnul( this->columns ); if( this->parameters ) this->parameters = astAnnul( this->parameters ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Table objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Table class to an output Channel. * Parameters: * this * Pointer to the Table whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstTable *this; /* Pointer to the Table structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Table structure. */ this = (AstTable *) this_object; /* Write out values representing the instance variables for the Table class. Note, the primitive data in the Table will be written out by the parent KeyMap Dump function. This function deals just with the extra information held in the Table structure. */ /* Write out the number of rows in the table. */ astWriteInt( channel, "Nrow", 1, 1, astGetNrow( this ), "Number of rows in table" ); /* Write out the KeyMap holding definitions of each column. */ if( this->columns ) { astWriteObject( channel, "Columns", 1, 0, this->columns, "KeyMap holding " "column definitions" ); } /* Write out the KeyMap holding definitions of each global parameter. */ if( this->parameters ) { astWriteObject( channel, "Params", 1, 0, this->parameters, "KeyMap holding " "parameter definitions" ); } } /* Standard class functions. */ /* ========================= */ /* Implement the astIsATable and astCheckTable functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Table,KeyMap) astMAKE_CHECK(Table) AstTable *astTable_( const char *options, int *status, ...) { /* *++ * Name: c astTable f AST_TABLE * Purpose: * Create a Table. * Type: * Public function. * Synopsis: c #include "table.h" c AstTable *astTable( const char *options, ... ) f RESULT = AST_TABLE( OPTIONS, STATUS ) * Class Membership: * Table constructor. * Description: * This function creates a new empty Table and optionally initialises * its attributes. * * The Table class is a type of KeyMap that represents a two-dimensional * table of values. The c astMapGet... and astMapPut... f AST_MAPGET... and AST_MAPPUT... * methods provided by the KeyMap class should be used for storing and * retrieving values from individual cells within a Table. Each entry * in the KeyMap represents a single cell of the table and has an * associated key of the form "(i)" where "" is the name of a * table column and "i" is the row index (the first row is row 1). Keys * of this form should always be used when using KeyMap methods to access * entries within a Table. * * Columns must be declared using the c astAddColumn f AST_ADDCOLUMN * method before values can be stored within them. This also fixes the * type and shape of the values that may be stored in any cell of the * column. Cells may contain scalar or vector values of any data type * supported by the KeyMap class. Multi-dimensional arrays may also be * stored, but these must be vectorised when storing and retrieving * them within a table cell. All cells within a single column must * have the same type and shape (specified when the column is declared). * * Tables may have parameters that describe global properties of the * entire table. These are stored as entries in the parent KeyMap and * can be access using the get and set method of the KeyMap class. * However, parameters must be declared using the c astAddParameter f AST_ADDPARAMETER * method before being accessed. * * Note - since accessing entries within a KeyMap is a relatively slow * process, it is not recommended to use the Table class to store * very large tables. * Parameters: c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new Table. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new Table. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astTable() f AST_TABLE = INTEGER * A pointer to the new Table. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list described above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTable *new; /* Pointer to new Table */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the Table, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitTable( NULL, sizeof( AstTable ), !class_init, &class_vtab, "Table" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Table's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new Table. */ return new; } AstTable *astTableId_( const char *options, ... ) { /* * Name: * astTableId_ * Purpose: * Create a Table. * Type: * Private function. * Synopsis: * #include "table.h" * AstTable *astTableId_( const char *options, ... ) * Class Membership: * Table constructor. * Description: * This function implements the external (public) interface to the * astTable constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astTable_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astTable_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astTable_. * Returned Value: * The ID value associated with the new Table. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTable *new; /* Pointer to new Table */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the Table, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitTable( NULL, sizeof( AstTable ), !class_init, &class_vtab, "Table" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Table's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new Table. */ return astMakeId( new ); } AstTable *astInitTable_( void *mem, size_t size, int init, AstTableVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitTable * Purpose: * Initialise a Table. * Type: * Protected function. * Synopsis: * #include "table.h" * AstTable *astInitTable( void *mem, size_t size, int init, * AstTableVtab *vtab, const char *name ) * Class Membership: * Table initialiser. * Description: * This function is provided for use by class implementations to initialise * a new Table object. It allocates memory (if necessary) to accommodate * the Table plus any additional data associated with the derived class. * It then initialises a Table structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a Table at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Table is to be initialised. * This must be of sufficient size to accommodate the Table data * (sizeof(Table)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the Table (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the Table * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the Table's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new Table. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * Returned Value: * A pointer to the new Table. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstTable *new; /* Pointer to new Table */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitTableVtab( vtab, name ); /* Initialise. */ new = NULL; /* Initialise a KeyMap structure (the parent class) as the first component within the Table structure, allocating memory if necessary. Specify that the KeyMap should be defined in both the forward and inverse directions. */ new = (AstTable *) astInitKeyMap( mem, size, 0, (AstKeyMapVtab *) vtab, name ); if ( astOK ) { /* Initialise the Table data. */ /* ---------------------------- */ new->nrow = 0; new->columns = astKeyMap( "KeyCase=0,Sortby=AgeDown", status ); new->parameters = astKeyMap( "KeyCase=0,Sortby=AgeDown", status ); /* Tables require the KeyCase attribute to be zero. */ (*parent_setkeycase)( (AstKeyMap *) new, 0, status ); /* If an error occurred, clean up by deleting the new Table. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new Table. */ return new; } AstTable *astLoadTable_( void *mem, size_t size, AstTableVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadTable * Purpose: * Load a Table. * Type: * Protected function. * Synopsis: * #include "table.h" * AstTable *astLoadTable( void *mem, size_t size, AstTableVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * Table loader. * Description: * This function is provided to load a new Table using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Table structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a Table at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the Table is to be * loaded. This must be of sufficient size to accommodate the * Table data (sizeof(Table)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the Table (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Table structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstTable) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Table. If this is NULL, a pointer * to the (static) virtual function table for the Table class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Table" is used instead. * Returned Value: * A pointer to the new Table. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTable *new; /* Pointer to the new Table */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Table. In this case the Table belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstTable ); vtab = &class_vtab; name = "Table"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitTableVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Table. */ new = astLoadKeyMap( mem, size, (AstKeyMapVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Table" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* The number of rows. */ new->nrow = astReadInt( channel, "nrow", 0 ); /* KeyMap holding columns definitions. */ new->columns = astReadObject( channel, "columns", NULL ); /* KeyMap holding parameter definitions. */ new->parameters = astReadObject( channel, "params", NULL ); /* If an error occurred, clean up by deleting the new Table. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Table pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astAddColumn_( AstTable *this, const char *name, int type, int ndim, int *dims, const char *unit, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Table,AddColumn))(this,name,type,ndim,dims,unit,status); } void astAddParameter_( AstTable *this, const char *name, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Table,AddParameter))(this,name,status); } void astRemoveColumn_( AstTable *this, const char *name, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Table,RemoveColumn))(this,name,status); } void astRemoveParameter_( AstTable *this, const char *name, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Table,RemoveParameter))(this,name,status); } void astRemoveRow_( AstTable *this, int index, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Table,RemoveRow))(this,index,status); } void astPurgeRows_( AstTable *this, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Table,PurgeRows))(this,status); } int astGetNcolumn_( AstTable *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetNcolumn))( this, status ); } int astGetNparameter_( AstTable *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetNparameter))( this, status ); } const char *astColumnName_( AstTable *this, int index, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Table,ColumnName))(this,index,status); } const char *astParameterName_( AstTable *this, int index, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Table,ParameterName))(this,index,status); } int astGetColumnType_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetColumnType))(this,column,status); } const char *astGetColumnUnit_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Table,GetColumnUnit))(this,column,status); } int astGetColumnLenC_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetColumnLenC))(this,column,status); } int astGetColumnLength_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetColumnLength))(this,column,status); } int astGetColumnNdim_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,GetColumnNdim))(this,column,status); } void astColumnShape_( AstTable *this, const char *column, int mxdim, int *ndim, int *dims, int *status ){ if ( !astOK ) return; (**astMEMBER(this,Table,ColumnShape))( this, column, mxdim, ndim, dims, status ); } AstKeyMap *astColumnProps_( AstTable *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Table,ColumnProps))(this,status); } AstKeyMap *astParameterProps_( AstTable *this, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Table,ParameterProps))(this,status); } int astHasColumn_( AstTable *this, const char *column, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,HasColumn))(this,column,status); } int astHasParameter_( AstTable *this, const char *parameter, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Table,HasParameter))(this,parameter,status); } ./ast-7.3.3/dsbspecframe.c0000644000175000017500000034660312262533650013760 0ustar olesoles/* *class++ * Name: * DSBSpecFrame * Purpose: * Dual sideband spectral coordinate system description. * Constructor Function: c astDSBSpecFrame f AST_DSBSPECFRAME * Description: * A DSBSpecFrame is a specialised form of SpecFrame which represents * positions in a spectrum obtained using a dual sideband instrument. * Such an instrument produces a spectrum in which each point contains * contributions from two distinctly different frequencies, one from * the "lower side band" (LSB) and one from the "upper side band" (USB). * Corresponding LSB and USB frequencies are connected by the fact * that they are an equal distance on either side of a fixed central * frequency known as the "Local Oscillator" (LO) frequency. * * When quoting a position within such a spectrum, it is necessary to * indicate whether the quoted position is the USB position or the * corresponding LSB position. The SideBand attribute provides this * indication. Another option that the SideBand attribute provides is * to represent a spectral position by its topocentric offset from the * LO frequency. * * In practice, the LO frequency is specified by giving the distance * from the LO frequency to some "central" spectral position. Typically * this central position is that of some interesting spectral feature. * The distance from this central position to the LO frequency is known * as the "intermediate frequency" (IF). The value supplied for IF can * be a signed value in order to indicate whether the LO frequency is * above or below the central position. * Inheritance: * The DSBSpecFrame class inherits from the SpecFrame class. * Attributes: * In addition to those attributes common to all SpecFrames, every * DSBSpecFrame also has the following attributes: * * - AlignSideBand: Should alignment occur between sidebands? * - DSBCentre: The central position of interest. * - IF: The intermediate frequency used to define the LO frequency. * - ImagFreq: The image sideband equivalent of the rest frequency. * - SideBand: Indicates which sideband the DSBSpecFrame represents. * Functions: c The DSBSpecFrame class does not define any new functions beyond those f The DSBSpecFrame class does not define any new routines beyond those * which are applicable to all SpecFrames. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * History: * 5-AUG-2004 (DSB): * Original version. * 7-OCT-2004 (DSB): * Fixed SetAttrib code which assigns values to SideBand. Previously * all supplied values were ignored, leaving SideBand unchanged. * 2-SEP-2005 (DSB): * Allow conversion in any Domain within TopoMap (sometimes * SpecFrames have a new Domain set which is not equal to SPECTRUM"). * 12-SEP-2005 (DSB): * Set all attributes required to described the RestFreq value * before determining Mapping from RestFreq to ImagFreq in * GetImageFreq. * 2-DEC-2005 (DSB): * Change default Domain from SPECTRUM to DSBSPECTRUM * 3-APR-2006 (DSB): * Fix memory leak in astLoadDSBSpecFrame. * 6-OCT-2006 (DSB): * Guard against annulling null pointers in subFrame. * 27-OCT-2006 (DSB): * Added AlignSideBand attribute. * 31-OCT-2006 (DSB): * Use AlignSideBand attribute in SubFrame only if we are not * currently restoring a FrameSet's integrity. * 31-JAN-2007 (DSB): * Modified so that a DSBSpecFrame can be used as a template to find a * DSBSpecFrame (or SpecFrame) contained within a CmpFrame. This * involves changes in Match. * 1-MAY-2007 (DSB): * The default for AlignSideband has been changed from 1 to 0. * 8-MAY-2007 (DSB): * Correct initialisation of alignsideband in astInitDSBSpecFrame_. * 19-OCT-2007 (DSB): * Ignore SideBand alignment if the AlignSideBand attribute is zero * in either the target or the template. * 16-JAN-2007 (DSB): * Modify SubFrame so that DSBSpecFrames are aligned in the * observed sideband (LSB or USB) rather than always being aligned * in the USB. * 12-FEB-2010 (DSB): * Report an error if the local oscillator frequency looks silly * (specifically, if it less than the absolute intermediate frequency). * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. *class-- * Implementation Deficiencies: * - The default values for System and StdOfRest inherited from the * SpecFrame class are "Wave" and "Heliocentric". These are not * usually what is wanted for a DSB instrument. Defaults such as * "Freq" and "Topo" may be more appropriate. However, changing the * defaults inherited from SpecFrame may cause problems in the * astConvert algorithm. The astConvertX function in frame.c includes * the following implementation deficiency warning: "One likely * problem is with attributes which default in both the source and * destination Frames. This means they also default in the common * coordinate system. If these default values were to differ when * matching different target Frames, however, we would be in trouble, * because the common coordinate system would not then be remaining * constant. The longer-term solution to this is probably to provide * some mechanism to "fix" all attribute values for a Frame, by taking * any attributes that are un-set and explicitly setting a firm value * (equal to the default) so they cannot then change". So the defaults * should probably be left unchanged until this fix is made. */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS DSBSpecFrame #define BADSB -9999 #define FIRST_SB -1 #define LSB -1 #define LO 0 #define USB 1 #define LAST_SB 1 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory management facilities */ #include "object.h" /* Base Object class */ #include "channel.h" /* I/O channels */ #include "specframe.h" /* Spectral frames (parent class) */ #include "unit.h" /* Unit handling */ #include "cmpmap.h" /* Compound Mappings */ #include "unitmap.h" /* Unit Mappings */ #include "winmap.h" /* Window Mappings */ #include "dsbspecframe.h" /* Interface definition for this class */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static const char *(* parent_getlabel)( AstFrame *, int, int * ); static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * ); static const char *(* parent_getdomain)( AstFrame *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->GetLabel_Buff[ 0 ] = 0; \ /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(DSBSpecFrame) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(DSBSpecFrame,Class_Init) #define class_vtab astGLOBAL(DSBSpecFrame,Class_Vtab) #define getattrib_buff astGLOBAL(DSBSpecFrame,GetAttrib_Buff) #define getlabel_buff astGLOBAL(DSBSpecFrame,GetLabel_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Define the thread-specific globals for this class. */ /* Buffer returned by GetAttrib. */ static char getattrib_buff[ 101 ]; /* Default Label string buffer */ static char getlabel_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstDSBSpecFrameVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstDSBSpecFrame *astDSBSpecFrameId_( const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *TopoMap( AstDSBSpecFrame *, int, const char *, int * ); static AstMapping *ToLOMapping( AstDSBSpecFrame *, const char *, int * )__attribute__((unused)); static AstMapping *ToLSBMapping( AstDSBSpecFrame *, const char *, int * ); static AstMapping *ToUSBMapping( AstDSBSpecFrame *, const char *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetLabel( AstFrame *, int, int * ); static double GetImagFreq( AstDSBSpecFrame *, int * ); static double GetLO( AstDSBSpecFrame *, const char *, const char *, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void Overlay( AstFrame *, const int *, AstFrame *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void VerifyAttrs( AstDSBSpecFrame *, const char *, const char *, const char *, int * ); static const char *GetDomain( AstFrame *, int * ); static double GetIF( AstDSBSpecFrame *, int * ); static int TestIF( AstDSBSpecFrame *, int * ); static void ClearIF( AstDSBSpecFrame *, int * ); static void SetIF( AstDSBSpecFrame *, double, int * ); static double GetDSBCentre( AstDSBSpecFrame *, int * ); static int TestDSBCentre( AstDSBSpecFrame *, int * ); static void ClearDSBCentre( AstDSBSpecFrame *, int * ); static void SetDSBCentre( AstDSBSpecFrame *, double, int * ); static int GetSideBand( AstDSBSpecFrame *, int * ); static int TestSideBand( AstDSBSpecFrame *, int * ); static void ClearSideBand( AstDSBSpecFrame *, int * ); static void SetSideBand( AstDSBSpecFrame *, int, int * ); static int GetAlignSideBand( AstDSBSpecFrame *, int * ); static int TestAlignSideBand( AstDSBSpecFrame *, int * ); static void ClearAlignSideBand( AstDSBSpecFrame *, int * ); static void SetAlignSideBand( AstDSBSpecFrame *, int, int * ); /* Member functions. */ /* ================= */ static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the astClearAttrib protected * method inherited from the SpecFrame class). * Description: * This function clears the value of a specified attribute for a * DSBSpecFrame, so that the default value will subsequently be used. * Parameters: * this * Pointer to the DSBSpecFrame. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the DSBSpecFrame structure. */ this = (AstDSBSpecFrame *) this_object; /* Check the attribute name and clear the appropriate attribute. */ /* DSBCentre. */ /* ---------- */ if ( !strcmp( attrib, "dsbcentre" ) ) { astClearDSBCentre( this ); /* IF */ /* -- */ } else if ( !strcmp( attrib, "if" ) ) { astClearIF( this ); /* SideBand */ /* -------- */ } else if ( !strcmp( attrib, "sideband" ) ) { astClearSideBand( this ); /* AlignSideBand */ /* ------------- */ } else if ( !strcmp( attrib, "alignsideband" ) ) { astClearAlignSideBand( this ); /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then report an error. */ } else if ( !strcmp( attrib, "imagfreq" ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the protected astGetAttrib * method inherited from the SpecFrame class). * Description: * This function returns a pointer to the value of a specified * attribute for a DSBSpecFrame, formatted as a character string. * Parameters: * this * Pointer to the DSBSpecFrame. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the DSBSpecFrame, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the DSBSpecFrame. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ AstMapping *tmap; /* Ptr to Mapping from topofreq to this */ const char *result; /* Pointer value to return */ double dval; /* Attribute value */ double dtemp; /* Attribute value */ int ival; /* Attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the SpecFrame structure. */ this = (AstDSBSpecFrame *) this_object; /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* DSBCentre */ /* --------- */ if ( !strcmp( attrib, "dsbcentre" ) ) { /* Get the value as topocentric frequency in Hz. */ dval = astGetDSBCentre( this ); /* Find the Mapping from topocentric frequency in Hz to the spectral system described by this SpecFrame. */ tmap = TopoMap( this, 0, "astGetAttrib", status ); if ( astOK ) { /* Transform the internal value from topocentric frequency into the required system. */ astTran1( tmap, 1, &dval, 1, &dtemp ); if( dtemp == AST__BAD ) { astError( AST__INTER, "astGetAttrib(%s): Cannot convert DSBCentre " "value from topocentric frequency to the required " "system.", status, astGetClass( this ) ); } else { /* Format it. */ (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dtemp ); result = getattrib_buff; } tmap = astAnnul( tmap ); } /* IF */ /* -- */ } else if ( !strcmp( attrib, "if" ) ) { dval = astGetIF( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval*1.0E-9 ); result = getattrib_buff; } /* ImagFreq */ /* -------- */ } else if ( !strcmp( attrib, "imagfreq" ) ) { dval = astGetImagFreq( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval*1.0E-9 ); result = getattrib_buff; } /* SideBand */ /* -------- */ } else if ( !strcmp( attrib, "sideband" ) ) { ival = astGetSideBand( this ); if ( astOK ) { result = ( ival == USB ) ? "USB" : (( ival == LO ) ? "LO" : "LSB" ); } /* AlignSideBand */ /* ------------- */ } else if ( !strcmp( attrib, "alignsideband" ) ) { ival = astGetAlignSideBand( this ) ? 1 : 0; if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static const char *GetDomain( AstFrame *this_frame, int *status ) { /* * Name: * GetDomain * Purpose: * Obtain a pointer to the Domain attribute string for a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * const char *GetDomain( AstFrame *this, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the astGetDomain protected * method inherited from the SpecFrame class). * Description: * This function returns a pointer to the Domain attribute string * for a DSBSpecFrame. * Parameters: * this * Pointer to the DSBSpecFrame. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a constant null-terminated string containing the * Domain value. * Notes: * - The returned pointer or the string it refers to may become * invalid following further invocation of this function or * modification of the DSBSpecFrame. * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. */ /* Local Variables: */ AstDSBSpecFrame *this; /* Pointer to DSBSpecFrame structure */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the DSBSpecFrame structure. */ this = (AstDSBSpecFrame *) this_frame; /* If a Domain attribute string has been set, invoke the parent method to obtain a pointer to it. */ if ( astTestDomain( this ) ) { result = (*parent_getdomain)( this_frame, status ); /* Otherwise, provide a pointer to a suitable default string. */ } else { result = "DSBSPECTRUM"; } /* Return the result. */ return result; } static double GetImagFreq( AstDSBSpecFrame *this, int *status ) { /* *+ * Name: * astGetImagFreq * Purpose: * Get the value of the ImagFreq attribute. * Type: * Protected virtual function. * Synopsis: * #include "dsbspecframe.h" * double GetImagFreq( AstDSBSpecFrame *this ) * Class Membership: * DSBSpecFrame method. * Description: * This function returns the image sideband frequency corresponding to * the rest frequency. * Parameters: * this * Pointer to the Frame. * Returned Value: * The required frequency, in Hz. * Notes: * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstDSBSpecFrame *rf_frame;/* DSBSpecFrame describing the rest frequency */ AstMapping *map; /* Pointer to "Observed to Image" mapping */ double result; /* The returned frequency */ double rf; /* Rest frequency in observed sideband */ int sb; /* SideBand value */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* The RestFreq attribute is an observed sideband frequency in the source's standard of rest, measured in Hz. Temporaily set attributes to these values. Create a copy of the supplied DSBSpecFrame and set its attributes to these values. */ rf_frame = astCopy( this ); astSetStdOfRest( rf_frame, AST__SCSOR ); astSetSystem( rf_frame, AST__FREQ ); astSetUnit( rf_frame, 0, "Hz" ); astSetC( rf_frame, "SideBand", "observed" ); /* Create a Mapping which transforms positions from the observed to the image sideband. */ sb = astGetSideBand( rf_frame ); if( sb == USB ) { map = ToLSBMapping( rf_frame, "astGetImagFreq", status ); } else if( sb == LSB ) { map = ToUSBMapping( rf_frame, "astGetImagFreq", status ); } else { map = NULL; astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " "(%d) encountered (internal AST programming error).", status, astGetClass( this ), sb ); } /* Get the rest frequency in Hz, and transform it using the above Mapping. */ rf = astGetRestFreq( rf_frame ); astTran1( map, 1, &rf, 1, &result ); /* Free resources */ map = astAnnul( map ); rf_frame = astAnnul( rf_frame ); /* If an error has occurrred, return AST__BAD. */ if( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static const char *GetLabel( AstFrame *this, int axis, int *status ) { /* * Name: * GetLabel * Purpose: * Access the Label string for a DSBSpecFrame axis. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * const char *GetLabel( AstFrame *this, int axis, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the astGetLabel method inherited * from the SpecFrame class). * Description: * This function returns a pointer to the Label string for a specified axis * of a DSBSpecFrame. * Parameters: * this * Pointer to the SpecFrame. * axis * Axis index (zero-based) identifying the axis for which information is * required. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a constant null-terminated character string containing the * requested information. * Notes: * - A NULL pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *result; /* Pointer to label string */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Initialise. */ result = NULL; /* Validate the axis index. */ astValidateAxis( this, axis, 1, "astGetLabel" ); /* Invoke the parent astGetLabel method to obtain a pointer to it. */ result = (*parent_getlabel)( this, axis, status ); /* Check if this is a default value. If so, append a string indicating the sideband. */ if ( !astTestLabel( this, axis ) ) { /* If OK, supply a pointer to a suitable default label string. */ sprintf( getlabel_buff, "%s (%s)", result, astGetAttrib( this, "sideband" ) ); result = getlabel_buff; } /* Return the result. */ return result; } static double GetLO( AstDSBSpecFrame *this, const char *check_msg, const char *method, int *status ) { /* * Name: * GetLO * Purpose: * Get the Local Oscillator frequency. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * double GetLO( AstDSBSpecFrame *this, const char *check_msg, * const char *method, int *status ) * Class Membership: * DSBSpecFrame method. * Description: * This function returns the local oscillator frequency in topocentric * frequency. * Parameters: * this * Pointer to the Frame. * check_msg * If not NULL, an error will be reported if either the DSBCentre * or IF attribute has not been set to an explicit value. In this * case, the error message will include the supplied text. * method * The name of the calling method - used in error messages. * status * Pointer to the inherited status value. * Returned Value: * The local oscillator frequency, in Hz. * Notes: * - An error is reported if the local oscillator frequency looks * un-physical (specifically, if it is less than the absolute value of * the intermediate frequency). * - A value of AST__BAD will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ double f_if; /* Intermediate frequency (topo,HZ) */ double result; /* The returned frequency */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* If required, check that explicit values have been assigned to the required attributes (i.e. report an error if a default value would be used for either attribute). */ if( check_msg ) VerifyAttrs( this, check_msg, "IF DSBCentre", method, status ); /* The local oscillator is the sum of the intermediate frequency and the observation centre frequency. */ f_if = astGetIF( this ); result = astGetDSBCentre( this ) + f_if; /* Check the local oscillator frequency is no smaller than the absolute intermediate frequency. */ if( result < fabs( f_if ) && astOK ) { astError( AST__ATTIN, "%s(%s): The local oscillator frequency (%g Hz) " "is too low (less than the intermediate frequency: %g Hz).", status, method, astGetClass( this ), result, fabs( f_if ) ); astError( AST__ATTIN, " This could be caused by a bad value for" " either the IF attribute (currently %g Hz) or the DSBCentre " "attribute (currently %g Hz).", status, f_if, astGetDSBCentre( this ) ); } /* If an error has occurrred, return AST__BAD. */ if( !astOK ) result = AST__BAD; /* Return the result. */ return result; } void astInitDSBSpecFrameVtab_( AstDSBSpecFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitDSBSpecFrameVtab * Purpose: * Initialise a virtual function table for a DSBSpecFrame. * Type: * Protected function. * Synopsis: * #include "dsbspecframe.h" * void astInitDSBSpecFrameVtab( AstDSBSpecFrameVtab *vtab, const char *name ) * Class Membership: * DSBSpecFrame vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the DSBSpecFrame class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitSpecFrameVtab( (AstSpecFrameVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsADSBSpecFrame) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstSpecFrameVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearDSBCentre = ClearDSBCentre; vtab->TestDSBCentre = TestDSBCentre; vtab->GetDSBCentre = GetDSBCentre; vtab->SetDSBCentre = SetDSBCentre; vtab->ClearIF = ClearIF; vtab->TestIF = TestIF; vtab->GetIF = GetIF; vtab->SetIF = SetIF; vtab->ClearSideBand = ClearSideBand; vtab->TestSideBand = TestSideBand; vtab->GetSideBand = GetSideBand; vtab->SetSideBand = SetSideBand; vtab->ClearAlignSideBand = ClearAlignSideBand; vtab->TestAlignSideBand = TestAlignSideBand; vtab->GetAlignSideBand = GetAlignSideBand; vtab->SetAlignSideBand = SetAlignSideBand; vtab->GetImagFreq = GetImagFreq; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; frame = (AstFrameVtab *) vtab; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_getdomain = frame->GetDomain; frame->GetDomain = GetDomain; parent_overlay = frame->Overlay; frame->Overlay = Overlay; parent_match = frame->Match; frame->Match = Match; parent_subframe = frame->SubFrame; frame->SubFrame = SubFrame; parent_getlabel = frame->GetLabel; frame->GetLabel = GetLabel; /* Declare the class delete function.*/ astSetDump( vtab, Dump, "DSBSpecFrame", "Dual sideband spectral axis" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int Match( AstFrame *template_frame, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * Match * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * int Match( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the protected astMatch method * inherited from the SpecFrame class). * Description: * This function matches a "template" DSBSpecFrame to a "target" Frame and * determines whether it is possible to convert coordinates between them. * If it is, a mapping that performs the transformation is returned along * with a new Frame that describes the coordinate system that results when * this mapping is applied to the "target" coordinate system. In addition, * information is returned to allow the axes in this "result" Frame to be * associated with the corresponding axes in the "target" and "template" * Frames from which they are derived. * Parameters: * template * Pointer to the template DSBSpecFrame. This describes the coordinate * system (or set of possible coordinate systems) into which we wish to * convert our coordinates. * target * Pointer to the target Frame. This describes the coordinate system in * which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case. * template_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the template DSBSpecFrame axis from * which it is derived. If it is not derived from any template * DSBSpecFrame axis, a value of -1 will be returned instead. * target_axes * Address of a location where a pointer to int will be returned if the * requested coordinate conversion is possible. This pointer will point * at a dynamically allocated array of integers with one element for each * axis of the "result" Frame (see below). It must be freed by the caller * (using astFree) when no longer required. * * For each axis in the result Frame, the corresponding element of this * array will return the index of the target Frame axis from which it * is derived. If it is not derived from any target Frame axis, a value * of -1 will be returned instead. * map * Address of a location where a pointer to a new Mapping will be * returned if the requested coordinate conversion is possible. If * returned, the forward transformation of this Mapping may be used to * convert coordinates between the "target" Frame and the "result" * Frame (see below) and the inverse transformation will convert in the * opposite direction. * result * Address of a location where a pointer to a new Frame will be returned * if the requested coordinate conversion is possible. If returned, this * Frame describes the coordinate system that results from applying the * returned Mapping (above) to the "target" coordinate system. In * general, this Frame will combine attributes from (and will therefore * be more specific than) both the target and the template Frames. In * particular, when the template allows the possibility of transformaing * to any one of a set of alternative coordinate systems, the "result" * Frame will indicate which of the alternatives was used. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if the requested coordinate conversion is * possible. Otherwise zero is returned (this will not in itself result in * an error condition). * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * This implementation addresses the matching of a DSBSpecFrame class * object to any other class of Frame. A DSBSpecFrame will match any class * of DSBSpecFrame (i.e. possibly from a derived class) but will not match * a less specialised class of Frame (except for a SpecFrame). */ /* Local Variables: */ AstDSBSpecFrame *template; /* Pointer to template DSBSpecFrame structure */ AstFrame *frame0; /* Pointer to Frame underlying axis 0 */ int iaxis0; /* Axis index underlying axis 0 */ int match; /* Coordinate conversion possible? */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain a pointer to the template DSBSpecFrame structure. */ template = (AstDSBSpecFrame *) template_frame; /* The first criterion for a match is that the template matches as a SpecFrame class object. This ensures that the number of axes (1) and domain, class, etc. of the target Frame are suitable. Invoke the parent "astMatch" method to verify this. */ match = (*parent_match)( template_frame, target, matchsub, template_axes, target_axes, map, result, status ); /* If a match was found, the target Frame must be (or contain) a SpecFrame, but this target SpecFrame may be a simple SpecFrame rather than a DSBSpecFrame. We use the returned objects directly if the target SpecFrame is not a DSBSpecFrame. So if a DSBSpecFrame and a base SpecFrame are aligned, this will result in the DSBSpecFrame behaving as a normal SpecFrame. */ if ( astOK && match ) { /* Get the primary Frame associated with the matching target axis. */ astPrimaryFrame( target, (*target_axes)[ 0 ], &frame0, &iaxis0 ); /* Skip this next section, thus retaining the values returned by the parent Match method above, if the target axis is not a DSBSpecFrame. */ if( astIsADSBSpecFrame( frame0 ) ) { /* Annul the returned objects, which are not needed, but keep the axis association arrays which already hold the correct values. */ *map = astAnnul( *map ); *result = astAnnul( *result ); /* Use the target's "astSubFrame" method to create a new Frame (the result Frame) with a copy of of the target axis. This process also overlays the template attributes on to the target Frame and returns a Mapping between the target and result Frames which effects the required coordinate conversion. */ match = astSubFrame( target, template, 1, *target_axes, *template_axes, map, result ); } /* Free resources. */ frame0 = astAnnul( frame0 ); } /* If an error occurred, or conversion to the result Frame's coordinate system was not possible, then free all memory, annul the returned objects, and reset the returned value. */ if ( !astOK || !match ) { if( *template_axes ) *template_axes = astFree( *template_axes ); if( *target_axes ) *target_axes = astFree( *target_axes ); if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } static void Overlay( AstFrame *template, const int *template_axes, AstFrame *result, int *status ) { /* * Name: * Overlay * Purpose: * Overlay the attributes of a template DSBSpecFrame on to another Frame. * Type: * Private function. * Synopsis: * #include "specframe.h" * void Overlay( AstFrame *template, const int *template_axes, * AstFrame *result, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the protected astOverlay method * inherited from the SpecFrame class). * Description: * This function overlays attributes of a DSBSpecFrame (the "template") on to * another Frame, so as to over-ride selected attributes of that second * Frame. Normally only those attributes which have been specifically set * in the template will be transferred. This implements a form of * defaulting, in which a Frame acquires attributes from the template, but * retains its original attributes (as the default) if new values have not * previously been explicitly set in the template. * * Note that if the result Frame is a DSBSpecFrame and a change of spectral * coordinate system occurs as a result of overlaying its System * attribute, then some of its original attribute values may no * longer be appropriate (e.g. the Title, or attributes describing * its axes). In this case, these will be cleared before overlaying * any new values. * Parameters: * template * Pointer to the template DSBSpecFrame, for which values should have been * explicitly set for any attribute which is to be transferred. * template_axes * Pointer to an array of int, with one element for each axis of the * "result" Frame (see below). For each axis in the result frame, the * corresponding element of this array should contain the (zero-based) * index of the template axis to which it corresponds. This array is used * to establish from which template axis any axis-dependent attributes * should be obtained. * * If any axis in the result Frame is not associated with a template * axis, the corresponding element of this array should be set to -1. * * If a NULL pointer is supplied, the template and result axis * indicies are assumed to be identical. * result * Pointer to the Frame which is to receive the new attribute values. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - In general, if the result Frame is not from the same class as the * template DSBSpecFrame, or from a class derived from it, then attributes may * exist in the template DSBSpecFrame which do not exist in the result Frame. * In this case, these attributes will not be transferred. */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the parent class astOverlay method to transfer attributes inherited from the parent class. */ (*parent_overlay)( template, template_axes, result, status ); /* Check if the result Frame is a DSBSpecFrame or from a class derived from DSBSpecFrame. If not, we cannot transfer DSBSpecFrame attributes to it as it is insufficiently specialised. In this case simply omit these attributes. */ if( astIsADSBSpecFrame( result ) && astOK ) { /* Define macros that test whether an attribute is set in the template and, if so, transfers its value to the result. */ #define OVERLAY(attribute) \ if ( astTest##attribute( template ) ) { \ astSet##attribute( result, astGet##attribute( template ) ); \ } /* Use the macro to transfer each DSBSpecFrame attribute in turn. */ OVERLAY(DSBCentre) OVERLAY(IF) OVERLAY(SideBand) OVERLAY(AlignSideBand) } /* Undefine macros local to this function. */ #undef OVERLAY } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * void SetAttrib( AstObject *this, const char *setting ) * Class Membership: * DSBSpecFrame member function (over-rides the astSetAttrib protected * method inherited from the SpecFrame class). * Description: * This function assigns an attribute value for a DSBSpecFrame, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the DSBSpecFrame. * setting * Pointer to a null-terminated string specifying the new attribute * value. */ /* Local Variables: */ AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ AstMapping *tmap; /* Ptr to Mapping from this to topofreq */ AstMapping *umap; /* Ptr to Mapping between units */ double dtemp; /* Attribute value */ double dval; /* Attribute value */ int ival; /* Attribute value */ int len; /* Length of setting string */ int nc; /* Used length */ int off; /* Offset to start of string */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the DSBSpecFrame structure. */ this = (AstDSBSpecFrame *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* DSBCentre */ /* --------- */ if ( strstr( setting, "dsbcentre=" ) ) { /* Without any units indication - assume it is supplied in the system of the DSBSpecFrame. */ int ok = 0; if( nc = 0, ( 1 == astSscanf( setting, "dsbcentre= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { ok = 1; /* With units indication. Is there a Mapping from the supplied units to the units used by the DSBSpecFrame? If so, use the Mapping to convert the supplied value to the required units. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "dsbcentre= %lg %n%*s %n", &dval, &off, &nc ) ) && ( nc >= len ) ) { if( ( umap = astUnitMapper( setting + off, astGetUnit( this, 0 ), NULL, NULL ) ) ) { astTran1( umap, 1, &dval, 1, &dtemp ); dval = dtemp; umap = astAnnul( umap ); if( astOK && dval != AST__BAD ) ok = 1; /* Otherwise report an error. */ } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): Value supplied for " "attribute \"DSBCentre\" (%s) uses units which are " "inappropriate for the current spectral system (%s).", status, astGetClass( this ), setting + 10, astGetTitle( this ) ); } } /* Convert the value from the supplied system to topocentric frequency in Hx, and store. */ if( ok ) { /* Find the Mapping from the spectral system described by this SpecFrame to topocentric frequency in Hz. */ tmap = TopoMap( this, 1, "astSetAttrib", status ); if ( astOK ) { /* Transform the supplied value to topocentric frequency. */ astTran1( tmap, 1, &dval, 1, &dtemp ); if( dtemp == AST__BAD ) { astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " "invalid for a %s.", status, astGetClass( this ), setting, astGetClass( this ) ); } else { /* Store it. */ astSetDSBCentre( this, dtemp ); } tmap = astAnnul( tmap ); } } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " "invalid for a %s.", status, astGetClass( this ), setting, astGetClass( this ) ); } /* IF */ /* -- */ /* Without any units indication - assume GHz. Convert to Hz for storage. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "if= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetIF( this, dval*1.0E9 ); /* With units indication. */ } else if ( nc = 0, ( 1 == astSscanf( setting, "if= %lg %n%*s %n", &dval, &off, &nc ) ) && ( nc >= len ) ) { /* Is there a Mapping from the supplied units to Hz? If so, use the Mapping to convert the supplied value to Hz. */ if( ( umap = astUnitMapper( setting + off, "Hz", NULL, NULL ) ) ) { astTran1( umap, 1, &dval, 1, &dtemp ); umap = astAnnul( umap ); /* Otherwise report an error. */ } else if( astOK ) { astError( AST__ATTIN, "astSetAttrib(%s): Intermediate frequency given " "in an inappropriate system of units \"%g %s\".", status, astGetClass( this ), dval, setting + off ); } /* Set the intermediate frequency. */ astSetIF( this, dtemp ); /* SideBand */ /* -------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "sideband= %n%*s %n", &ival, &nc ) ) && ( nc >= len ) ) { if( astChrMatch( "usb", setting+ival ) ) { astSetSideBand( this, USB ); } else if( astChrMatch( "lsb", setting+ival ) ) { astSetSideBand( this, LSB ); } else if( astChrMatch( "lo", setting+ival ) ) { astSetSideBand( this, LO ); } else if( astChrMatch( "observed", setting+ival ) ) { astSetSideBand( this, ( astGetIF( this ) > 0 ) ? LSB : USB ); } else if( astChrMatch( "image", setting+ival ) ) { astSetSideBand( this, ( astGetIF( this ) <= 0 ) ? LSB : USB ); } else { astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " "invalid for a %s.", status, astGetClass( this ), setting, astGetClass( this ) ); } /* AlignSideBand */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "alignsideband= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetAlignSideBand( this, ival ); /* Read-only attributes. */ /* --------------------- */ /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* Use this macro to report an error if a read-only attribute has been specified. */ } else if ( MATCH( "imagfreq" ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Pass any unrecognised setting to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static int SubFrame( AstFrame *target_frame, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* * Name: * SubFrame * Purpose: * Select axes from a DSBSpecFrame and convert to the new coordinate * system. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * int SubFrame( AstFrame *target, AstFrame *template, * int result_naxes, const int *target_axes, * const int *template_axes, AstMapping **map, * AstFrame **result, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the protected astSubFrame * method inherited from the SpecFrame class). * Description: * This function selects a requested sub-set (or super-set) of the axes * from a "target" DSBSpecFrame and creates a new Frame with copies of * the selected axes assembled in the requested order. It then * optionally overlays the attributes of a "template" Frame on to the * result. It returns both the resulting Frame and a Mapping that * describes how to convert between the coordinate systems described by * the target and result Frames. If necessary, this Mapping takes * account of any differences in the Frames' attributes due to the * influence of the template. * Parameters: * target * Pointer to the target DSBSpecFrame, from which axes are to be * selected. * template * Pointer to the template Frame, from which new attributes for the * result Frame are to be obtained. Optionally, this may be NULL, in * which case no overlaying of template attributes will be performed. * result_naxes * Number of axes to be selected from the target Frame. This number may * be greater than or less than the number of axes in this Frame (or * equal). * target_axes * Pointer to an array of int with result_naxes elements, giving a list * of the (zero-based) axis indices of the axes to be selected from the * target DSBSpecFrame. The order in which these are given determines * the order in which the axes appear in the result Frame. If any of the * values in this array is set to -1, the corresponding result axis will * not be derived from the target Frame, but will be assigned default * attributes instead. * template_axes * Pointer to an array of int with result_naxes elements. This should * contain a list of the template axes (given as zero-based axis indices) * with which the axes of the result Frame are to be associated. This * array determines which axes are used when overlaying axis-dependent * attributes of the template on to the result. If any element of this * array is set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not used and * a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned Mapping. * The forward transformation of this Mapping will describe how to * convert coordinates from the coordinate system described by the target * DSBSpecFrame to that described by the result Frame. The inverse * transformation will convert in the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * status * Pointer to the inherited status variable. * Returned Value: * A non-zero value is returned if coordinate conversion is possible * between the target and the result Frame. Otherwise zero is returned and * *map and *result are returned as NULL (but this will not in itself * result in an error condition). In general, coordinate conversion should * always be possible if no template Frame is supplied but may not always * be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * Implementation Notes: * - This implementation addresses the selection of axes from a * DSBSpecFrame object. This results in another object of the same class * only if the single DSBSpecFrame axis is selected exactly once. * Otherwise, the result is a Frame class object which inherits the * DSBSpecFrame's axis information (if appropriate) but none of the other * properties of a DSBSpecFrame. * - In the event that a DSBSpecFrame results, the returned Mapping will * take proper account of the relationship between the target and result * coordinate systems. * - In the event that a Frame class object results, the returned Mapping * will only represent a selection/permutation of axes. * Implementation Deficiencies: * - Any axis selection is currently permitted. Probably this should be * restricted so that each axis can only be selected once. The * astValidateAxisSelection method will do this but currently there are bugs * in the CmpFrame class that cause axis selections which will not pass this * test. Install the validation when these are fixed. */ /* Local Variables: */ AstDSBSpecFrame *dsbresult;/* Pointer to the DSBSpecFrame result Frame */ AstDSBSpecFrame *dsbtarget;/* Pointer to the DSBSpecFrame target Frame */ AstMapping *map1; /* Intermediate Mapping */ AstMapping *map2; /* Intermediate Mapping */ AstMapping *map3; /* Intermediate Mapping */ int alignsb; /* Use sidebands to align the Frames? */ int match; /* Coordinate conversion is possible? */ int obs_sb; /* The observed sideband value */ int old_sb; /* The original Sideband value */ /* Initialise the returned values. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Invoke the astSubFrame method inherited from the parent SpecFrame class. This will (if possible) create a result Frame which is a DSBSpecFrame (since the supplied target Frame is a DSBSpecFrame). However, the Mapping from target to result Frame will take no account of any differences in the values of the attributes specific to the DSBSpecFrame class. */ match = (*parent_subframe)( target_frame, template, result_naxes, target_axes, template_axes, map, result, status ); /* If a match occurred, and the result and template Frames are both DSBSpecFrames, we now modify the Mapping to take account of DSBSpecFrame-specific attributes. */ if( match && template && astIsADSBSpecFrame( template ) && astIsADSBSpecFrame( *result ) ) { /* Get pointers to the two DSBSpecFrames */ dsbtarget = (AstDSBSpecFrame *) target_frame; /* See whether alignment occurs between sidebands. If the current call to this function is part of the process of restoring a FrameSet's integrity following changes to the FrameSet's current Frame, then we ignore the setting of the AlignSideBand attributes and use 1. This ensures that when the SideBand attribute (for instance) is changed via a FrameSet pointer, the Mappings within the FrameSet are modified to produce frequencies in the new SideBand. In most other cases, astronomers usually want to align the DSBSpecFrames as if they were basic SpecFrames (that is, ignoring the setting of the SideBand attribute). */ if( astGetFrameFlags( target_frame ) & AST__INTFLAG ) { alignsb = 1; } else { alignsb = astGetAlignSideBand( dsbtarget ) && astGetAlignSideBand( (AstDSBSpecFrame *) template ); } /* If we are aligning the sidebands we need to modify the Mapping returned above by the parent SubFrame method. The existing Mapping will convert between the spectral systems represented by the two DSBSpecFrames but will not take account of any difference in sidebands. */ if( alignsb ) { /* We assume that alignment occurs in the observed sideband. Determine which side band is the observed sideband in the target. */ old_sb = astGetSideBand( dsbtarget ); astSetC( dsbtarget, "SideBand", "observed" ); obs_sb = astGetSideBand( dsbtarget ); astSetSideBand( dsbtarget, old_sb ); /* Create a Mapping which transforms positions from the target to an exact copy of the target in which the SideBand attribute is set to the observed (USB or LSB) sideband. This will be a UnitMap if the target already represents the observed sideband. */ if( obs_sb == USB ) { map1 = ToUSBMapping( dsbtarget, "astSubFrame", status ); } else if( obs_sb == LSB ) { map1 = ToLSBMapping( dsbtarget, "astSubFrame", status ); } else { map1 = NULL; astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " "(%d) encountered (internal AST programming error).", status, astGetClass( target_frame ), obs_sb ); } /* Determine which side band is the observed sideband in the result. */ dsbresult = (AstDSBSpecFrame *) *result; old_sb = astGetSideBand( dsbresult ); astSetC( dsbresult, "SideBand", "observed" ); obs_sb = astGetSideBand( dsbresult ); astSetSideBand( dsbresult, old_sb ); /* Create a Mapping which transforms positions from the result to an exact copy of the result in which the SideBand attribute is set to the obserfed sideband. This will be a UnitMap if the target already represents the observed sideband. */ if( obs_sb == USB ) { map2 = ToUSBMapping( dsbresult, "astSubFrame", status ); } else if( obs_sb == LSB ) { map2 = ToLSBMapping( dsbresult, "astSubFrame", status ); } else { map2 = NULL; astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " "(%d) encountered (internal AST programming error).", status, astGetClass( target_frame ), obs_sb ); } /* Invert it to get the mapping from the observed sideband to the result. */ astInvert( map2 ); /* Form a Mapping which first maps target values to the observed sideband, then applies the Mapping returned by the parent SubFrame method in order to convert between spectral systems, and then converts from the observed sideband to the SideBand of the result. */ map3 = (AstMapping *) astCmpMap( map1, *map, 1, "", status ); map1 = astAnnul( map1 ); *map = astAnnul( *map ); map1 = (AstMapping *) astCmpMap( map3, map2, 1, "", status ); map3 = astAnnul( map3 ); map2 = astAnnul( map2 ); /* Returned the simplified Mapping. */ *map = astSimplify( map1 ); map1 = astAnnul( map1 ); } } /* If an error occurred or no match was found, annul the returned objects and reset the returned result. */ if ( !astOK || !match ) { if( *map ) *map = astAnnul( *map ); if( *result ) *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * DSBSpecFrame member function (over-rides the astTestAttrib protected * method inherited from the SpecFrame class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a DSBSpecFrame's attributes. * Parameters: * this * Pointer to the DSBSpecFrame. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the DSBSpecFrame structure. */ this = (AstDSBSpecFrame *) this_object; /* Check the attribute name and test the appropriate attribute. */ /* DSBCentre */ /* --------- */ if ( !strcmp( attrib, "dsbcentre" ) ) { result = astTestDSBCentre( this ); /* IF */ /* -- */ } else if ( !strcmp( attrib, "if" ) ) { result = astTestIF( this ); /* SideBand */ /* -------- */ } else if ( !strcmp( attrib, "sideband" ) ) { result = astTestSideBand( this ); /* AlignSideBand */ /* ------------- */ } else if ( !strcmp( attrib, "alignsideband" ) ) { result = astTestAlignSideBand( this ); /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then return zero. */ } else if ( !strcmp( attrib, "imagfreq" ) ) { result = 0; /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstMapping *ToLOMapping( AstDSBSpecFrame *this, const char *method, int *status ){ /* * Name: * ToLOMapping * Purpose: * Create a Mapping which transforms a DSBSpecFrame to offset from the * local oscillator frequency. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * AstMapping *ToLOMapping( AstDSBSpecFrame *this, const char *method, int *status ) * Class Membership: * DSBSpecFrame member function * Description: * This function returns a pointer to a new Mapping which transforms * positions in the supplied DSBSpecFrame into an offset from the local * oscillator frequency. This will be a UnitMap if the DSBSpecFrame * already represents offset from the local oscillator frequency. * Parameters: * this * Pointer to the DSBSpecFrame. * method * Pointer to a null-terminated string containing the name of the * public invoking method. This is only used in the construction of * error messages. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a new Mapping. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *fmap; /* LSB to USB (topo freq) */ AstMapping *map1; /* This to USB (topo freq) */ AstMapping *map2; /* This (LSB) to This (USB) */ AstMapping *result; /* Pointer to the returned Mapping */ AstMapping *tmap; /* This to topocentric freq */ double f_lo; /* Local oscillator freq (topo Hz) */ double f_in_a; /* First LSB or USB freq */ double f_in_b; /* Second LSB or USB freq */ double f_out_a; /* First LO freq */ double f_out_b; /* Second LO freq */ int sb; /* SideBand value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the DSBSpecFrame already represents LO offset, return a UnitMap.*/ sb = astGetSideBand( this ); if( sb == LO ) { result = (AstMapping *) astUnitMap( 1, "", status ); /* If the DSBSpecFrame represents the USB or LSB, create a suitable WinMap. */ } else { /* Find the Mapping from the spectral system described by this SpecFrame to topocentric frequency in Hz. */ tmap = TopoMap( this, 1, method, status ); /* Calculate the local oscillator frequency (topocentric in Hertz). */ f_lo = GetLO( this, "create a Mapping to upper sideband", "astGetImagFreq", status ); /* Create a 1D WinMap which converts f_in to f_out. */ if( sb == LSB ) { f_in_a = 0.0; f_in_b = f_lo; f_out_a = f_lo; f_out_b = 0.0; } else { f_in_a = 0.0; f_in_b = -f_lo; f_out_a = f_lo; f_out_b = 0.0; } fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); /* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); astInvert( tmap ); map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); /* Simplify */ result = astSimplify( map2 ); /* Free resources */ tmap = astAnnul( tmap ); fmap = astAnnul( fmap ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); } /* Return NULL if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstMapping *ToLSBMapping( AstDSBSpecFrame *this, const char *method, int *status ){ /* * Name: * ToLSBMapping * Purpose: * Create a Mapping which transforms a DSBSpecFrame to the lower * sideband. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * AstMapping *ToLSBMapping( AstDSBSpecFrame *this, const char *method, int *status ) * Class Membership: * DSBSpecFrame member function * Description: * This function returns a pointer to a new Mapping which transforms * positions in the supplied DSBSpecFrame to the lower sideband. This * will be a UnitMap if the DSBSpecFrame already represents the lower * sideband. * Parameters: * this * Pointer to the DSBSpecFrame. * method * Pointer to a null-terminated string containing the name of the * public invoking method. This is only used in the construction of * error messages. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a new Mapping. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *fmap; /* LSB to USB (topo freq) */ AstMapping *map1; /* This to USB (topo freq) */ AstMapping *map2; /* This (LSB) to This (USB) */ AstMapping *result; /* Pointer to the returned Mapping */ AstMapping *tmap; /* This to topocentric freq */ double f_lo; /* Local oscillator freq (topo Hz) */ double f_out_a; /* First LSB freq */ double f_out_b; /* Second LSB freq */ double f_in_a; /* First USB or LO freq */ double f_in_b; /* Second USB or LO freq */ int sb; /* SideBand value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the DSBSpecFrame already represents the LSB, return a UnitMap.*/ sb = astGetSideBand( this ); if( sb == LSB ) { result = (AstMapping *) astUnitMap( 1, "", status ); /* If the DSBSpecFrame represents the USB or LO offset, create a suitable WinMap. */ } else { /* Find the Mapping from the spectral system described by this SpecFrame to topocentric frequency in Hz. */ tmap = TopoMap( this, 1, method, status ); /* Calculate the local oscillator frequency (topocentric in Hertz). */ f_lo = GetLO( this, "create a Mapping to lower sideband", "astGetImagFreq", status ); /* Create a 1D WinMap which converts USB or LO to LSB. */ if( sb == USB ) { f_in_a = 0.0; f_in_b = 2*f_lo; f_out_a = 2*f_lo; f_out_b = 0.0; } else { f_in_a = 0.0; f_in_b = f_lo; f_out_a = f_lo; f_out_b = 0.0; } fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); /* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); astInvert( tmap ); map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); /* Simplify */ result = astSimplify( map2 ); /* Free resources */ tmap = astAnnul( tmap ); fmap = astAnnul( fmap ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); } /* Return NULL if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstMapping *TopoMap( AstDSBSpecFrame *this, int forward, const char *method, int *status ){ /* * Name: * TopoMap * Purpose: * Create a Mapping which transforms a DSBSpecFrame to topocentric * frequency. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * AstMapping *TopoMap( AstDSBSpecFrame *this, int forward, * const char *method, int *status ) * Class Membership: * DSBSpecFrame member function * Description: * This function returns a pointer to a new Mapping which transforms * positions in the supplied DSBSpecFrame to the corresponding * topocentric frequency values in Hz (or the inverse of this). * Parameters: * this * Pointer to the DSBSpecFrame. * forward * If zero, the calcuated Mapping is inverted before being returned. * method * Pointer to a null-terminated string containing the name of the * public invoking method. This is only used in the construction of * error messages. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a new Mapping. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *result; /* The returned Mapping */ AstFrameSet *fs; /* FrameSet connecting tf1 and tf2 */ AstSpecFrame *tf1; /* SpecFrame corresponding to this DSBSpecFrame */ AstSpecFrame *tf2; /* Topocentric frequency SpecFrame */ int template_axis; /* The axis to overlay */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Make a SpecFrame and then overlay the SpecFrame attributes of this DSBSpecFrame onto the new SpecFrame. This means it inherits the current values of things like ObsLon and ObsLat. */ tf1 = astSpecFrame( "", status ); template_axis = 0; (*parent_overlay)( (AstFrame *) this, &template_axis, (AstFrame *) tf1, status ); /* Copy this new SpecFrame and set its attributes to describe topocentric frequency in Hz. Ensure that alignment occurs in the topocentric Frame. */ astSetAlignStdOfRest( tf1, AST__TPSOR); tf2 = astCopy( tf1 ); astSetSystem( tf2, AST__FREQ ); astSetStdOfRest( tf2, AST__TPSOR ); astSetUnit( tf2, 0, "Hz" ); /* Find the Mapping from the spectral system described by this SpecFrame to topocentric frequency in Hz. */ fs = astConvert( tf1, tf2, "" ); if ( astOK ) { if( !fs ) { astError( AST__INTER, "%s(%s): Cannot convert DSBCentre " "value from the supplied system to topocentric frequency " "(internal AST programming error).", status, method, astGetClass( this ) ); } else { result = astGetMapping( fs, AST__BASE, AST__CURRENT ); if( !forward ) astInvert( result ); } fs = astAnnul( fs ); } /* Free resources */ tf1 = astAnnul( tf1 ); tf2 = astAnnul( tf2 ); /* Annul the result if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstMapping *ToUSBMapping( AstDSBSpecFrame *this, const char *method, int *status ){ /* * Name: * ToUSBMapping * Purpose: * Create a Mapping which transforms a DSBSpecFrame to the upper * sideband. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * AstMapping *ToUSBMapping( AstDSBSpecFrame *this, const char *method, int *status ) * Class Membership: * DSBSpecFrame member function * Description: * This function returns a pointer to a new Mapping which transforms * positions in the supplied DSBSpecFrame to the upper sideband. This * will be a UnitMap if the DSBSpecFrame already represents the upper * sideband. * Parameters: * this * Pointer to the DSBSpecFrame. * method * Pointer to a null-terminated string containing the name of the * public invoking method. This is only used in the construction of * error messages. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a new Mapping. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *fmap; /* LSB to USB (topo freq) */ AstMapping *map1; /* This to USB (topo freq) */ AstMapping *map2; /* This (LSB) to This (USB) */ AstMapping *result; /* Pointer to the returned Mapping */ AstMapping *tmap; /* This to topocentric freq */ double f_lo; /* Local oscillator freq (topo Hz) */ double f_in_a; /* First LSB or LO freq */ double f_in_b; /* Second LSB or LO freq */ double f_out_a; /* First USB freq */ double f_out_b; /* Second USB freq */ int sb; /* SideBand value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the DSBSpecFrame already represents the USB, return a UnitMap.*/ sb = astGetSideBand( this ); if( sb == USB ) { result = (AstMapping *) astUnitMap( 1, "", status ); /* If the DSBSpecFrame represents the LSB, or LO offset, create a suitable WinMap. */ } else { /* Find the Mapping from the spectral system described by this SpecFrame to topocentric frequency in Hz. */ tmap = TopoMap( this, 1, method, status ); /* Calculate the local oscillator frequency (topocentric in Hertz). */ f_lo = GetLO( this, "create a Mapping to upper sideband", "astGetImagFreq", status ); /* Create a 1D WinMap which converts f_in to f_out. */ if( sb == LSB ) { f_in_a = 0.0; f_in_b = 2*f_lo; f_out_a = 2*f_lo; f_out_b = 0.0; } else { f_in_a = 0.0; f_in_b = -f_lo; f_out_a = f_lo; f_out_b = 0.0; } fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); /* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); astInvert( tmap ); map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); /* Simplify */ result = astSimplify( map2 ); /* Free resources */ tmap = astAnnul( tmap ); fmap = astAnnul( fmap ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); } /* Return NULL if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static void VerifyAttrs( AstDSBSpecFrame *this, const char *purp, const char *attrs, const char *method, int *status ) { /* * Name: * VerifyAttrs * Purpose: * Verify that usable attribute values are available. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * void VerifyAttrs( AstDSBSpecFrame *this, const char *purp, * const char *attrs, const char *method, int *status ) * Class Membership: * DSBSpecFrame member function * Description: * This function tests each attribute listed in "attrs". It returns * without action if 1) an explicit value has been set for each attribute * or 2) the UseDefs attribute of the supplied DSBSpecFrame is non-zero. * * If UseDefs is zero (indicating that default values should not be * used for attributes), and any of the named attributes does not have * an explicitly set value, then an error is reported. * Parameters: * this * Pointer to the DSBSpecFrame. * purp * Pointer to a text string containing a message which will be * included in any error report. This shouldindicate the purpose * for which the attribute value is required. * attrs * A string holding a space separated list of attribute names. * method * A string holding the name of the calling method for use in error * messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ const char *a; const char *desc; const char *p; int len; int set; int state; /* Check inherited status */ if( !astOK ) return; /* If the DSBSpecFrame has a non-zero value for its UseDefs attribute, then all attributes are assumed to have usable values, since the defaults will be used if no explicit value has been set. So we only need to do any checks if UseDefs is zero. */ if( !astGetUseDefs( this ) ) { /* Initialise variables to avoid compiler warnings. */ a = NULL; desc = NULL; len = 0; set = 0; /* Loop round the "attrs" string identifying the start and length of each non-blank word in the string. */ state = 0; p = attrs; while( 1 ) { if( state == 0 ) { if( !isspace( *p ) ) { a = p; len = 1; state = 1; } } else { if( isspace( *p ) || !*p ) { /* The end of a word has just been reached. Compare it to each known attribute value. Get a flag indicating if the attribute has a set value, and a string describing the attribute.*/ if( len > 0 ) { if( !strncmp( "DSBCentre", a, len ) ) { set = astTestDSBCentre( this ); desc = "central position of interest"; } else if( !strncmp( "IF", a, len ) ) { set = astTestIF( this ); desc = "intermediate frequency"; } else { astError( AST__INTER, "VerifyAttrs(DSBSpecFrame): " "Unknown attribute name \"%.*s\" supplied (AST " "internal programming error).", status, len, a ); } /* If the attribute does not have a set value, report an error. */ if( !set && astOK ) { astError( AST__NOVAL, "%s(%s): Cannot %s.", status, method, astGetClass( this ), purp ); astError( AST__NOVAL, "No value has been set for " "the AST \"%.*s\" attribute (%s).", status, len, a, desc ); } /* Continue the word search algorithm. */ } len = 0; state = 0; } else { len++; } } if( !*(p++) ) break; } } } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* *att++ * Name: * ImagFreq * Purpose: * The image sideband equivalent of the rest frequency. * Type: * Public attribute. * Synopsis: * Floating point, read-only. * Description: * This is a read-only attribute giving the frequency which * corresponds to the rest frequency but is in the opposite sideband. * The value is calculated by first transforming the rest frequency * (given by the RestFreq attribute) from the standard of rest of the * source (given by the SourceVel and SourceVRF attributes) to the * standard of rest of the observer (i.e. the topocentric standard of * rest). The resulting topocentric frequency is assumed to be in the * same sideband as the value given for the DSBCentre attribute (the * "observed" sideband), and is transformed to the other sideband (the * "image" sideband). The new frequency is converted back to the standard * of rest of the source, and the resulting value is returned as the * attribute value, in units of GHz. * Applicability: * DSBSpecFrame * All DSBSpecFrames have this attribute. *att-- */ /* *att++ * Name: * DSBCentre * Purpose: * The central position of interest in a dual sideband spectrum. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute specifies the central position of interest in a dual * sideband spectrum. Its sole use is to determine the local oscillator * frequency (the frequency which marks the boundary between the lower * and upper sidebands). See the description of the IF (intermediate * frequency) attribute for details of how the local oscillator frequency * is calculated. The sideband containing this central position is * referred to as the "observed" sideband, and the other sideband as * the "image" sideband. * * The value is accessed as a position in the spectral system * represented by the SpecFrame attributes inherited by this class, but * is stored internally as topocentric frequency. Thus, if the System * attribute of the DSBSpecFrame is set to "VRAD", the Unit attribute * set to "m/s" and the StdOfRest attribute set to "LSRK", then values * for the DSBCentre attribute should be supplied as radio velocity in * units of "m/s" relative to the kinematic LSR (alternative units may * be used by appending a suitable units string to the end of the value). * This value is then converted to topocentric frequency and stored. If * (say) the Unit attribute is subsequently changed to "km/s" before * retrieving the current value of the DSBCentre attribute, the stored * topocentric frequency will be converted back to LSRK radio velocity, * this time in units of "km/s", before being returned. * * The default value for this attribute is 30 GHz. * Applicability: * DSBSpecFrame * All DSBSpecFrames have this attribute. * Note: * - The attributes which define the transformation to or from topocentric * frequency should be assigned their correct values before accessing * this attribute. These potentially include System, Unit, StdOfRest, * ObsLon, ObsLat, ObsAlt, Epoch, RefRA, RefDec and RestFreq. *att-- */ /* The central frequency (topocentric frequency in Hz). */ astMAKE_CLEAR(DSBSpecFrame,DSBCentre,dsbcentre,AST__BAD) astMAKE_GET(DSBSpecFrame,DSBCentre,double,3.0E10,((this->dsbcentre!=AST__BAD)?this->dsbcentre:3.0E10)) astMAKE_SET(DSBSpecFrame,DSBCentre,double,dsbcentre,value) astMAKE_TEST(DSBSpecFrame,DSBCentre,( this->dsbcentre != AST__BAD )) /* *att++ * Name: * IF * Purpose: * The intermediate frequency in a dual sideband spectrum. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute specifies the (topocentric) intermediate frequency in * a dual sideband spectrum. Its sole use is to determine the local * oscillator (LO) frequency (the frequency which marks the boundary * between the lower and upper sidebands). The LO frequency is * equal to the sum of the centre frequency and the intermediate * frequency. Here, the "centre frequency" is the topocentric * frequency in Hz corresponding to the current value of the DSBCentre * attribute. The value of the IF attribute may be positive or * negative: a positive value results in the LO frequency being above * the central frequency, whilst a negative IF value results in the LO * frequency being below the central frequency. The sign of the IF * attribute value determines the default value for the SideBand * attribute. * * When setting a new value for this attribute, the units in which the * frequency value is supplied may be indicated by appending a suitable * string to the end of the formatted value. If the units are not * specified, then the supplied value is assumed to be in units of GHz. * For instance, the following strings all result in an IF of 4 GHz being * used: "4.0", "4.0 GHz", "4.0E9 Hz", etc. * * When getting the value of this attribute, the returned value is * always in units of GHz. The default value for this attribute is 4 GHz. * Applicability: * DSBSpecFrame * All DSBSpecFrames have this attribute. *att-- */ /* The intermediate frequency (topocentric in Hz). */ astMAKE_CLEAR(DSBSpecFrame,IF,ifr,AST__BAD) astMAKE_GET(DSBSpecFrame,IF,double,4.0E9,((this->ifr!=AST__BAD)?this->ifr:4.0E9)) astMAKE_SET(DSBSpecFrame,IF,double,ifr,value) astMAKE_TEST(DSBSpecFrame,IF,( this->ifr != AST__BAD )) /* *att++ * Name: * SideBand * Purpose: * Indicates which sideband a dual sideband spectrum represents. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute indicates whether the DSBSpecFrame currently * represents its lower or upper sideband, or an offset from the local * oscillator frequency. When querying the current value, the returned * string is always one of "usb" (for upper sideband), "lsb" (for lower * sideband), or "lo" (for offset from the local oscillator frequency). * When setting a new value, any of the strings "lsb", "usb", "observed", * "image" or "lo" may be supplied (case insensitive). The "observed" * sideband is which ever sideband (upper or lower) contains the central * spectral position given by attribute DSBCentre, and the "image" * sideband is the other sideband. It is the sign of the IF attribute * which determines if the observed sideband is the upper or lower * sideband. The default value for SideBand is the observed sideband. * Applicability: * DSBSpecFrame * All DSBSpecFrames have this attribute. *att-- */ /* Protected access to the SideBand attribute uses BADSB to indicate "unset". Other negative values mean "LSB", zero means "LO" and positive values mean "USB". */ astMAKE_CLEAR(DSBSpecFrame,SideBand,sideband,BADSB) astMAKE_SET(DSBSpecFrame,SideBand,int,sideband,((value<0)?LSB:((value==0)?LO:USB))) astMAKE_TEST(DSBSpecFrame,SideBand,( this->sideband != BADSB )) astMAKE_GET(DSBSpecFrame,SideBand,int,USB,(this->sideband == BADSB ? ((astGetIF( this )>0)?LSB:USB):this->sideband)) /* *att++ * Name: * AlignSideBand * Purpose: * Should the SideBand attribute be taken into account when aligning * this DSBSpecFrame with another DSBSpecFrame? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls how a DSBSpecFrame behaves when an attempt * is made to align it with another DSBSpecFrame using c astFindFrame or astConvert. f AST_FINDFRAME or AST_CONVERT. * If both DSBSpecFrames have a non-zero value for AlignSideBand, the * value of the SideBand attribute in each DSBSpecFrame is used so that * alignment occurs between sidebands. That is, if one DSBSpecFrame * represents USB and the other represents LSB then c astFindFrame and astConvert f AST_FINDFRAME and AST_CONVERT * will recognise that the DSBSpecFrames represent different sidebands * and will take this into account when constructing the Mapping that * maps positions in one DSBSpecFrame into the other. If AlignSideBand * in either DSBSpecFrame is set to zero, then the values of the SideBand * attributes are ignored. In the above example, this would result in a * frequency in the first DSBSpecFrame being mapped onto the same * frequency in the second DSBSpecFrame, even though those frequencies * refer to different sidebands. In other words, if either AlignSideBand * attribute is zero, then the two DSBSpecFrames aligns like basic * SpecFrames. The default value for AlignSideBand is zero. * c When astFindFrame or astConvert f When AST_FINDFRAME or AST_CONVERT * is used on two DSBSpecFrames (potentially describing different spectral * coordinate systems and/or sidebands), it returns a Mapping which can be * used to transform a position in one DSBSpecFrame into the corresponding * position in the other. The Mapping is made up of the following steps in * the indicated order: * * - If both DSBSpecFrames have a value of 1 for the AlignSideBand * attribute, map values from the target's current sideband (given by its * SideBand attribute) to the observed sideband (whether USB or LSB). If * the target already represents the observed sideband, this step will * leave the values unchanged. If either of the two DSBSpecFrames have a * value of zero for its AlignSideBand attribute, then this step is omitted. * * - Map the values from the spectral system of the target to the spectral * system of the template. This Mapping takes into account all the * inherited SpecFrame attributes such as System, StdOfRest, Unit, etc. * * - If both DSBSpecFrames have a value of 1 for the AlignSideBand * attribute, map values from the result's observed sideband to the * result's current sideband (given by its SideBand attribute). If the * result already represents the observed sideband, this step will leave * the values unchanged. If either of the two DSBSpecFrames have a value * of zero for its AlignSideBand attribute, then this step is omitted. * Applicability: * DSBSpecFrame * All DSBSpecFrames have this attribute. *att-- */ /* The AlignSideBand value has a value of -1 when not set yielding a default of 0. */ astMAKE_TEST(DSBSpecFrame,AlignSideBand,( this->alignsideband != -1 )) astMAKE_CLEAR(DSBSpecFrame,AlignSideBand,alignsideband,-1) astMAKE_GET(DSBSpecFrame,AlignSideBand,int,-1,((this->alignsideband==-1)?0:this->alignsideband) ) astMAKE_SET(DSBSpecFrame,AlignSideBand,int,alignsideband,(value?1:0)) /* Copy constructor. */ /* ----------------- */ /* None needed */ /* Destructor. */ /* ----------- */ /* None needed */ /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for DSBSpecFrame objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the DSBSpecFrame class to an output Channel. * Parameters: * this * Pointer to the DSBSpecFrame whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ const char *cval; /* Attribute value */ const char *comm; /* Attribute comment */ double dval; /* Attribute value */ int ival; /* Attribute value */ int set; /* Is attribute set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the DSBSpecFrame structure. */ this = (AstDSBSpecFrame *) this_object; /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* DSBCentre */ /* --------- */ set = TestDSBCentre( this, status ); dval = set ? GetDSBCentre( this, status ) : astGetDSBCentre( this ); astWriteDouble( channel, "DSBCen", set, 1, dval, "Central frequency (Hz topo)" ); /* IF */ /* -- */ set = TestIF( this, status ); dval = set ? GetIF( this, status ) : astGetIF( this ); astWriteDouble( channel, "IF", set, 1, dval, "Intermediate frequency (Hz)" ); /* SideBand */ /* -------- */ set = TestSideBand( this, status ); ival = set ? GetSideBand( this, status ) : astGetSideBand( this ); if( ival == LSB ) { cval = "LSB"; comm = "Represents lower sideband"; } else if( ival == LO ) { cval = "LO"; comm = "Represents offset from LO frequency"; } else { cval = "USB"; comm = "Represents upper sideband"; } astWriteString( channel, "SideBn", set, 1, cval, comm ); /* AlignSideBand */ /* ------------- */ set = TestAlignSideBand( this, status ); ival = set ? GetAlignSideBand( this, status ) : astGetAlignSideBand( this ); astWriteInt( channel, "AlSdBn", set, 1, ival, "Align sidebands?" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsADSBSpecFrame and astCheckDSBSpecFrame functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(DSBSpecFrame,SpecFrame) astMAKE_CHECK(DSBSpecFrame) AstDSBSpecFrame *astDSBSpecFrame_( const char *options, int *status, ...) { /* *++ * Name: c astDSBSpecFrame f AST_DSBSPECFRAME * Purpose: * Create a DSBSpecFrame. * Type: * Public function. * Synopsis: c #include "dsbspecframe.h" c AstDSBSpecFrame *astDSBSpecFrame( const char *options, ... ) f RESULT = AST_DSBSPECFRAME( OPTIONS, STATUS ) * Class Membership: * DSBSpecFrame constructor. * Description: * This function creates a new DSBSpecFrame and optionally initialises its * attributes. * * A DSBSpecFrame is a specialised form of SpecFrame which represents * positions in a spectrum obtained using a dual sideband instrument. * Such an instrument produces a spectrum in which each point contains * contributions from two distinctly different frequencies, one from * the "lower side band" (LSB) and one from the "upper side band" (USB). * Corresponding LSB and USB frequencies are connected by the fact * that they are an equal distance on either side of a fixed central * frequency known as the "Local Oscillator" (LO) frequency. * * When quoting a position within such a spectrum, it is necessary to * indicate whether the quoted position is the USB position or the * corresponding LSB position. The SideBand attribute provides this * indication. Another option that the SideBand attribute provides is * to represent a spectral position by its topocentric offset from the * LO frequency. * * In practice, the LO frequency is specified by giving the distance * from the LO frequency to some "central" spectral position. Typically * this central position is that of some interesting spectral feature. * The distance from this central position to the LO frequency is known * as the "intermediate frequency" (IF). The value supplied for IF can * be a signed value in order to indicate whether the LO frequency is * above or below the central position. * Parameters: c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new DSBSpecFrame. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new DSBSpecFrame. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astDSBSpecFrame() f AST_DSBSPECFRAME = INTEGER * A pointer to the new DSBSpecFrame. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the DSBSpecFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitDSBSpecFrame( NULL, sizeof( AstDSBSpecFrame ), !class_init, &class_vtab, "DSBSpecFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new DSBSpecFrame's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new DSBSpecFrame. */ return new; } AstDSBSpecFrame *astDSBSpecFrameId_( const char *options, ... ) { /* * Name: * astDSBSpecFrameId_ * Purpose: * Create a DSBSpecFrame. * Type: * Private function. * Synopsis: * #include "dsbspecframe.h" * AstDSBSpecFrame *astDSBSpecFrameId_( const char *options, ... ) * Class Membership: * DSBSpecFrame constructor. * Description: * This function implements the external (public) interface to the * astDSBSpecFrame constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astDSBSpecFrame_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astDSBSpecFrame_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astDSBSpecFrame_. * Returned Value: * The ID value associated with the new DSBSpecFrame. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the DSBSpecFrame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitDSBSpecFrame( NULL, sizeof( AstDSBSpecFrame ), !class_init, &class_vtab, "DSBSpecFrame" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new DSBSpecFrame's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new DSBSpecFrame. */ return astMakeId( new ); } AstDSBSpecFrame *astInitDSBSpecFrame_( void *mem, size_t size, int init, AstDSBSpecFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitDSBSpecFrame * Purpose: * Initialise a DSBSpecFrame. * Type: * Protected function. * Synopsis: * #include "dsbspecframe.h" * AstDSBSpecFrame *astInitDSBSpecFrame( void *mem, size_t size, int init, * AstDSBSpecFrameVtab *vtab, const char *name ) * Class Membership: * DSBSpecFrame initialiser. * Description: * This function is provided for use by class implementations to initialise * a new DSBSpecFrame object. It allocates memory (if necessary) to accommodate * the DSBSpecFrame plus any additional data associated with the derived class. * It then initialises a DSBSpecFrame structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a DSBSpecFrame at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the DSBSpecFrame is to be initialised. * This must be of sufficient size to accommodate the DSBSpecFrame data * (sizeof(DSBSpecFrame)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the DSBSpecFrame (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the DSBSpecFrame * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the DSBSpecFrame's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new DSBSpecFrame. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * Returned Value: * A pointer to the new DSBSpecFrame. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitDSBSpecFrameVtab( vtab, name ); /* Initialise. */ new = NULL; /* Initialise a SpecFrame structure (the parent class) as the first component within the DSBSpecFrame structure, allocating memory if necessary. Specify that the SpecFrame should be defined in both the forward and inverse directions. */ new = (AstDSBSpecFrame *) astInitSpecFrame( mem, size, 0, (AstSpecFrameVtab *) vtab, name ); if ( astOK ) { /* Initialise the DSBSpecFrame data. */ /* --------------------------------- */ new->dsbcentre = AST__BAD; new->ifr = AST__BAD; new->sideband = BADSB; new->alignsideband = -1; /* If an error occurred, clean up by deleting the new DSBSpecFrame. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new DSBSpecFrame. */ return new; } AstDSBSpecFrame *astLoadDSBSpecFrame_( void *mem, size_t size, AstDSBSpecFrameVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadDSBSpecFrame * Purpose: * Load a DSBSpecFrame. * Type: * Protected function. * Synopsis: * #include "dsbspecframe.h" * AstDSBSpecFrame *astLoadDSBSpecFrame( void *mem, size_t size, * AstDSBSpecFrameVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * DSBSpecFrame loader. * Description: * This function is provided to load a new DSBSpecFrame using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * DSBSpecFrame structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a DSBSpecFrame at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the DSBSpecFrame is to be * loaded. This must be of sufficient size to accommodate the * DSBSpecFrame data (sizeof(DSBSpecFrame)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the DSBSpecFrame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the DSBSpecFrame structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstDSBSpecFrame) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new DSBSpecFrame. If this is NULL, a pointer * to the (static) virtual function table for the DSBSpecFrame class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "DSBSpecFrame" is used instead. * Returned Value: * A pointer to the new DSBSpecFrame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants. */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstDSBSpecFrame *new; /* Pointer to the new DSBSpecFrame */ char *text; /* Pointer to string value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this DSBSpecFrame. In this case the DSBSpecFrame belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstDSBSpecFrame ); vtab = &class_vtab; name = "DSBSpecFrame"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitDSBSpecFrameVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built DSBSpecFrame. */ new = astLoadSpecFrame( mem, size, (AstSpecFrameVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "DSBSpecFrame" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* DSBCentre */ /* --------- */ new->dsbcentre = astReadDouble( channel, "dsbcen", AST__BAD ); if ( TestDSBCentre( new, status ) ) SetDSBCentre( new, new->dsbcentre, status ); /* IF */ /* -- */ new->ifr = astReadDouble( channel, "if", AST__BAD ); if ( TestIF( new, status ) ) SetIF( new, new->ifr, status ); /* SideBand */ /* -------- */ text = astReadString( channel, "sidebn", " " ); if( astOK ) { if( !strcmp( text, " " ) ) { new->sideband = BADSB; } else if( !strcmp( text, "USB" ) ) { new->sideband = USB; } else if( !strcmp( text, "LSB" ) ) { new->sideband = LSB; } else if( !strcmp( text, "LO" ) ) { new->sideband = LO; } else { astError( AST__ATTIN, "astRead(%s): Invalid SideBand description " "\"%s\".", status, astGetClass( channel ), text ); } if ( TestSideBand( new, status ) ) SetSideBand( new, new->sideband, status ); text = astFree( text ); } /* AlignSideBand */ /* ------------- */ new->alignsideband = astReadInt( channel, "alsdbn", -1 ); if( TestAlignSideBand( new, status ) ) SetAlignSideBand( new, new->alignsideband, status ); /* If an error occurred, clean up by deleting the new DSBSpecFrame. */ if ( !astOK ) new = astDelete( new ); } /* Return the new DSBSpecFrame pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ double astGetImagFreq_( AstDSBSpecFrame *this, int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,DSBSpecFrame,GetImagFreq))( this, status ); } ./ast-7.3.3/grf_2.0.c0000644000175000017500000000550312262533650012446 0ustar olesoles/* * Name: * grf_2.0.c * Purpose: * Implement the grf module required by AST V2.0 if no graphics system * is available. * Description: * This file implements the low level graphics functions required * by the rest of AST V2.0, by reporting errors when called. * Inheritance: * This module is not a class and does not inherit. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 23-OCT-1996 (DSB): * Original version. * 13-NOV-1996 (DSB): * Modified to issue error messages using astError instead of printf. * 23-NOV-2004 (DSB): * Renamed from grf_null.c */ /* Header files */ /* ============ */ #include "grf.h" /* Declare the functions in this module */ #include "error.h" /* AST error reporting facilities */ #include "ast_err.h" /* AST error codes */ /* Function Prototypes */ /* =================== */ static void Report( const char * ); /* Function definitions */ /* ==================== */ int astGFlush( void ){ Report( "astGFlush"); return 0; } int astGLine( int n, const float *x, const float *y ){ Report( "astGLine" ); return 0; } int astGQch( float *chv, float *chh ){ Report( "astGQch" ); return 0; } int astGMark( int n, const float *x, const float *y, int type ){ Report( "astGMark" ); return 0; } int astGText( const char *text, float x, float y, const char *just, float upx, float upy ){ Report( "astGText" ); return 0; } int astGTxExt( const char *text, float x, float y, const char *just, float upx, float upy, float *xb, float *yb ){ Report( "astGTxExt" ); return 0; } int astGAttr( int attr, double value, double *old_value, int prim ){ Report( "astGAttr" ); return 0; } static void Report( const char *name ){ astError( AST__GRFER, "%s: No graphics facilities are available.", name ); astError( AST__GRFER, "Re-link using an option such as '-pgplot' with " "the ast_link script." ); } ./ast-7.3.3/ellipse.h0000644000175000017500000002020212262533650012744 0ustar olesoles#if !defined( ELLIPSE_INCLUDED ) /* Include this file only once */ #define ELLIPSE_INCLUDED /* *+ * Name: * ellipse.h * Type: * C include file. * Purpose: * Define the interface to the Ellipse class. * Invocation: * #include "ellipse.h" * Description: * This include file defines the interface to the Ellipse class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The Ellipse class implement a Region which represents a simple interval * on each axis of the encapsulated Frame * Inheritance: * The Ellipse class inherits from the Region class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 7-SEP-2004 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "region.h" /* Coordinate regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* Ellipse structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstEllipse { /* Attributes inherited from the parent class. */ AstRegion region; /* Parent class structure */ /* Attributes specific to objects in this class. */ double *centre; /* Ellipse centre coords */ double *point1; /* Point at end of primary axis */ double angle; /* Orientation of primary axis */ double a; /* Half-length of primary axis */ double b; /* Half-length of secondary axis */ double lbx; /* Lower x limit of mesh bounding box */ double ubx; /* Upper y limit of mesh bounding box */ double lby; /* Lower x limit of mesh bounding box */ double uby; /* Upper y limit of mesh bounding box */ int stale; /* Is cached information stale? */ } AstEllipse; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstEllipseVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstRegionVtab region_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* EllipsePars)( AstEllipse *, double[2], double *, double *, double *, double[2], double[2], int * ); } AstEllipseVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstEllipseGlobals { AstEllipseVtab Class_Vtab; int Class_Init; } AstEllipseGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitEllipseGlobals_( AstEllipseGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Ellipse) /* Check class membership */ astPROTO_ISA(Ellipse) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstEllipse *astEllipse_( void *, int, const double[2], const double[2], const double[2], AstRegion *, const char *, int *, ...); #else AstEllipse *astEllipseId_( void *, int, const double[2], const double[2], const double[2], AstRegion *, const char *, ... )__attribute__((format(printf,7,8))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstEllipse *astInitEllipse_( void *, size_t, int, AstEllipseVtab *, const char *, AstFrame *, int, const double[2], const double[2], const double[2], AstRegion *, int * ); /* Vtab initialiser. */ void astInitEllipseVtab_( AstEllipseVtab *, const char *, int * ); /* Loader. */ AstEllipse *astLoadEllipse_( void *, size_t, AstEllipseVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astEllipsePars_( AstEllipse *, double[2], double *, double *, double *, double[2], double[2], int * ); # if defined(astCLASS) /* Protected */ AstRegion *astBestEllipse_( AstPointSet *, double *, AstRegion *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckEllipse(this) astINVOKE_CHECK(Ellipse,this,0) #define astVerifyEllipse(this) astINVOKE_CHECK(Ellipse,this,1) /* Test class membership. */ #define astIsAEllipse(this) astINVOKE_ISA(Ellipse,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astEllipse astINVOKE(F,astEllipse_) #else #define astEllipse astINVOKE(F,astEllipseId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitEllipse(mem,size,init,vtab,name,frame,form,p1,p2,p3,unc) \ astINVOKE(O,astInitEllipse_(mem,size,init,vtab,name,frame,form,p1,p2,p3,unc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitEllipseVtab(vtab,name) astINVOKE(V,astInitEllipseVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadEllipse(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadEllipse_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckEllipse to validate Ellipse pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astEllipsePars(this,centre,a,b,angle,p1,p2) \ astINVOKE(V,astEllipsePars_(astCheckEllipse(this),centre,a,b,angle,p1,p2,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astBestEllipse(pset,cen,unc) astBestEllipse_(pset,cen,unc,STATUS_PTR) #endif #endif ./ast-7.3.3/fellipse.c0000644000175000017500000001015712262533650013115 0ustar olesoles/* *+ * Name: * fellipse.c * Purpose: * Define a FORTRAN 77 interface to the AST Ellipse class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the Ellipse class. * Routines Defined: * AST_ISAELLIPSE * AST_ELLIPSE * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 31-AUG-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "ellipse.h" /* C interface to the Ellipse class */ F77_LOGICAL_FUNCTION(ast_isaellipse)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAELLIPSE", NULL, 0 ); astWatchSTATUS( RESULT = astIsAEllipse( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_ellipse)( INTEGER(FRAME), INTEGER(FORM), DOUBLE_ARRAY(POINT1), DOUBLE_ARRAY(POINT2), DOUBLE_ARRAY(POINT3), INTEGER(UNC), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FRAME) GENPTR_INTEGER(FORM) GENPTR_DOUBLE_ARRAY(POINT1) GENPTR_DOUBLE_ARRAY(POINT2) GENPTR_DOUBLE_ARRAY(POINT3) GENPTR_INTEGER(UNC) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_ELLIPSE", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astEllipse( astI2P( *FRAME ), *FORM, POINT1, POINT2, POINT3, astI2P( *UNC ), "%s", options ) ); astFree( options ); ) return RESULT; } F77_SUBROUTINE(ast_ellipsepars)( INTEGER(THIS), DOUBLE_ARRAY(CENTRE), DOUBLE(A), DOUBLE(B), DOUBLE(ANGLE), DOUBLE_ARRAY(P1), DOUBLE_ARRAY(P2), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_DOUBLE_ARRAY(CENTRE) GENPTR_DOUBLE(A) GENPTR_DOUBLE(B) GENPTR_DOUBLE(ANGLE) GENPTR_DOUBLE_ARRAY(P1) GENPTR_DOUBLE_ARRAY(P2) astAt( "AST_ELLIPSEPARS", NULL, 0 ); astWatchSTATUS( astEllipsePars( astI2P( *THIS ), CENTRE, A, B, ANGLE, P1, P2 ); ) } ./ast-7.3.3/unit.h0000644000175000017500000000464512262533650012303 0ustar olesoles#if !defined( UNIT_INCLUDED ) /* Include this file only once */ #define UNIT_INCLUDED /* *+ * Name: * unit.h * Purpose: * Define the interface to the Unit module. * Description: * This module defines functions which identify units and transform * between them. * * Note that this module is not a class implementation, although it * resembles one. * Functions Defined: * Public: * None. * * Protected: * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 10-DEC-2002 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ #include "mapping.h" /* Coordinate mappings */ /* C header files. */ /* --------------- */ /* Function prototypes. */ /* ==================== */ #if defined(astCLASS) /* Protected */ AstMapping *astUnitMapper_( const char *, const char *, const char *, char **, int * ); const char *astUnitLabel_( const char *, int * ); double astUnitAnalyser_( const char *, double[9], int * ); const char *astUnitNormaliser_( const char *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These wrap up the functions defined by this module. */ #if defined(astCLASS) /* Protected */ #define astUnitMapper(in,out,inlab,outlab) astINVOKE(O,astUnitMapper_(in,out,inlab,outlab,STATUS_PTR)) #define astUnitAnalyser(in,powers) astUnitAnalyser_(in,powers,STATUS_PTR) #define astUnitNormaliser(in) astUnitNormaliser_(in,STATUS_PTR) #define astUnitLabel(sym) astINVOKE(O,astUnitLabel_(sym,STATUS_PTR)) #endif #endif ./ast-7.3.3/ratemap.c0000644000175000017500000020626512262533650012752 0ustar olesoles/* *class++ * Name: * RateMap * Purpose: * Mapping which represents differentiation. * Constructor Function: c astRateMap f AST_RATEMAP * Description: * A RateMap is a Mapping which represents a single element of the * Jacobian matrix of another Mapping. The Mapping for which the * Jacobian is required is specified when the new RateMap is created, * and is referred to as the "encapsulated Mapping" below. * * The number of inputs to a RateMap is the same as the number of inputs * to its encapsulated Mapping. The number of outputs from a RateMap * is always one. This one output equals the rate of change of a * specified output of the encapsulated Mapping with respect to a * specified input of the encapsulated Mapping (the input and output * to use are specified when the RateMap is created). * * A RateMap which has not been inverted does not define an inverse * transformation. If a RateMap has been inverted then it will define * an inverse transformation but not a forward transformation. * Inheritance: * The RateMap class inherits from the Mapping class. * Attributes: * The RateMap class does not define any new attributes beyond those * which are applicable to all Mappings. * Functions: c The RateMap class does not define any new functions beyond those f The RateMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 10-FEB-2004 (DSB): * Original version. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 10-MAY-2006 (DSB): * Override astEqual. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS RateMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate Mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "ratemap.h" /* Interface definition for this class */ #include "unitmap.h" /* Unit Mappings */ #include "frame.h" /* Frames */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int *(* parent_mapsplit)( AstMapping *, int, const int *, AstMapping **, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(RateMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(RateMap,Class_Init) #define class_vtab astGLOBAL(RateMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstRateMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstRateMap *astRateMapId_( void *, int, int, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *RemoveRegions( AstMapping *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetObjSize( AstObject *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two RateMaps are equivalent. * Type: * Private function. * Synopsis: * #include "ratemap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * RateMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two RateMaps are equivalent. * Parameters: * this * Pointer to the first Object (a RateMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the RateMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstRateMap *that; AstRateMap *this; int nin; int nout; int result; int that_inv; int this_inv; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two RateMap structures. */ this = (AstRateMap *) this_object; that = (AstRateMap *) that_object; /* Check the second object is a RateMap. We know the first is a RateMap since we have arrived at this implementation of the virtual function. */ if( astIsARateMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNin( that ) == nin && astGetNout( that ) == nout ) { /* If the Invert flags for the two RateMaps differ, it may still be possible for them to be equivalent. First compare the RateMaps if their Invert flags are the same. In this case all the attributes of the two RateMaps must be identical. */ if( astGetInvert( this ) == astGetInvert( that ) ) { /* Temporarily re-instate the original Invert flag values. */ this_inv = astGetInvert( this->map ); that_inv = astGetInvert( that->map ); astSetInvert( this->map, this->invert ); astSetInvert( that->map, that->invert ); if( astEqual( this->map, that->map ) && this->iin == that->iin && this->iout == that->iout ){ result = 1; } /* Restore the original Invert flag values. */ astSetInvert( this->map, this_inv ); astSetInvert( that->map, that_inv ); /* If the Invert flags for the two RateMaps differ, the attributes of the two RateMaps must be inversely related to each other. */ } else { /* In the specific case of a RateMap, Invert flags must be equal. */ result = 0; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "ratemap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * RateMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied RateMap, * in bytes. * Parameters: * this * Pointer to the RateMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstRateMap *this; /* Pointer to RateMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the RateMap structure. */ this = (AstRateMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->map ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } void astInitRateMapVtab_( AstRateMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitRateMapVtab * Purpose: * Initialise a virtual function table for a RateMap. * Type: * Protected function. * Synopsis: * #include "ratemap.h" * void astInitRateMapVtab( AstRateMapVtab *vtab, const char *name ) * Class Membership: * RateMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the RateMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsARateMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* None. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; mapping->RemoveRegions = RemoveRegions; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_transform = mapping->Transform; mapping->Transform = Transform; parent_mapsplit = mapping->MapSplit; mapping->MapSplit = MapSplit; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "RateMap", "Differential Mapping" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * RateMap member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstRateMap *this; /* Pointer to RateMap structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the RateMap structure. */ this = (AstRateMap *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->map, mode, extra, fail ); return result; } #endif static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a RateMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * RateMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated RateMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated RateMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated RateMap which is to be merged with * its neighbours. This should be a cloned copy of the RateMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * RateMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated RateMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *emap1; AstMapping *emap2; AstMapping *emap; AstMapping *smap; AstRateMap *map; AstRateMap *rmap1; AstRateMap *rmap2; int cancel; int map_inv; int nax; int old_inv2; int old_inv; int old_winv; int result; /* Initialise. */ result = -1; /* Check the inherited status. */ if ( !astOK ) return result; /* Initialisation to avoid compiler warnings. */ nax = 0; /* Get a pointer to this RateMap. */ map = (AstRateMap *) this; /* Temporarily set its Invert flag to the requested value. */ map_inv = astGetInvert( map ); astSetInvert( map, ( *invert_list )[ where ] ); /* Get the encapsulated Mapping, and temporarily set its Invert attribute back to the value it had when the RateMap was created, saving the current Invert value so that it can be re-instated later. */ emap = map->map; old_inv = astGetInvert( emap ); astSetInvert( emap, map->invert ); /* First try to simplify the RateMap by simplifying its encapsulated Mapping. */ smap = astSimplify( emap ); /* If any simplification took place, create a new RateMap with the simplified mapping. */ if( smap != emap ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) astRateMap( smap, map->iout, map->iin, "", status ); result = where; /* The only other simplication which can be performed is to cancel a RateMap with its own inverse in series. */ } else if( series ) { /* Indicate we have nothing to cancel with as yet. */ cancel = -1; /* First consider the lower neighbour. */ if( where > 0 && astIsARateMap( ( *map_list )[ where - 1 ] ) ) { /* Check the Invert flags are opposite */ if( ( *invert_list )[ where ] != ( *invert_list )[ where - 1 ] ) { rmap1 = map; rmap2 = (AstRateMap *) ( *map_list )[ where - 1 ]; /* Check the input and output indices are equal. */ if( rmap1->iin == rmap2->iin && rmap1->iout == rmap2->iout ) { /* Check the encapsulated Mappings are equal. */ emap1 = emap; emap2 = rmap2->map; old_winv = astGetInvert( rmap2 ); astSetInvert( rmap2, ( *invert_list )[ where - 1 ] ); old_inv2 = astGetInvert( emap2 ); astSetInvert( emap2, rmap2->invert ); if( astEqual( emap1, emap2 ) ) cancel = where - 1; astSetInvert( emap2, old_inv2 ); astSetInvert( rmap2, old_winv ); nax = astGetNout( rmap1 ); } } } /* Likewise consider the upper neighbour. */ if( cancel == -1 && where + 1 < *nmap && astIsARateMap( ( *map_list )[ where + 1 ] ) ) { if( ( *invert_list )[ where ] != ( *invert_list )[ where + 1 ] ) { rmap1 = map; rmap2 = (AstRateMap *) ( *map_list )[ where + 1 ]; if( rmap1->iin == rmap2->iin && rmap1->iout == rmap2->iout ) { emap1 = emap; emap2 = rmap2->map; old_winv = astGetInvert( rmap2 ); astSetInvert( rmap2, ( *invert_list )[ where + 1 ] ); old_inv2 = astGetInvert( emap2 ); astSetInvert( emap2, rmap2->invert ); if( astEqual( emap1, emap2 ) ) cancel = where + 1; astSetInvert( emap2, old_inv2 ); astSetInvert( rmap2, old_winv ); nax = astGetNin( rmap1 ); } } } /* If we can cancel with a neightbour, do so. */ if( cancel != -1 ) { (void) astAnnul( ( *map_list )[ where ] ); (void) astAnnul( ( *map_list )[ cancel ] ); ( *map_list )[ where ] = (AstMapping *) astUnitMap( nax, "", status ); ( *invert_list )[ where ] = 0; ( *map_list )[ cancel ] = (AstMapping *) astUnitMap( nax, "", status ); ( *invert_list )[ cancel ] = 0; result = ( cancel < where ) ? cancel : where; } } /* Free resources. */ smap = astAnnul( smap ); /* Reset the original Invert attribute for the encapsulated Mapping. */ astSetInvert( emap, old_inv ); /* Reset the original Invert attribute for the specified RateMap */ astSetInvert( map, map_inv ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * RateMap. * Type: * Private function. * Synopsis: * #include "ratemap.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * RateMap method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing RateMap. This is only possible if the specified inputs * correspond to some subset of the RateMap outputs. That is, there * must exist a subset of the RateMap outputs for which each output * depends only on the selected RateMap inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied RateMap, then a NULL Mapping is returned. * Parameters: * this * Pointer to the RateMap to be split (the RateMap is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied RateMap, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied RateMap has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied RateMap. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ AstMapping *emap; /* Pointer to Mapping encapsulated by RateMap */ AstMapping *remap; /* Split Mapping encapsulated by RateMap */ AstRateMap *this; /* Pointer to RateMap structure */ int *eres; /* Outputs used by split Mapping */ int *result; /* Array holding returned output inedx */ int ax1; /* New index of output being differentiated */ int ax2; /* New index of output being varied */ int i; /* Loop count */ int nout; /* No. of outputs in the split Mapping */ int old_inv; /* Original Invert flag for emap */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the parent astMapSplit method to see if it can do the job. */ result = (*parent_mapsplit)( this_map, nin, in, map, status ); /* If not, we provide a special implementation here. Note we cannot produce the Mapping if the RaterMap has been inverted. */ if( !result && !astGetInvert( this_map ) ) { /* Get a pointer to the RateMap structure. */ this = (AstRateMap *) this_map; /* Temporarily reset the Invert attribute of the encapsulated Mapping back to the value it had when the RateMap was created. */ emap = this->map; old_inv = astGetInvert( emap ); astSetInvert( emap, this->invert ); /* Attempt to split the encapsulated Mapping */ eres = astMapSplit( emap, nin, in, &remap ); /* We can only continue if this was succesful. */ if( eres ) { /* Check that the input which the RateMap varies is one of the selected inputs. */ ax2 = -1; for( i = 0; i < nin; i++ ) { if( in[ i ] == this->iin ) { ax2 = i; break; } } /* Check that the output which the RateMap differentiates is one of the outputs of the "remap" Mapping. */ ax1 = -1; nout = astGetNout( remap ); for( i = 0; i < nout; i++ ) { if( eres[ i ] == this->iout ) { ax1 = i; break; } } /* If possible create the required Mapping and returned array. */ if( ax1 != -1 && ax2 != -1 ) { *map = (AstMapping *) astRateMap( remap, ax1, ax2, "", status ); result = astMalloc( sizeof( int ) ); if( astOK ) *result= 0; } /* Free resources */ eres = astFree( eres ); remap = astAnnul( remap ); } /* Re-instate the original Invert flag in the Mapping encapsulated by the supplied RateMap. */ astSetInvert( emap, old_inv ); } /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) { /* * Name: * RemoveRegions * Purpose: * Remove any Regions from a Mapping. * Type: * Private function. * Synopsis: * #include "ratemap.h" * AstMapping *RemoveRegions( AstMapping *this, int *status ) * Class Membership: * RateMap method (over-rides the astRemoveRegions method inherited * from the Mapping class). * Description: * This function searches the supplied Mapping (which may be a * compound Mapping such as a CmpMap) for any component Mappings * that are instances of the AST Region class. It then creates a new * Mapping from which all Regions have been removed. If a Region * cannot simply be removed (for instance, if it is a component of a * parallel CmpMap), then it is replaced with an equivalent UnitMap * in the returned Mapping. * * The implementation provided by the RateMap class invokes the * astRemoveRegions method on the encapsulated Mapping, and returns a * new RateMap containing the resulting Mapping. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the modified mapping. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstMapping *newmap; /* New component Mapping */ AstMapping *result; /* Result pointer to return */ AstRateMap *new; /* Pointer to new RateMap */ AstRateMap *this; /* Pointer to RateMap structure */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the RateMap. */ this = (AstRateMap *) this_mapping; /* Invoke the astRemoveRegions method on the component Mapping. */ newmap = astRemoveRegions( this->map ); /* If the Mapping was not modified, just return a clone of the supplied pointer. */ if( this->map == newmap ) { result = astClone( this ); /* Otherwise, we need to create a new RateMap to return. */ } else { /* If the new Mapping is a Frame (as will be the case if the original Mapping was a Region), use a UnitMap instead. */ if( astIsAFrame( newmap ) ) { (void) astAnnul( newmap ); newmap = (AstMapping *) astUnitMap( astGetNin( this ), " ", status ); } /* Take a deep copy of the supplied RateMap and then modify the Mapping so that we retain any extra information in the supplied RateMap. */ new = astCopy( this ); (void) astAnnul( new->map ); new->map = astClone( newmap ); result = (AstMapping *) new; } /* Free resources. */ newmap = astAnnul( newmap ); /* Annul the returned Mapping if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a RateMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "ratemap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * RateMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a RateMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required Mapping. * This implies applying each of the RateMap's component Mappings in turn, * either in series or in parallel. * Parameters: * this * Pointer to the RateMap. * in * Pointer to the PointSet associated with the input coordinate values. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the RateMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstMapping *emap; AstPointSet *result; AstRateMap *map; double **ptr2; double **ptr; double *pout; double *work; int ic; int iin; int iout; int ipoint; int ncoord; int npoint; int old_inv; /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the RateMap. */ map = (AstRateMap *) this; /* Apply the parent Mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We now extend the parent astTransform method by applying the component Mappings of the RateMap to generate the output coordinate values. */ /* Determine whether to apply the forward or inverse Mapping, according to the direction specified and whether the Mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* The RateMap class does not have an inverse transformation. */ if( !forward ) { astError( AST__INTER, "astTransform(%s): The %s class does not have " "an inverse transformation (AST internal programming error).", status, astGetClass( this ), astGetClass( this ) ); /* Otherwise use the astRate method on the encapsulated Maping to determine the required rate of change at each supplied input point. */ } else { /* Temporarily reset the Invert attribute of the encapsulated Mapping back to the value it had when the RateMap was created. */ emap = map->map; old_inv = astGetInvert( emap ); astSetInvert( emap, map->invert ); /* Note the indices of the input and output to use. */ iin = map->iin; iout = map->iout; /* Get pointers to the axis values in the supplied PointSet. */ ptr = astGetPoints( in ); ncoord = astGetNcoord( in ); npoint = astGetNpoint( in ); /* Work space to hold an input position. */ work = astMalloc( sizeof( double )*(size_t) ncoord ); /* Get a pointer to the axis values in the results PointSet. */ ptr2 = astGetPoints( result ); pout = ptr2[ 0 ]; if( astOK ) { /* Loop round each point in the supplied PointSet. */ for( ipoint = 0; ipoint < npoint; ipoint++ ) { /* Copy this point into the work array. */ for( ic = 0; ic < ncoord; ic++ ) work[ ic ] = ptr[ ic ][ ipoint ]; /* Find the rate of change of the specified output of the encapsulated Mapping with respect to the specified input. */ *(pout++) = astRate( emap, work, iout, iin ); } } /* Re-instate the original Invert flag. */ astSetInvert( emap, old_inv ); /* Free resources */ work = astFree( work ); } /* If an error occurred, clean up by deleting the output PointSet (if allocated by this function) and setting a NULL result pointer. */ if ( !astOK ) { if ( !out ) result = astDelete( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for RateMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for RateMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Mappings within the RateMap. */ /* Local Variables: */ AstRateMap *in; /* Pointer to input RateMap */ AstRateMap *out; /* Pointer to output RateMap */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output RateMaps. */ in = (AstRateMap *) objin; out = (AstRateMap *) objout; /* For safety, start by clearing any references to the input component Mappings from the output RateMap. */ out->map = NULL; /* Make copies of these Mappings and store pointers to them in the output RateMap structure. */ out->map = astCopy( in->map ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for RateMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for RateMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstRateMap *this; /* Pointer to RateMap */ /* Obtain a pointer to the RateMap structure. */ this = (AstRateMap *) obj; /* Annul the pointers to the component Mappings. */ this->map = astAnnul( this->map ); /* Clear the remaining RateMap variables. */ this->invert = 0; this->iin = 0; this->iout = 0; } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for RateMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the RateMap class to an output Channel. * Parameters: * this * Pointer to the RateMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRateMap *this; /* Pointer to the RateMap structure */ int ival; /* Integer value */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the RateMap structure. */ this = (AstRateMap *) this_object; /* Write out values representing the instance variables for the RateMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Input axis. */ /* ------------ */ ival = this->iin; set = ( ival != 0 ); astWriteInt( channel, "IIn", set, 0, ival, "Index of Mapping input" ); /* Output axis. */ /* ------------ */ ival = this->iout; set = ( ival != 0 ); astWriteInt( channel, "IOut", set, 0, ival, "Index of Mapping output" ); /* Invert flag. */ /* ------------ */ ival = this->invert; set = ( ival != 0 ); astWriteInt( channel, "Inv", set, 0, ival, ival ? "Mapping used in inverse direction" : "Mapping used in forward direction" ); /* Mapping. */ /* -------- */ astWriteObject( channel, "Map", 1, 1, this->map, "Mapping to be differentiated" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsARateMap and astCheckRateMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(RateMap,Mapping) astMAKE_CHECK(RateMap) AstRateMap *astRateMap_( void *map_void, int ax1, int ax2, const char *options, int *status, ...) { /* *+ * Name: * astRateMap * Purpose: * Create a RateMap. * Type: * Protected function. * Synopsis: * #include "ratemap.h" * AstRateMap *astRateMap( AstMapping *map, int ax1, int ax2, const char *options, int *status, ... ) * Class Membership: * RateMap constructor. * Description: * This function creates a new RateMap and optionally initialises its * attributes. * Parameters: * map * Pointer to the Mapping to differentiate. * ax1 * zero-based index of the "map" output which is to be differentiated. * ax2 * Zero-based index of the "map" input which is to be varied. * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new RateMap. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new RateMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic RateMap constructor which is * available via the protected interface to the RateMap class. A * public interface is provided by the astRateMapId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "map" parameter is of type (void *) and is converted and validated * within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRateMap *new; /* Pointer to new RateMap */ AstMapping *map; /* Pointer to Mapping structure */ va_list args; /* Variable argument list */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return new; /* Obtain and validate pointers to the Mapping structures provided. */ map = astCheckMapping( map_void ); if ( astOK ) { /* Initialise the RateMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitRateMap( NULL, sizeof( AstRateMap ), !class_init, &class_vtab, "RateMap", map, ax1, ax2 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new RateMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new RateMap. */ return new; } AstRateMap *astRateMapId_( void *map_void, int ax1, int ax2, const char *options, ... ) { /* *++ * Name: c astRateMap f AST_RATEMAP * Purpose: * Create a RateMap. * Type: * Public function. * Synopsis: c #include "ratemap.h" c AstRateMap *astRateMap( AstMapping *map, int ax1, int ax2, c const char *options, ... ) f RESULT = AST_RATEMAP( MAP, AX1, AX2, OPTIONS, STATUS ) * Class Membership: * RateMap constructor. * Description: * This function creates a new RateMap and optionally initialises * its attributes. * * A RateMap is a Mapping which represents a single element of the * Jacobian matrix of another Mapping. The Mapping for which the * Jacobian is required is specified when the new RateMap is created, * and is referred to as the "encapsulated Mapping" below. * * The number of inputs to a RateMap is the same as the number of inputs * to its encapsulated Mapping. The number of outputs from a RateMap * is always one. This one output equals the rate of change of a * specified output of the encapsulated Mapping with respect to a * specified input of the encapsulated Mapping (the input and output * to use are specified when the RateMap is created). * * A RateMap which has not been inverted does not define an inverse * transformation. If a RateMap has been inverted then it will define * an inverse transformation but not a forward transformation. * Parameters: c map f MAP = INTEGER (Given) * Pointer to the encapsulated Mapping. c ax1 f AX1 = INTEGER (Given) * Index of the output from the encapsulated Mapping for which the * rate of change is required. This corresponds to the delta * quantity forming the numerator of the required element of the * Jacobian matrix. The first axis has index 1. c ax2 f AX2 = INTEGER (Given) * Index of the input to the encapsulated Mapping which is to be * varied. This corresponds to the delta quantity forming the * denominator of the required element of the Jacobian matrix. * The first axis has index 1. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new RateMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new RateMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astRateMap() f AST_RATEMAP = INTEGER * A pointer to the new RateMap. * Notes: * - The forward transformation of the encapsulated Mapping must be * defined. c - Note that the component Mappings supplied are not copied by c astRateMap (the new RateMap simply retains a reference to c them). They may continue to be used for other purposes, but c should not be deleted. If a RateMap containing a copy of its c component Mappings is required, then a copy of the RateMap should c be made using astCopy. f - Note that the component Mappings supplied are not copied by f AST_RATEMAP (the new RateMap simply retains a reference to f them). They may continue to be used for other purposes, but f should not be deleted. If a RateMap containing a copy of its f component Mappings is required, then a copy of the RateMap should f be made using AST_COPY. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astRateMap constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astRateMap_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - Because no checking or casting of arguments is performed * before the function is invoked, the "map" parameter is of type * (void *) and is converted from an ID value to a pointer and * validated within the function itself. * - The variable argument list also prevents this function from * invoking astRateMap_ directly, so it must be a re-implementation * of it in all respects, except for the conversions between IDs * and pointers on input/output of Objects. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRateMap *new; /* Pointer to new RateMap */ AstMapping *map; /* Pointer to Mapping structure */ va_list args; /* Variable argument list */ /* Pointer to inherited status value */ int *status; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = NULL; /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return new; /* Obtain the Mapping pointer from the ID supplied and validate the pointer to ensure it identifies a valid Mapping. */ map = astVerifyMapping( astMakePointer( map_void ) ); if ( astOK ) { /* Initialise the RateMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitRateMap( NULL, sizeof( AstRateMap ), !class_init, &class_vtab, "RateMap", map, ax1 - 1, ax2 - 1 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new RateMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return an ID value for the new RateMap. */ return astMakeId( new ); } AstRateMap *astInitRateMap_( void *mem, size_t size, int init, AstRateMapVtab *vtab, const char *name, AstMapping *map, int ax1, int ax2, int *status ) { /* *+ * Name: * astInitRateMap * Purpose: * Initialise a RateMap. * Type: * Protected function. * Synopsis: * #include "ratemap.h" * AstRateMap *astInitRateMap( void *mem, size_t size, int init, * AstRateMapVtab *vtab, const char *name, * AstMapping *map, int ax1, int ax2 ) * Class Membership: * RateMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new RateMap object. It allocates memory (if necessary) to * accommodate the RateMap plus any additional data associated with the * derived class. It then initialises a RateMap structure at the start * of this memory. If the "init" flag is set, it also initialises the * contents of a virtual function table for a RateMap at the start of * the memory passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the RateMap is to be initialised. * This must be of sufficient size to accommodate the RateMap data * (sizeof(RateMap)) plus any data used by the derived class. If a * value of NULL is given, this function will allocate the memory itself * using the "size" parameter to determine its size. * size * The amount of memory used by the RateMap (plus derived class * data). This will be used to allocate memory if a value of NULL is * given for the "mem" parameter. This value is also stored in the * RateMap structure, so a valid value must be supplied even if not * required for allocating memory. * init * A logical flag indicating if the RateMap's virtual function table * is to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new RateMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * map * Pointer to the Mapping. * ax1 * Zero-based index of output axis. * ax2 * Zero-based index of input axis. * Returned Value: * A pointer to the new RateMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstRateMap *new; /* Pointer to new RateMap */ int nin; /* No. input coordinates for RateMap */ int nout; /* No. output coordinates for RateMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitRateMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Report an error if "map" has no forward transformation. */ if( !astGetTranForward( map ) && astOK ) { astError( AST__INTRD, "astInitRateMap(%s): The supplied Mapping " "is not able to transform coordinates in the forward direction.", status, name ); } /* Check that the input and output axis indices are valid. */ nin = astGetNin( map ); nout = astGetNout( map ); if( ( ax1 < 0 || ax1 >= nout ) && astOK ) { astError( AST__INNCO, "astInitRateMap(%s): The output axis %d is out " "of range - it should be in the range 1 to %d.", status, name, ax1 + 1, nout ); } if( ( ax2 < 0 || ax2 >= nin ) && astOK ) { astError( AST__INNCO, "astInitRateMap(%s): The input axis %d is out " "of range - it should be in the range 1 to %d.", status, name, ax2 + 1, nin ); } /* Initialise a Mapping structure (the parent class) as the first component within the RateMap structure, allocating memory if necessary. Specify the number of input and output coordinates and in which directions the Mapping should be defined. */ if ( astOK ) { new = (AstRateMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, nin, 1, 1, 0 ); if ( astOK ) { /* Initialise the RateMap data. */ /* --------------------------- */ /* Store a pointer to the encapsulated Mapping. */ new->map = astClone( map ); /* Save the initial values of the inversion flag for this Mapping. */ new->invert = astGetInvert( map ); /* Save the input and output axis indices. */ new->iout = ax1; new->iin = ax2; /* If an error occurred, clean up by annulling the Mapping pointers and deleting the new object. */ if ( !astOK ) { new->map = astAnnul( new->map ); new = astDelete( new ); } } } /* Return a pointer to the new object. */ return new; } AstRateMap *astLoadRateMap_( void *mem, size_t size, AstRateMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadRateMap * Purpose: * Load a RateMap. * Type: * Protected function. * Synopsis: * #include "ratemap.h" * AstRateMap *astLoadRateMap( void *mem, size_t size, * AstRateMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * RateMap loader. * Description: * This function is provided to load a new RateMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * RateMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a RateMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the RateMap is to be * loaded. This must be of sufficient size to accommodate the * RateMap data (sizeof(RateMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the RateMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the RateMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstRateMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new RateMap. If this is NULL, a pointer to * the (static) virtual function table for the RateMap class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "RateMap" is used instead. * Returned Value: * A pointer to the new RateMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRateMap *new; /* Pointer to the new RateMap */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this RateMap. In this case the RateMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstRateMap ); vtab = &class_vtab; name = "RateMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitRateMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built RateMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "RateMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Invert flag. */ /* ------------ */ new->invert = astReadInt( channel, "inv", 0 ); new->invert = ( new->invert != 0 ); /* Input and output axes. */ /* ---------------------- */ new->iin = astReadInt( channel, "iin", 0 ); new->iout = astReadInt( channel, "iout", 0 ); /* Mapping. */ /* -------- */ new->map = astReadObject( channel, "map", NULL ); /* If an error occurred, clean up by deleting the new RateMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new RateMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ /* None. */ ./ast-7.3.3/configure.ac0000644000175000017500000001413612262533650013435 0ustar olesolesdnl Process this file with autoconf to produce a configure script AC_REVISION($Revision$) dnl This configure file is known to work with autoconf-2.57, dnl automake versions 1.6.3 and 1.7.5, and libtool versions 1.4.2 and dnl 1.5. It should work with autoconf versions 2.50 or better, and dnl automake 1.6 or better. dnl Initialisation: package name and version number AC_INIT(ast, 7.3.3, starlink@jiscmail.ac.uk) dnl Require autoconf-2.50 at least AC_PREREQ(2.50) dnl Require Starlink automake AM_INIT_AUTOMAKE(1.8.2-starlink) dnl Sanity-check: name a file in the source directory AC_CONFIG_SRCDIR([ast_link.in]) # Include defaults for Starlink configurations STAR_DEFAULTS # See if the --with-starmem option has been provided. This sets the # preprocesor macro HAVE_STAR_MEM_H. AC_ARG_WITH( [starmem], AC_HELP_STRING([--with-starmem], [use starmem library for memory management]), AC_DEFINE([HAVE_STAR_MEM_H],[1],[Use the starmem library for memory management]), ) # See if the --with-memdebug option has been provided. This sets the # preprocesor macro MEM_DEBUG which enables facilities used to track # down memory leaks, etc. AC_ARG_WITH( [memdebug], AC_HELP_STRING([--with-memdebug], [enable AST memory leak debugging functions]), AC_DEFINE([MEM_DEBUG],[1],[enable AST memory leak debugging functions in memory.c]), ) # See if the --with-external_pal option has been provided. This sets the # preprocesor macro EXTERNAL_PAL which prevents use of the PAL & SOFA # library functions that are included in the AST distribution. Suitable # link options are used within ast_link(_adam) scripts to pull in libpal. AC_ARG_WITH([external_pal], [ --with-external_pal Use external PAL and SOFA libraries], if test "$withval" = "yes"; then external_pal="1" else external_pal="0" fi, external_pal="0") AC_SUBST( EXTERNAL_PAL, $external_pal ) if test "$external_pal" = "1"; then AC_SUBST( LIBPAL, "-lpal" ) AC_DEFINE([EXTERNAL_PAL],[1],[use external PAL and SOFA libraries]), else AC_SUBST( LIBPAL, "" ) fi AM_CONDITIONAL(EXTERNAL_PAL, test x$external_pal = x1) # Checks for programs AC_PROG_CC AC_PROG_CPP AC_PROG_LIBTOOL AC_PROG_LN_S # If --with-pic=no is set we should honour that. AM_CONDITIONAL(NOPIC, test x$pic_mode = xno) # Conditional defining whether we build with POSIX thread support. AC_ARG_WITH([pthreads], [ --without-pthreads Build package without POSIX threads support], if test "$withval" = "yes"; then use_pthreads="1" else use_pthreads="0" fi, use_pthreads="1") if test "$use_pthreads" = "1"; then AC_CHECK_LIB([pthread], [pthread_create], ,[use_pthreads="0"]) fi AM_CONDITIONAL(NOTHREADS, test x$use_pthreads = x0) AC_SUBST(THREADS, $use_pthreads) # See which variadic function API to use AC_CHECK_HEADERS(stdarg.h varargs.h, break) # Can we use backtrace? AC_CHECK_HEADERS([execinfo.h]) AC_CHECK_FUNCS([backtrace]) # Do we have reentrant strerror and strtok? AC_CHECK_FUNCS([strerror_r strtok_r]) # See if we have long doubles (used by the Mapping and Region classes) AC_CHECK_TYPES([long double]) # See if we have 64 bit integers. AC_CHECK_TYPES([int64_t, uint64_t]) # Calculate alternative 64 bit integer sizes AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) # ast_link needs to be able to link against the Fortran runtime if # necessary AC_FC_LIBRARY_LDFLAGS # Find an absolute path to the Perl binary, augmenting the path with the # location of the Starlink Perl build. If this fails, then set @PERL@ # to the backup `/usr/bin/env perl', which will find Perl if it exists # in the path at runtime. AC_PATH_PROG(PERL, perl, [/usr/bin/env perl], [$STARLINK/Perl/bin:$PATH]) # Function and declaration checks AC_CHECK_FUNCS([isnan]) AC_CHECK_DECLS([isnan],,,[#include ]) AC_CHECK_FUNCS([isfinite]) AC_CHECK_DECLS([isfinite],,,[#include ]) STAR_DECLARE_DEPENDENCIES(sourceset, [sst htx]) # Perform the check that configures f77.h.in for the return type of REAL # Fortran functions. On 64-bit g77 with f2c compatibility this is double # not float. STAR_CNF_F2C_COMPATIBLE # Determine the type of Fortran character string lengths. STAR_CNF_TRAIL_TYPE # Declare the message file. STAR_MESSGEN(ast_err.msg) # Test for non-ANSI behaviour in sscanf on some platforms, reported by # Bill Joye. Also check for bad MINGW sscanf. That returns nc=0 in the # System test. AC_MSG_CHECKING([whether the sscanf function is ANSI-compatible]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { char foo[] = " name 1111.1 "; char mingw[] = "system= FK4_NO_E"; char bar[8]; float ff; int system; int nc; int r; nc = 0; r = sscanf(foo, " %s %f %n", bar, &ff, &nc); if ( nc == 13 ) { nc = 0; r = sscanf( mingw, "system= %n%*s %n", &system, &nc ); if ( nc != 0 ) nc = 13; } exit( ( nc != 13 ) ? 0 : 1 ); } ]])],[ AC_MSG_RESULT([no]);AC_DEFINE([HAVE_NONANSI_SSCANF],[1],[The sscanf shows the non-ANSI behaviour reported by Bill Joye]) ],[AC_MSG_RESULT([yes])],[ AC_DEFINE([HAVE_NONANSI_SSCANF],[1],[The sscanf may show the non-ANSI behaviour reported by Bill Joye]) ]) # Declare the documentation. We need to do complicated things to # satisfy these targets, so give a non-null value # for the second argument, to suppress automatic generation of # rules. STAR_LATEX_DOCUMENTATION([sun210 sun211], [sun210.pdf sun210.tex sun211.pdf sun211.tex sun210.htx_tar sun211.htx_tar]) STAR_PREDIST_SOURCES(sun_master.tex) STAR_CHECK_PROGS(star2html) STAR_CHECK_PROGS(prolat, sst) # prolat is part of SST AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES(Makefile component.xml ast_link ast_link_adam object.h f77.h) AC_CONFIG_FILES([ast_cpp], [chmod +x ast_cpp]) # Following are files which are substituted by the Makefile at # distribution time, rather than by configure. They are not distributed. STAR_PREDIST_SOURCES(version.h.in builddocs.in addversion.in) AC_OUTPUT ./ast-7.3.3/version.h0000644000175000017500000000436712262534206013010 0ustar olesoles#if !defined( VERSION_INCLUDED ) #define VERSION_INCLUDED 1 /* *+ * Name: * version.h * Purpose: * Declare version numbers * Description: * Defines macros which expand to the components of the AST version * number, namely the major and minor version numbers, and the * release number. The version number as a string is available by * including the file config.h, which defines macros PACKAGE_STRING, * PACKAGE_VERSION and (equivalently to the latter) VERSION. * * For example, the version string `3.2.1' corresponds to major version * 3, minor version 2, release 1. * Macros defined: * AST__VMAJOR * The AST major version number * AST__VMINOR * The AST minor version number * AST__RELEASE * The AST release number * * For backwards compatibility, this module also declares macros * AST_MAJOR_VERS, AST_MINOR_VERS and AST_RELEASE. The AST__* * macros should be used in preference to these, since the latter * use (non-standard) single underscores. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * NG: Norman Gray (Starlink) * History: * 25-NOV-2003 (NG): * Original version *- */ /* The current version of AST is 7.3.3 */ #define AST__VMAJOR 7 #define AST__VMINOR 3 #define AST__RELEASE 3 /* Deprecated macros */ #define AST_MAJOR_VERS 7 #define AST_MINOR_VERS 3 #define AST_RELEASE 3 #endif /* #if ! defined(VERSION_INCLUDED) */ ./ast-7.3.3/lutmap.h0000644000175000017500000002363612262533650012627 0ustar olesoles#if !defined( LUTMAP_INCLUDED ) /* Include this file only once */ #define LUTMAP_INCLUDED /* *+ * Name: * lutmap.h * Type: * C include file. * Purpose: * Define the interface to the LutMap class. * Invocation: * #include "lutmap.h" * Description: * This include file defines the interface to the LutMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The LutMap class implements Mappings which transform * 1-dimensional coordinates using linear interpolation in a lookup * table. * Inheritance: * The LutMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * None. * * Protected: * astMapMerge * Simplify a sequence of Mappings. * astTransform * Apply a LutMap to transform a set of points. * New Methods Defined: * Public: * None. * * Protected: * None. * Other Class Functions: * Public: * astIsALutMap * Test class membership. * astLutMap * Create a LutMap. * * Protected: * astCheckLutMap * Validate class membership. * astInitLutMap * Initialise a LutMap. * astInitLutMapVtab * Initialise the virtual function table for the LutMap class. * astLoadLutMap * Load a LutMap. * Macros: * None. * Type Definitions: * Public: * AstLutMap * LutMap object type. * * Protected: * AstLutMapVtab * LutMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 8-JUL-1997 (RFWS): * Original version. * 8-JAN-2003 (DSB): * Added protected astInitLutMapVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* LutMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstLutMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ double *lut; /* Pointer to lookup table */ double *luti; /* Reduced lookup table for inverse trans. */ double inc; /* Input increment between table entries */ double last_fwd_in; /* Last input value (forward transfm.) */ double last_fwd_out; /* Last output value (forward transfm.) */ double last_inv_in; /* Last input value (inverse transfm.) */ double last_inv_out; /* Last output value (inverse transfm.) */ double start; /* Input value for first table entry */ int *flagsi; /* Flags indicating adjacent bad values */ int *indexi; /* Translates reduced to original indices */ int lutinterp; /* Interpolation method */ int nlut; /* Number of table entries */ int nluti; /* Reduced number of table entries */ } AstLutMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstLutMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ int (*GetLutInterp)( AstLutMap *, int * ); int (* TestLutInterp)( AstLutMap *, int * ); void (* ClearLutInterp)( AstLutMap *, int * ); void (* SetLutInterp)( AstLutMap *, int, int * ); double *(* GetLutMapInfo)( AstLutMap *, double *, double *, int *, int * ); } AstLutMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstLutMapGlobals { AstLutMapVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstLutMapGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(LutMap) /* Check class membership */ astPROTO_ISA(LutMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstLutMap *astLutMap_( int, const double [], double, double, const char *, int *, ...); #else AstLutMap *astLutMapId_( int, const double [], double, double, const char *, ... )__attribute__((format(printf,5,6))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstLutMap *astInitLutMap_( void *, size_t, int, AstLutMapVtab *, const char *, int, const double *, double, double, int * ); /* Vtab initialiser. */ void astInitLutMapVtab_( AstLutMapVtab *, const char *, int * ); /* Loader. */ AstLutMap *astLoadLutMap_( void *, size_t, AstLutMapVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitLutMapGlobals_( AstLutMapGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ int astGetLutInterp_( AstLutMap *, int * ); int astTestLutInterp_( AstLutMap *, int * ); void astClearLutInterp_( AstLutMap *, int * ); void astSetLutInterp_( AstLutMap *, int, int * ); double *astGetLutMapInfo_( AstLutMap *, double *, double *, int *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckLutMap(this) astINVOKE_CHECK(LutMap,this,0) #define astVerifyLutMap(this) astINVOKE_CHECK(LutMap,this,1) /* Test class membership. */ #define astIsALutMap(this) astINVOKE_ISA(LutMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astLutMap astINVOKE(F,astLutMap_) #else #define astLutMap astINVOKE(F,astLutMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define \ astInitLutMap(mem,size,init,vtab,name,nlut,lut,start,inc) \ astINVOKE(O,astInitLutMap_(mem,size,init,vtab,name,nlut,lut,start,inc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitLutMapVtab(vtab,name) astINVOKE(V,astInitLutMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadLutMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadLutMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckLutMap to validate LutMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astClearLutInterp(this) \ astINVOKE(V,astClearLutInterp_(astCheckLutMap(this),STATUS_PTR)) #define astGetLutInterp(this) \ astINVOKE(V,astGetLutInterp_(astCheckLutMap(this),STATUS_PTR)) #define astSetLutInterp(this,value) \ astINVOKE(V,astSetLutInterp_(astCheckLutMap(this),value,STATUS_PTR)) #define astTestLutInterp(this) \ astINVOKE(V,astTestLutInterp_(astCheckLutMap(this),STATUS_PTR)) #define astGetLutMapInfo(this,start,inc,nlut) \ astINVOKE(V,astGetLutMapInfo_(astCheckLutMap(this),start,inc,nlut,STATUS_PTR)) #endif #endif ./ast-7.3.3/memory.h0000644000175000017500000003016312262533650012626 0ustar olesoles#if !defined( MEMORY_INCLUDED ) /* Include this file only once */ #define MEMORY_INCLUDED /* *+ * Name: * memory.h * Purpose: * Define the interface to the Memory module. * Description: * This module defines functions which wrap up and extend the * standard C functions for performing memory allocation. They * provide better security against memory leaks, etc., and should * not be inter-mixed with the standard C functions. * * Note that this module is not a class implementation, although it * resembles one. * Functions Defined: * Public: * None. * * Protected: * astAppendString * Append a string to another string which grows dynamically. * astCalloc * Allocate memory. * astChrMatch * Case-insensitive string comparison. * astChrMatchN * Case-insensitive string comparison of an most N characters. * astFree * Free previously allocated memory. * astGrow * Allocate memory for an adjustable array. * astMalloc * Allocate memory. * astRealloc * Change the size of a dynamically allocated region of memory. * astSizeOf * Determine the size of a dynamically allocated region of memory. * astStore * Store data in dynamically allocated memory. * astString * Create a C string from an array of characters. * astStringArray * Create an array of C strings from an array of characters. * astStringCase * Convert a string to upper or lower case. * astChrLen * Returns length of a string without trailing white space, etc. * astSscanf * Like sscanf, but fixes certain platform-specific bugs in the * native sscanf implementation. * astTSizeOf * Determine the total size of a dynamically allocated region of memory. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: D.S. Berry (Starlink) * History: * 8-JAN-1996 (RFWS): * Original version. * 26-JAN-1996 (RFWS) * Added function interfaces. * 20-JUN-1996 (RFWS): * Added astString. * 15-JUL-1996 (RFWS): * Use improved prologue style, etc. and make all functions protected. * 11-SEP-1996 (RFWS): * Added astStringArray (original written by DSB). * 18-MAR-1998 (RFWS): * Make interface available for writing foreign language and * graphics interfaces, etc. * 18-MAR-1998 (RFWS): * Added explicit arguments to function macros. * 29-JAN-2002 (DSB): * Added astChrLen and astSscanf. * 15-NOV-2002 (DSB): * Added astChrMatch astChrMatchN. * 23-FEB-2006 (DSB): * Added astMemCaching and AST__TUNULL. * 2-MAR-2006 (DSB): * Only use astSscanf if the system on which AST was configured * showed the non-ANSI behaviour reported by Bill Joye. * 27-JUN-2007 (DSB): * Added astIsDynamic. * 25-OCT-2007 (DSB): * Added astRemoveLeadingBlanks. * 22-FEB-2008 (DSB): * Added astChrSub. * 19-MAY-2010 (DSB): * Added astStringCase. *- */ /* Include files. */ /* ============== */ /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* C header files. */ /* --------------- */ #include #include "error.h" /* Macros. */ /* ======= */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif #define AST__TUNULL -99999 #define AST__TUNULLC "" /* Type definitions */ /* ================ */ #if defined(astCLASS) /* Header for allocated memory. */ /* ---------------------------- */ /* This stores a "magic" value so that dynamically allocated memory can be recognised, together with the allocated size. It also ensures correct alignment. */ typedef struct Memory { struct Memory *next; unsigned long magic; size_t size; #ifdef MEM_DEBUG struct Memory *prev; /* Pointer to the previous linked Memory structure */ int id; /* A unique identifier for every allocated memory chunk */ int perm; /* Is this chunk part of an acceptable once-off "memory leak"? */ int line; /* Line number in "file" (below). */ char file[50];/* The source file that made the top-level call to AST */ #endif } Memory; /* Define the largest size of a cached memory block in bytes. This does not include the size of the Memory header. This does not need to be too big because the vast majority of memory blocks allocated by AST are less than a few hundred bytes. */ #define MXCSIZE 300 #endif #if defined(THREAD_SAFE) && defined(astCLASS) /* Define a structure holding all data items that are global within the memory.c file. */ typedef struct AstMemoryGlobals { size_t Sizeof_Memory; int Cache_Init; int Use_Cache; Memory *Cache[ MXCSIZE + 1 ]; } AstMemoryGlobals; #endif /* Function prototypes. */ /* ==================== */ #if defined(THREAD_SAFE) && defined(astCLASS) void astInitMemoryGlobals_( AstMemoryGlobals * ); #endif #if defined(astCLASS) || 1 /* Nominally protected, but available for */ /* use in developing (e.g.) foreign */ /* language or graphics interfaces. */ int astMemCaching_( int, int * ); void astChrCase_( const char *, char *, int, int, int * ); char **astChrSplit_( const char *, int *, int * ); char **astChrSplitRE_( const char *, const char *, int *, const char **, int * ); char **astChrSplitC_( const char *, char, int *, int * ); int astChrMatch_( const char *, const char *, int * ); int astChrMatchN_( const char *, const char *, size_t, int * ); char **astStringArray_( const char *, int, int, int * ); char *astStringCase_( const char *, int, int * ); char *astString_( const char *, int, int * ); int astSscanf_( const char *str, const char *format, ...); size_t astSizeOf_( const void *, int * ); int astIsDynamic_( const void *, int * ); size_t astTSizeOf_( const void *, int * ); void *astFree_( void *, int * ); void *astFreeDouble_( void *, int * ); void *astGrow_( void *, int, size_t, int * ); void *astCalloc_( size_t, size_t, int * ); void *astMalloc_( size_t, int, int * ); void *astRealloc_( void *, size_t, int * ); void *astStore_( void *, const void *, size_t, int * ); size_t astChrLen_( const char *, int * ); double astChr2Double_( const char *, int * ); void astRemoveLeadingBlanks_( char *, int * ); char *astAppendString_( char *, int *, const char *, int * ); char *astChrSub_( const char *, const char *, const char *[], int, int * ); #ifdef MEM_PROFILE void astStartTimer_( const char *, int, const char *, int * ); void astStopTimer_( int * ); void astEnableTimers_( int, int * ); #endif #ifdef MEM_DEBUG void astActiveMemory_( const char * ); void astWatchMemory_( int ); void astCheckMemory_( int * ); void astFlushMemory_( int, int * ); int astMemoryTune_( const char *, int, int * ); void *astMemoryPtr_( int ); void astMemoryAlarm_( const char * ); void astMemoryStats_( int , size_t *, size_t *, int * ); void astMemoryWarning_( size_t, int * ); void astMemoryUse_( const void *, const char *, int * ); int astMemoryId_( const void *, int * ); void astBeginPM_( int * ); void astEndPM_( int * ); #endif #endif /* Function interfaces. */ /* ==================== */ /* These wrap up the functions defined by this module. */ #define astCalloc(nmemb,size) astERROR_INVOKE(astCalloc_(nmemb,size,STATUS_PTR)) #define astChrMatch(str1,str2) astERROR_INVOKE(astChrMatch_(str1,str2,STATUS_PTR)) #define astChrMatchN(str1,str2,n) astERROR_INVOKE(astChrMatchN_(str1,str2,n,STATUS_PTR)) #define astFree(ptr) astERROR_INVOKE(astFree_(ptr,STATUS_PTR)) #define astFreeDouble(ptr) astERROR_INVOKE(astFreeDouble_(ptr,STATUS_PTR)) #define astGrow(ptr,n,size) astERROR_INVOKE(astGrow_(ptr,n,size,STATUS_PTR)) #define astMalloc(size) astERROR_INVOKE(astMalloc_(size,0,STATUS_PTR)) #define astMemCaching(flag) astERROR_INVOKE(astMemCaching_(flag,STATUS_PTR)) #define astRealloc(ptr,size) astERROR_INVOKE(astRealloc_(ptr,size,STATUS_PTR)) #define astSizeOf(ptr) astERROR_INVOKE(astSizeOf_(ptr,STATUS_PTR)) #define astIsDynamic(ptr) astERROR_INVOKE(astIsDynamic_(ptr,STATUS_PTR)) #define astTSizeOf(ptr) astERROR_INVOKE(astTSizeOf_(ptr,STATUS_PTR)) #define astStore(ptr,data,size) astERROR_INVOKE(astStore_(ptr,data,size,STATUS_PTR)) #define astAppendString(ptr,len,text) astERROR_INVOKE(astAppendString_(ptr,len,text,STATUS_PTR)) #define astString(chars,nchars) astERROR_INVOKE(astString_(chars,nchars,STATUS_PTR)) #define astStringArray(chars,nel,len) astERROR_INVOKE(astStringArray_(chars,nel,len,STATUS_PTR)) #define astStringCase(string,toupper) astERROR_INVOKE(astStringCase_(string,toupper,STATUS_PTR)) #define astChrLen(string) astERROR_INVOKE(astChrLen_(string,STATUS_PTR)) #define astChr2Double(string) astERROR_INVOKE(astChr2Double_(string,STATUS_PTR)) #define astRemoveLeadingBlanks(string) astERROR_INVOKE(astRemoveLeadingBlanks_(string,STATUS_PTR)) #define astChrSub(test,template,subs,nsub) astERROR_INVOKE(astChrSub_(test,template,subs,nsub,STATUS_PTR)) #define astChrCase(in,out,upper,blen) astERROR_INVOKE(astChrCase_(in,out,upper,blen,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astMallocInit(size) astMalloc_(size,1,STATUS_PTR) #endif #ifdef HAVE_NONANSI_SSCANF #define astSscanf astERROR_INVOKE(astSscanf_) #else #define astSscanf astERROR_INVOKE(sscanf) #endif #define astChrSplit(str,n) astERROR_INVOKE(astChrSplit_(str,n,STATUS_PTR)) #define astChrSplitC(str,c,n) astERROR_INVOKE(astChrSplitC_(str,c,n,STATUS_PTR)) #define astChrSplitRE(str,c,n,m) astERROR_INVOKE(astChrSplitRE_(str,c,n,m,STATUS_PTR)) #ifdef MEM_PROFILE #define astStartTimer(name) astERROR_INVOKE(astStartTimer_(__FILE__,__LINE__,name,STATUS_PTR)) #define astStopTimer astERROR_INVOKE(astStopTimer_(STATUS_PTR)) #define astEnableTimers(enable) astERROR_INVOKE(astEnableTimers_(enable,STATUS_PTR)) #endif /* Functions used for debugging memory leaks, etc */ #ifdef MEM_DEBUG #define astActiveMemory(label) astERROR_INVOKE(astActiveMemory_(label)) #define astMemoryTune(name,value) astERROR_INVOKE(astMemoryTune_(name,value,STATUS_PTR)) #define astWatchMemory(id) astERROR_INVOKE(astWatchMemory_(id)) #define astCheckMemory astERROR_INVOKE(astCheckMemory_(STATUS_PTR)) #define astFlushMemory(leak) astERROR_INVOKE(astFlushMemory_(leak,STATUS_PTR)) #define astBeginPM astERROR_INVOKE(astBeginPM_(STATUS_PTR)) #define astEndPM astERROR_INVOKE(astEndPM_(STATUS_PTR)) #define astMemoryPtr(id) astERROR_INVOKE(astMemoryPtr_(id)) #define astMemoryAlarm(text) astERROR_INVOKE(astMemoryAlarm_(text)) #define astMemoryStats(reset,peak,current) astERROR_INVOKE(astMemoryStats_(reset,peak,current,STATUS_PTR)) #define astMemoryWarning(threshold) astERROR_INVOKE(astMemoryWarning_(threshold,STATUS_PTR)) #define astMemoryUse(ptr,text) astERROR_INVOKE(astMemoryUse_(ptr,text,STATUS_PTR)) #define astMemoryId(ptr) astERROR_INVOKE(astMemoryId_(ptr,STATUS_PTR)) #else #define astActiveMemory(label) #define astMemoryTune(name,value) #define astWatchMemory(id) #define astCheckMemory #define astFlushMemory(leak) #define astBeginPM #define astEndPM #define astMemoryPtr(id) NULL #define astMemoryAlarm(text) #define astMemoryStats(reset,peak,current) #define astMemoryUse(ptr,text) #define astMemoryId(ptr) #define astMemoryWarning(threshold) #endif #endif ./ast-7.3.3/box.h0000644000175000017500000001661012262533650012107 0ustar olesoles#if !defined( BOX_INCLUDED ) /* Include this file only once */ #define BOX_INCLUDED /* *+ * Name: * box.h * Type: * C include file. * Purpose: * Define the interface to the Box class. * Invocation: * #include "box.h" * Description: * This include file defines the interface to the Box class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The Box class implement a Region which represents a simple interval * on each axis of the encapsulated Frame * Inheritance: * The Box class inherits from the Region class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 22-MAR-2003 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "region.h" /* Coordinate regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* Box structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstBox { /* Attributes inherited from the parent class. */ AstRegion region; /* Parent class structure */ /* Attributes specific to objects in this class. */ double *extent; /* Original axis half-widths */ double *shextent; /* Shrunk axis half-widths */ double *centre; /* Box centre coords */ double shrink; /* Temporary shrink factor */ double *lo; /* Shrunk low limits */ double *hi; /* Shrunk high limits */ double *geolen; /* Geodesic half-dimensions of box */ int stale; /* Is other info out of date? */ } AstBox; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstBoxVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstRegionVtab region_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* BoxPoints)( AstBox *, double *, double *, int *); } AstBoxVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstBoxGlobals { AstBoxVtab Class_Vtab; int Class_Init; } AstBoxGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitBoxGlobals_( AstBoxGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Box) /* Check class membership */ astPROTO_ISA(Box) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstBox *astBox_( void *, int, const double[], const double[], AstRegion *, const char *, int *, ...); #else AstBox *astBoxId_( void *, int, const double[], const double[], AstRegion *, const char *, ... )__attribute__((format(printf,6,7))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstBox *astInitBox_( void *, size_t, int, AstBoxVtab *, const char *, AstFrame *, int, const double[], const double[], AstRegion *, int * ); /* Vtab initialiser. */ void astInitBoxVtab_( AstBoxVtab *, const char *, int * ); /* Loader. */ AstBox *astLoadBox_( void *, size_t, AstBoxVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ void astBoxPoints_( AstBox *, double *, double *, int *); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckBox(this) astINVOKE_CHECK(Box,this,0) #define astVerifyBox(this) astINVOKE_CHECK(Box,this,1) /* Test class membership. */ #define astIsABox(this) astINVOKE_ISA(Box,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astBox astINVOKE(F,astBox_) #else #define astBox astINVOKE(F,astBoxId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitBox(mem,size,init,vtab,name,frame,form,p1,p2,unc) \ astINVOKE(O,astInitBox_(mem,size,init,vtab,name,frame,form,p1,p2,unc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitBoxVtab(vtab,name) astINVOKE(V,astInitBoxVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadBox(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadBox_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckBox to validate Box pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astBoxPoints(this,centre,corner) astINVOKE(V,astBoxPoints_(astCheckBox(this),centre,corner,STATUS_PTR)) #endif #endif ./ast-7.3.3/Makefile.am0000644000175000017500000004532312262533650013205 0ustar olesoles## Process this file with automake to produce Makefile.in # First declare various groups of files. These were initially extracted # from the grp.make file, as constructed by the SDT newdev command GRP_C_ROUTINES = \ axis.c \ box.c \ c2f77.c \ channel.c \ circle.c \ cmpframe.c \ cmpmap.c \ cmpregion.c \ dsbspecframe.c \ dssmap.c \ ellipse.c \ error.c \ fbox.c \ fchannel.c \ fcircle.c \ fcmpframe.c \ fcmpmap.c \ fcmpregion.c \ fdsbspecframe.c \ fdssmap.c \ fellipse.c \ ferror.c \ ffitschan.c \ ffluxframe.c \ fframe.c \ fframeset.c \ fgrismmap.c \ finterval.c \ fintramap.c \ fitschan.c \ fkeymap.c \ flutmap.c \ fluxframe.c \ fmapping.c \ fmathmap.c \ fmatrixmap.c \ fnullregion.c \ fobject.c \ fpcdmap.c \ fpermmap.c \ fplot.c \ fplot3d.c \ fpointlist.c \ fpolygon.c \ fpolymap.c \ fprism.c \ frame.c \ frameset.c \ fratemap.c \ fnormmap.c \ fregion.c \ fshiftmap.c \ fskyframe.c \ fslamap.c \ fspecfluxframe.c \ fspecframe.c \ fspecmap.c \ ftimeframe.c \ ftimemap.c \ fsphmap.c \ ffitstable.c \ ftable.c \ ftranmap.c \ fselectormap.c \ fswitchmap.c \ funitmap.c \ fwcsmap.c \ fwinmap.c \ fxmlchan.c \ fzoommap.c \ globals.c \ grismmap.c \ interval.c \ intramap.c \ keymap.c \ loader.c \ lutmap.c \ mapping.c \ mathmap.c \ matrixmap.c \ memory.c \ nullregion.c \ object.c \ pcdmap.c \ permmap.c \ plot.c \ plot3d.c \ pointlist.c \ pointset.c \ polygon.c \ polymap.c \ prism.c \ normmap.c \ ratemap.c \ region.c \ shiftmap.c \ skyaxis.c \ skyframe.c \ slamap.c \ specfluxframe.c \ specframe.c \ specmap.c \ sphmap.c \ stc.c \ stcresourceprofile.c \ stcsearchlocation.c \ stccatalogentrylocation.c \ stcobsdatalocation.c \ stcschan.c \ fstc.c \ fstcresourceprofile.c \ fstcsearchlocation.c \ fstccatalogentrylocation.c \ fstcobsdatalocation.c \ fstcschan.c \ fitstable.c \ table.c \ timeframe.c \ timemap.c \ tranmap.c \ selectormap.c \ switchmap.c \ unit.c \ unitmap.c \ wcsmap.c \ winmap.c \ xml.c \ xmlchan.c \ zoommap.c # Header files which contribute to the "ast.h" file, organised to correspond # with the class hierarchy. AST_H_FILES = \ xml.h \ wcstrig.h \ levmar.h \ proj.h \ memory.h \ error.h \ globals.h \ unit.h \ ast_err.h \ version.h \ object.h \ keymap.h \ table.h \ fitstable.h \ pointset.h \ axis.h \ skyaxis.h \ mapping.h \ cmpmap.h \ dssmap.h \ grismmap.h \ intramap.h \ lutmap.h \ mathmap.h \ matrixmap.h \ pcdmap.h \ permmap.h \ polymap.h \ ratemap.h \ normmap.h \ shiftmap.h \ slamap.h \ specmap.h \ sphmap.h \ timemap.h \ selectormap.h \ switchmap.h \ tranmap.h \ unitmap.h \ wcsmap.h \ winmap.h \ zoommap.h \ frame.h \ cmpframe.h \ specfluxframe.h \ fluxframe.h \ frameset.h \ plot.h \ plot3d.h \ skyframe.h \ specframe.h \ dsbspecframe.h \ region.h \ box.h \ circle.h \ cmpregion.h \ ellipse.h \ interval.h \ nullregion.h \ pointlist.h \ polygon.h \ prism.h \ stc.h \ stcresourceprofile.h \ stcsearchlocation.h \ stccatalogentrylocation.h \ stcobsdatalocation.h \ timeframe.h \ channel.h \ fitschan.h \ stcschan.h \ xmlchan.h # All the (C) include files required to build the library. GRP_C_INCLUDE_FILES = \ $(AST_H_FILES) \ c2f77.h \ ems.h \ err.h \ Ers.h \ f77.h \ grf.h \ grf3d.h \ pg3d.h \ loader.h \ pal2ast.h \ skyaxis.h \ sofa2ast.h \ stc.h \ stcresourceprofile.h \ stcsearchlocation.h \ stccatalogentrylocation.h \ stcobsdatalocation.h \ wcsmath.h \ wcstrig.h \ xmlchan.h # The following list should include AST_PAR, but that must not be # distributed, and so it is listed separately in # nodist_libast_la_SOURCES below. GRP_F_INCLUDE_FILES = \ GRF_PAR \ AST_ERR ## Following declaration isn't used ## LATEX_DOCUMENTATION_FILES = \ ## sun210.tex \ ## sun211.tex DOCUMENTATION_PRODUCTS = $(PAPER_DOCUMENTATION) $(HYPER_DOCUMENTATION) PAPER_DOCUMENTATION = sun210.tex sun211.tex sun210.pdf sun211.pdf HYPER_DOCUMENTATION = sun210.htx_tar sun211.htx_tar PDF_FIGURES = \ cmpframe.pdf \ complex.pdf \ frames.pdf \ frameset.pdf \ fronta.pdf \ fronta_bw.pdf \ frontb.pdf \ frontb_bw.pdf \ frontc.pdf \ frontc_bw.pdf \ fsalign.pdf \ fsconvert.pdf \ fsexample.pdf \ fsmerge.pdf \ fsremap.pdf \ gridplot.pdf \ gridplot_bw.pdf \ mapping.pdf \ overgrid.pdf \ overgrid_bw.pdf \ parallel.pdf \ series.pdf \ simpexamp.pdf WCSLIB_FILES = \ proj.c \ tpn.c \ proj.h \ wcstrig.c \ wcsmath.h \ wcstrig.h LEVMAR_FILES = \ levmar.c \ levmar.h STAR_PAL_FILES = \ pal/pal.h \ pal/palAddet.c \ pal/palAmpqk.c \ pal/palCaldj.c \ pal/palDat.c \ pal/palDe2h.c \ pal/palDeuler.c \ pal/palDh2e.c \ pal/palDjcal.c \ pal/palDmat.c \ pal/palDrange.c \ pal/palDs2tp.c \ pal/palDtp2s.c \ pal/palDtps2c.c \ pal/palDtt.c \ pal/palEcmat.c \ pal/palEqgal.c \ pal/palEtrms.c \ pal/palEvp.c \ pal/palFk45z.c \ pal/palFk524.c \ pal/palFk54z.c \ pal/palGaleq.c \ pal/palGalsup.c \ pal/palMappa.c \ pal/palMapqkz.c \ pal/palOne2One.c \ pal/palPrebn.c \ pal/palPrec.c \ pal/palPrenut.c \ pal/palPvobs.c \ pal/palRvgalc.c \ pal/palRvlg.c \ pal/palRvlsrd.c \ pal/palRvlsrk.c \ pal/palSubet.c \ pal/palSupgal.c \ pal/palmac.h IAU_SOFA_FILES = \ sofa/00READ.ME \ sofa/sofa.h \ sofa/sofam.h \ sofa/a2af.c \ sofa/a2tf.c \ sofa/af2a.c \ sofa/anp.c \ sofa/anpm.c \ sofa/bi00.c \ sofa/bp00.c \ sofa/bp06.c \ sofa/bpn2xy.c \ sofa/c2i00a.c \ sofa/c2i00b.c \ sofa/c2i06a.c \ sofa/c2ibpn.c \ sofa/c2ixy.c \ sofa/c2ixys.c \ sofa/c2s.c \ sofa/c2t00a.c \ sofa/c2t00b.c \ sofa/c2t06a.c \ sofa/c2tcio.c \ sofa/c2teqx.c \ sofa/c2tpe.c \ sofa/c2txy.c \ sofa/cal2jd.c \ sofa/cp.c \ sofa/cpv.c \ sofa/cr.c \ sofa/d2dtf.c \ sofa/d2tf.c \ sofa/dat.c \ sofa/dtdb.c \ sofa/dtf2d.c \ sofa/ee00.c \ sofa/ee00a.c \ sofa/ee00b.c \ sofa/ee06a.c \ sofa/eect00.c \ sofa/eform.c \ sofa/eo06a.c \ sofa/eors.c \ sofa/epb.c \ sofa/epb2jd.c \ sofa/epj.c \ sofa/epj2jd.c \ sofa/epv00.c \ sofa/eqeq94.c \ sofa/era00.c \ sofa/fad03.c \ sofa/fae03.c \ sofa/faf03.c \ sofa/faju03.c \ sofa/fal03.c \ sofa/falp03.c \ sofa/fama03.c \ sofa/fame03.c \ sofa/fane03.c \ sofa/faom03.c \ sofa/fapa03.c \ sofa/fasa03.c \ sofa/faur03.c \ sofa/fave03.c \ sofa/fk52h.c \ sofa/fk5hip.c \ sofa/fk5hz.c \ sofa/fw2m.c \ sofa/fw2xy.c \ sofa/gc2gd.c \ sofa/gc2gde.c \ sofa/gd2gc.c \ sofa/gd2gce.c \ sofa/gmst00.c \ sofa/gmst06.c \ sofa/gmst82.c \ sofa/gst00a.c \ sofa/gst00b.c \ sofa/gst06.c \ sofa/gst06a.c \ sofa/gst94.c \ sofa/h2fk5.c \ sofa/hfk5z.c \ sofa/ir.c \ sofa/jd2cal.c \ sofa/jdcalf.c \ sofa/num00a.c \ sofa/num00b.c \ sofa/num06a.c \ sofa/numat.c \ sofa/nut00a.c \ sofa/nut00b.c \ sofa/nut06a.c \ sofa/nut80.c \ sofa/nutm80.c \ sofa/obl06.c \ sofa/obl80.c \ sofa/p06e.c \ sofa/p2pv.c \ sofa/p2s.c \ sofa/pap.c \ sofa/pas.c \ sofa/pb06.c \ sofa/pdp.c \ sofa/pfw06.c \ sofa/plan94.c \ sofa/pm.c \ sofa/pmat00.c \ sofa/pmat06.c \ sofa/pmat76.c \ sofa/pmp.c \ sofa/pn.c \ sofa/pn00.c \ sofa/pn00a.c \ sofa/pn00b.c \ sofa/pn06.c \ sofa/pn06a.c \ sofa/pnm00a.c \ sofa/pnm00b.c \ sofa/pnm06a.c \ sofa/pnm80.c \ sofa/pom00.c \ sofa/ppp.c \ sofa/ppsp.c \ sofa/pr00.c \ sofa/prec76.c \ sofa/pv2p.c \ sofa/pv2s.c \ sofa/pvdpv.c \ sofa/pvm.c \ sofa/pvmpv.c \ sofa/pvppv.c \ sofa/pvstar.c \ sofa/pvu.c \ sofa/pvup.c \ sofa/pvxpv.c \ sofa/pxp.c \ sofa/rm2v.c \ sofa/rv2m.c \ sofa/rx.c \ sofa/rxp.c \ sofa/rxpv.c \ sofa/rxr.c \ sofa/ry.c \ sofa/rz.c \ sofa/s00.c \ sofa/s00a.c \ sofa/s00b.c \ sofa/s06.c \ sofa/s06a.c \ sofa/s2c.c \ sofa/s2p.c \ sofa/s2pv.c \ sofa/s2xpv.c \ sofa/sepp.c \ sofa/seps.c \ sofa/sp00.c \ sofa/starpm.c \ sofa/starpv.c \ sofa/sxp.c \ sofa/sxpv.c \ sofa/taitt.c \ sofa/taiut1.c \ sofa/taiutc.c \ sofa/tcbtdb.c \ sofa/tcgtt.c \ sofa/tdbtcb.c \ sofa/tdbtt.c \ sofa/tf2a.c \ sofa/tf2d.c \ sofa/tr.c \ sofa/trxp.c \ sofa/trxpv.c \ sofa/tttai.c \ sofa/tttcg.c \ sofa/tttdb.c \ sofa/ttut1.c \ sofa/ut1tai.c \ sofa/ut1tt.c \ sofa/ut1utc.c \ sofa/utctai.c \ sofa/utcut1.c \ sofa/xy06.c \ sofa/xys00a.c \ sofa/xys00b.c \ sofa/xys06a.c \ sofa/zp.c \ sofa/zpv.c \ sofa/zr.c PAL_FILES = \ pal.c \ pal.h \ sofa.h \ sofam.h bin_SCRIPTS = ast_link dist_bin_SCRIPTS = ast_link_adam noinst_SCRIPTS = ast_cpp dist_noinst_SCRIPTS = makeh # Scripts are not distributed by default (since they might be derived objects) # Add these to the distribution below. In fact, it would be useful # and straightforward to make ast_link{,_adam} derived, since they # could then have installation directories painlessly edited in to # them. This might be a requirement for scripts which supported # linking against shared libraries. # Headers required by library users. Both of the following lines # indicate headers which are installed. include_HEADERS = GRF_PAR grf.h grf3d.h # Following are generated, so should not be distributed. nodist_include_HEADERS = ast.h AST_PAR include_MESSAGES = AST_ERR ast_err.h if EXTERNAL_PAL PAL_LIB = else PAL_LIB = libast_pal.la endif lib_LTLIBRARIES = \ $(PAL_LIB) \ libast.la \ libast_err.la \ libast_ems.la \ libast_drama.la \ libast_grf3d.la \ libast_grf_2.0.la \ libast_grf_3.2.la \ libast_grf_5.6.la \ libast_pgplot.la \ libast_pgplot3d.la stardocs_DATA = @STAR_LATEX_DOCUMENTATION@ dist_starnews_DATA = ast.news dist_pkgdata_DATA = LICENCE # Make all library code position independent by default. This is handy for # creating shareable libraries from the static ones (Java JNI libraries). # Note we do not simply set the AM_CFLAGS variable, as this would also # apply to programs compiled without using libtool, possibly causing the # compilation to fail. if !NOTHREADS if !NOPIC libast_la_CFLAGS = $(AM_CFLAGS) -prefer-pic -DTHREAD_SAFE else libast_la_CFLAGS = $(AM_CFLAGS) -DTHREAD_SAFE endif else libast_la_CFLAGS = $(AM_CFLAGS) -prefer-pic endif if !NOPIC libast_err_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_ems_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_drama_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_grf3d_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_grf_2_0_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_grf_3_2_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_grf_5_6_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_pgplot_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_pgplot3d_la_CFLAGS = $(AM_CFLAGS) -prefer-pic libast_pal_la_CFLAGS = $(AM_CFLAGS) -prefer-pic endif # The module containing the main AST classes libast_la_SOURCES = \ $(GRP_C_ROUTINES) \ $(GRP_C_INCLUDE_FILES) \ $(GRP_F_INCLUDE_FILES) \ $(LEVMAR_FILES) \ $(WCSLIB_FILES) \ ast_err.h # Ensure libast links against libraries containing functions used within # libast. If AST is configured --with-external-pal, then the internal # libast_pal library will be empty, and we link to an external PAL # library instead. if EXTERNAL_PAL libast_la_LIBADD = $(libdir)/libpal.la else libast_la_LIBADD = libast_pal.la endif # AST_PAR is really part of GRP_F_INCLUDE_FILES, but it must not be # distributed, so list it separately. nodist_libast_la_SOURCES = \ ast.h \ AST_PAR # The default error reporting module. libast_err_la_SOURCES = err_null.c # The error reporting module that uses EMS to deliver errors. libast_ems_la_SOURCES = err_ems.c # The error reporting module that uses DRAMA Ers to deliver errors. libast_drama_la_SOURCES = err_drama.c # The module containing null implementations of the 3D graphics routines # required by AST libast_grf3d_la_SOURCES = grf3d.c # The module containing null implementations of the graphics routines # required by AST V2.0 libast_grf_2_0_la_SOURCES = grf_2.0.c # The module containing null implementations of the graphics routines # added by AST V3.2 and not present in V2.0 libast_grf_3_2_la_SOURCES = grf_3.2.c # The module containing null implementations of the graphics routines # added by AST V5.6 and not present in V3.2 libast_grf_5_6_la_SOURCES = grf_5.6.c # The graphics module that uses PGPLOT for 2D graphical output. libast_pgplot_la_SOURCES = grf_pgplot.c # The graphics module that uses PGPLOT for 3D graphical output. libast_pgplot3d_la_SOURCES = grf3d_pgplot.c # Positional astronomy libraries. libast_pal_la_SOURCES = $(PAL_FILES) # The following files are built by the targets in this makefile. MAINTAINERCLEANFILES = version.h builddocs addversion \ ast.h $(DOCUMENTATION_PRODUCTS) CLEANFILES = AST_PAR ast.h # Special cases start here # The AST_PAR include file is produced by compiling the astbad.c # program and editing its output into the ast_par.source file (while # also changing the "E" exponent character to a "D"). The astbad.c # and ast_par.source must be distributed (the generation of the # AST__BAD value must be done on the build host) but not installed. noinst_PROGRAMS = astbad astbad_SOURCES = astbad.c pointset.h AST_PAR: ast_par.source astbad sed -e 's//'`./astbad AST__BAD | tr 'E' 'D'`'/' \ -e 's//'`./astbad AST__NAN | tr 'E' 'D'`'/' \ -e 's//'`./astbad AST__NANF | tr 'E' 'D'`'/' \ ast_par.source >$@ # ast_link is generated from ast_link.in; ast_link_adam does not # need configuration, and so is not mentioned in AC_CONFIG_FILES within # configure.ac, and so is not distributed automatically. # # makeh is required in order to build ast.h after distribution (see below). EXTRA_DIST = ast_par.source sun210_figures sun211_figures pal sofa # ast.h depends on the error-facility files. ast.h _could_ be made # before distribution, but since it's generated from other distributed # files, it's more robust to distribute makeh and make ast.h on the # build host. ast.h: $(AST_H_FILES) ast_err.h makeh config.h @PERL@ ./makeh -s $(srcdir) $(AST_H_FILES) >$@ # AST_ERR and ast_err.h are `generated source files', and so must be # generated before any other compilations are done. Note that these # files are generated on the distribution host, and so this # declaration has no effect post-distribution. # # AST_PAR is also a generated source file, but it should _not_ be # included in the list of BUILT_SOURCES, otherwise `make' tries to make # it before it makes the `astbad' program it depends on. Instead, # just rely on the dependencies expressed in the main body above to # have AST_PAR built before it is needed. # # version.h is included by object.h, and thus indirectly by most modules. # It's most straightforward to build it at the beginning. BUILT_SOURCES = AST_ERR ast_err.h version.h # Form a second link to the main object library (static and shared). This # is used when a second pass through the library is needed during linking # to resolve references made within other AST libraries (e.g. the grf # modules, etc), to functions defined within libast (e.g. memory management # and error reporting functions). Do not forget to change the contents of # the libast_pass2.la file to refer to libast_pass2.* rather than libast.*. # Use target install-exec-hook rather than install-exec-local so that the # soft links and files are created *after* the main library has been # installed. install-exec-hook: libast.la $(mkdir_p) $(DESTDIR)$(libdir) cd $(DESTDIR)$(libdir); \ for f in `ls libast.*`; do \ ff=`echo $$f | sed -e 's/libast/libast_pass2/'`; \ if test -f "$$ff"; then rm "$$ff"; fi; \ $(LN_S) $$f $$ff; \ $(MANIFEST) && echo "MANIFEST:$(DESTDIR)$(libdir)/$$ff" || :; \ done; \ if test -f "libast.la"; then \ if test -f "libast_pass2.la"; then rm "libast_pass2.la"; fi; \ sed -e 's/libast\./libast_pass2\./g' libast.la > libast_pass2.la; \ fi # Make pre-distribution files. These are files which are required for # building the distribution, but are not themselves distributed. # The source files here should be mentioned in STAR_PREDIST_SOURCES in # configure.ac @PREDIST@predist_subs = sed \ @PREDIST@ -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),' \ @PREDIST@ -e 's,@PACKAGE_VERSION_MAJOR\@,$(PACKAGE_VERSION_MAJOR),' \ @PREDIST@ -e 's,@PACKAGE_VERSION_MINOR\@,$(PACKAGE_VERSION_MINOR),' \ @PREDIST@ -e 's,@PACKAGE_VERSION_RELEASE\@,$(PACKAGE_VERSION_RELEASE),' \ @PREDIST@ -e 's,@PERL\@,$(PERL),' @PREDIST@version.h: version.h.in configure.ac @PREDIST@ rm -f $@; $(predist_subs) version.h.in >$@ @PREDIST@builddocs: builddocs.in configure.ac @PREDIST@ rm -f $@; $(predist_subs) builddocs.in >$@; chmod +x $@ @PREDIST@addversion: addversion.in configure.ac @PREDIST@ rm -f $@; $(predist_subs) addversion.in >$@; chmod +x $@ # Documentation @PREDIST@$(PAPER_DOCUMENTATION): sun211_figures builddocs addversion @PREDIST@ ./builddocs # The contents of the sun211_figures directory is identical to that # sun210_figures sun211_figures: sun210_figures $(LN_S) sun210_figures sun211_figures # Installation check TESTS = ast_test check_PROGRAMS = ast_test ast_test_SOURCES = ast_test.c #ast_test_LDADD = `ast_link` # Expand ast_link to avoid libast_pass2, which causes problems for Solaris ast_test_LDADD = @LIBPAL@ libast.la libast_pal.la libast_grf_3.2.la libast_grf_5.6.la libast_grf_2.0.la libast_grf3d.la libast_err.la -lm ./ast-7.3.3/lutmap.c0000644000175000017500000025357712262533650012633 0ustar olesoles/* *class++ * Name: * LutMap * Purpose: * Transform 1-dimensional coordinates using a lookup table. * Constructor Function: c astLutMap f AST_LUTMAP * Description: * A LutMap is a specialised form of Mapping which transforms * 1-dimensional coordinates by using linear interpolation in a * lookup table. * * Each input coordinate value is first scaled to give the index of * an entry in the table by subtracting a starting value (the input * coordinate corresponding to the first table entry) and dividing * by an increment (the difference in input coordinate value * between adjacent table entries). * * The resulting index will usually contain a fractional part, so * the output coordinate value is then generated by interpolating * linearly between the appropriate entries in the table. If the * index lies outside the range of the table, linear extrapolation * is used based on the two nearest entries (i.e. the two entries * at the start or end of the table, as appropriate). If either of the * entries used for the interplation has a value of AST__BAD, then the * interpolated value is returned as AST__BAD. * * If the lookup table entries increase or decrease monotonically * (ignoring any flat sections), then the inverse transformation may * also be performed. * Inheritance: * The LutMap class inherits from the Mapping class. * Attributes: * In addition to those attributes common to all Mappings, every * LutMap also has the following attributes: * * - LutInterp: The interpolation method to use between table entries. * Functions: c The LutMap class does not define any new functions beyond those f The LutMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2007-2011 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (JAC, UCLan) * History: * 8-JUL-1997 (RFWS): * Original version. * 10-JUL-1997 (RFWS): * Added the MapMerge function. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitLutMapVtab * method. * 12-JAN-2004 (DSB): * Check for AST__BAD values in the supplied lut array. * 17-MAR-2006 (DSB): * - MapMerge changed so that a LutMap will cancel with its own * inverse. * - Added attribute LutInterp * 10-MAY-2006 (DSB): * Override astEqual. * 4-OCT-2006 (DSB): * - Correct "mintick" to "lutinterp" in SetAttrib. * - Do not include bad values in the dumped LUT array. * 8-NOV-2007 (DSB): * - Take account of the requested invert flag when comparing two * neighbouring LutMaps for equality in MapMerge. * 19-NOV-2010 (DSB): * Added (protected) astGetLutMapInfo function. * 24-JAN-2011 (DSB): * Implement an inverse transformation even if the coordinate * array contains sections of equal or bad values. The inverse * transformation will generate bad values if used within such * regions of the coordinate array. * 6-JUL-2011 (DSB): * Avoid indexing the lut array beyond the end when doing an * inverse transform. * 2-OCT-2012 (DSB): * Check for Infs as well as NaNs. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS LutMap #define LINEAR 0 #define NEAR 1 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory management facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "winmap.h" /* Linear mappings between windows */ #include "channel.h" /* I/O channels */ #include "unitmap.h" /* Unit mappings */ #include "lutmap.h" /* Interface definition for this class */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(LutMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(LutMap,Class_Init) #define class_vtab astGLOBAL(LutMap,Class_Vtab) #define getattrib_buff astGLOBAL(LutMap,GetAttrib_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstLutMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstLutMap *astLutMapId_( int, const double [], double, double, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int GetLinear( AstMapping *, int * ); static int GetMonotonic( int, const double *, int *, double **, int **, int **, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static int Equal( AstObject *, AstObject *, int * ); static double *GetLutMapInfo( AstLutMap *, double *, double *, int *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static int GetLutInterp( AstLutMap *, int * ); static int TestLutInterp( AstLutMap *, int * ); static void ClearLutInterp( AstLutMap *, int * ); static void SetLutInterp( AstLutMap *, int, int * ); /* Member functions. */ /* ================= */ static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a LutMap. * Type: * Private function. * Synopsis: * #include "lutmap.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * LutMap member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * LutMap, so that the default value will subsequently be used. * Parameters: * this * Pointer to the LutMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstLutMap *this; /* Pointer to the LutMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_object; /* Check the attribute name and clear the appropriate attribute. */ /* LutInterp. */ /* ---------- */ if ( !strcmp( attrib, "lutinterp" ) ) { astClearLutInterp( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two LutMaps are equivalent. * Type: * Private function. * Synopsis: * #include "lutmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * LutMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two LutMaps are equivalent. * Parameters: * this * Pointer to the first Object (a LutMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the LutMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstLutMap *that; AstLutMap *this; int i; int nin; int nout; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two LutMap structures. */ this = (AstLutMap *) this_object; that = (AstLutMap *) that_object; /* Check the second object is a LutMap. We know the first is a LutMap since we have arrived at this implementation of the virtual function. */ if( astIsALutMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNin( that ) == nin && astGetNout( that ) == nout ) { /* If the Invert flags for the two LutMaps differ, it may still be possible for them to be equivalent. First compare the LutMaps if their Invert flags are the same. In this case all the attributes of the two LutMaps must be identical. */ if( astGetInvert( this ) == astGetInvert( that ) ) { if( astEQUAL( this->start, that->start ) && astEQUAL( this->inc, that->inc ) && this->nlut == that->nlut && this->lutinterp == that->lutinterp ){ result = 1; for( i = 0; i < this->nlut; i++ ) { if( !astEQUAL( (this->lut)[ i ], (that->lut)[ i ] ) ) { result = 0; break; } } } /* If the Invert flags for the two LutMaps differ, the attributes of the two LutMaps must be inversely related to each other. */ } else { /* In the specific case of a LutMap, Invert flags must be equal. */ result = 0; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a LutMap. * Type: * Private function. * Synopsis: * #include "lutmap.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * LutMap member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a LutMap, formatted as a character string. * Parameters: * this * Pointer to the LutMap. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the LutMap, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the LutMap. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstLutMap *this; /* Pointer to the LutMap structure */ const char *result; /* Pointer value to return */ int lutinterp; /* LutInterp attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_object; /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* LutInterp. */ /* ---------- */ if ( !strcmp( attrib, "lutinterp" ) ) { lutinterp = astGetLutInterp( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", lutinterp ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static int GetLinear( AstMapping *this_mapping, int *status ) { /* * Name: * GetLinear * Purpose: * Determine if a LutMap implements a linear coordinate transformation. * Type: * Private function. * Synopsis: * #include "lutmap.h" * int GetLinear( AstMapping *this, int *status ) * Class Membership: * LutMap member function. * Description: * This function returns a boolean value to indicate if the LutMap * supplied is equivalent to a linear coordinate * transformation. This will be the case if the lookup table * elements increase or decrease linearly. * Parameters: * this * Pointer to the LutMap. * status * Pointer to the inherited status variable. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstLutMap *this; /* Pointer to the LutMap structure */ double *lut; /* Pointer to the lookup table */ double fract; /* Fractional position within table */ double hi; /* Largest value */ double interp; /* Interpolated value */ double lo; /* Smallest value */ double tol1; /* First tolerance estimate */ double tol2; /* Second tolerance estimate */ double tol; /* Tolerance value used */ int ilut; /* Loop counter for table elements */ int linear; /* Result to be returned */ int nlut; /* Number of lookup table elements */ /* Initialise. */ linear = 0; /* Check the global error status. */ if ( !astOK ) return linear; /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_mapping; /* Nearest neighbour LutMaps are not considered to be linear because of the discontinuities at the start and end of the table. */ if( astGetLutInterp( this ) != NEAR ) { /* Obtain the lookup table details. */ lut = this->lut; nlut = this->nlut; /* Loop to identify the largest and smallest values in the lookup table. */ lo = DBL_MAX; hi = -DBL_MAX; for ( ilut = 0; ilut < nlut; ilut++ ) { if ( lut[ ilut ] > hi ) hi = lut[ ilut ]; if ( lut[ ilut ] < lo ) lo = lut[ ilut ]; } /* Check if the values are all the same (this makes the LutMap linear, although it will have no inverse). */ linear = ( hi == lo ); if ( !linear ) { /* Form a tolerance estimate based on the overall range of values in the lookup table. */ tol1 = fabs( hi - lo ) * DBL_EPSILON; /* Now loop to inspect all the lookup table elements except the first and last. */ linear = 1; for ( ilut = 1; ilut < ( nlut - 1 ); ilut++ ) { /* Calculate the fractional position of the current element within the table. */ fract = ( (double) ilut ) / ( (double) ( nlut - 1 ) ); /* Calculate the value it should have if the table is linear by interpolating between the first and last values. */ interp = lut[ 0 ] * ( 1.0 - fract ) + lut[ nlut - 1 ] * fract; /* Form a second tolerance estimate from this interpolated value. Select whichever tolerance estimate is larger (this avoids problems when values are near zero). */ tol2 = fabs( interp ) * DBL_EPSILON; tol = ( tol1 > tol2 ) ? tol1 : tol2; /* Test for linearity within a small multiple of the tolerance. */ linear = ( fabs( lut[ ilut ] - interp ) <= ( 2.0 * tol ) ); if ( !linear ) break; } } } /* Return the result. */ return linear; } static double *GetLutMapInfo( AstLutMap *this, double *start, double *inc, int *nlut, int *status ){ /* * Name: * GetLutMapInfo * Purpose: * Return information about a LutMap. * Type: * Protected virtual function. * Synopsis: * #include "permmap.h" * double *astGetLutMapInfo( AstLutMap *this, double *start, double *inc, * int *nlut, int *status ) * Class Membership: * LutMap method * Description: * This function returns information about the supplied LutMap. * Parameters: * this * Pointer to the LutMap. * start * Pointer to a double in which to return the "start" value * supplied when the LutMap was created. * inc * Pointer to a double in which to return the "inc" value * supplied when the LutMap was created. * nlut * Pointer to a double in which to return the number of values in * the LUT. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array holding a copy of the * look-up table. This is an array of "nlut" elements, giving the * output values for input values "start", "start+inc", "start+2*inc", * etc. The pointer should be freed using astFree when no longer * needed. * Notes: * - A value of NULL will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Store the scalar values. */ *start = this->start; *inc = this->inc; *nlut = this->nlut; /* Return a copy of the look up table. */ return astStore( NULL, this->lut, sizeof( double )*this->nlut ); } static int GetMonotonic( int nlut, const double *lut, int *nluti, double **luti, int **flagsi, int **indexi, int *status ) { /* * Name: * GetMonotonic * Purpose: * Determine if a array is monotonic increasing or decreasing. * Type: * Private function. * Synopsis: * #include "lutmap.h" * int GetMonotonic( int nlut, const double *lut, int *nluti, double **luti, * int **flagsi, int **indexi, int *status ) * Class Membership: * LutMap member function. * Description: * This function returns a flag indiciating the supplied array is * monotonic increasing, monotonic decreasing, or non-monotonic. * Sections of equal or bad values do not invalidate an otherwise * monotonic array. * * It also returns information needed to implement the inverse * transformation of a LutMap. * Parameters: * nlut * The length of the array. * lut * The array to check. * nluti * Address of an int in which to store the length of the returned * "luti" and "flags" arrays. * luti * Address at which to return a pointer to a newly allocated array * containing "*nluti" elements. This is a copy of the supplied * "lut" array but with any bad or NaN values omitted. Subsequent * elements are shuffled down to fill the holes left by removing * these bad values. A NULL pointer is returned if there are no bad * values in "lut". * flagsi * Address at which to return a pointer to a newly allocated array * containing "*nluti" elements. Each element is non-zero if the * corresponding value stored in "luti" was adjacent to a bad value * in the supplied "lut" array. A NULL pointer is returned if there * are no bad values in "lut". * indexi * Address at which to return a pointer to a newly allocated array * containing "*nluti" elements. Each element is the index within * "lut" of the corresponding value stored in "luti". A NULL pointer * is returned if there are no bad values in "lut". * status * Pointer to the inherited status variable. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ const double *p3; double *p1; double lval; int *p2; int *p4; int ilut; int nbad; int result; /* Initialise. */ result = 0; *nluti = 0; *luti = NULL; *flagsi = NULL; *indexi = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* As yet we have not found a good value. */ lval = AST__BAD; /* As yet we have not found a bad value. */ nbad = 0; /* Loop round the supplied array, ignoring bad (AST__BAD or NaN) values. */ for ( ilut = 0; ilut < nlut; ilut++ ) { if( !astISBAD( lut[ ilut ] ) ) { /* If this is the first good value, record it. */ if( lval == AST__BAD ) { lval = lut[ ilut ]; /* If this is not the first good value, ignore it if it is equal to the previous god value. */ } else if( lut[ ilut ] != lval ) { /* Set the returned flag on the basis of the first pair of good values. */ if( result == 0 ) { result = ( lut[ ilut ] > lval ) ? 1 : -1; /* For subsequent pairs of good values, check the pair increases or decreases in the same way as the first pair. Reset the returned value to zero and break if not. */ } else if( result == 1 && lut[ ilut ] < lval ) { result = 0; break; } else if( result == -1 && lut[ ilut ] >lval ) { result = 0; break; } } } else { nbad++; } } /* If any bad values were found, we now allocate the required returned arrays. */ if( nbad ) { *nluti = nlut - nbad; *luti = astMalloc( sizeof( double )*( *nluti ) ); *flagsi = astMalloc( sizeof( double )*( *nluti ) ); *indexi = astMalloc( sizeof( double )*( *nluti ) ); if( astOK ) { /* Into "luti" copy all good values from "lut", shuffling down values to fill holes left by bad values. Into "flagsi", store a flag indicating if the corresponding "luti" value was adjacent to a bad value in the full "lut" array. */ p1 = *luti; p2 = *flagsi; p3 = lut; p4 = *indexi; /* Do the first input point (it has no lower neighbour). */ if( !astISBAD( *p3 ) ) { *(p1++) = *p3; *(p2++) = astISBAD( p3[ +1 ] ); *(p4++) = 0; } /* Do all remaining input points except for the last one. */ for ( ilut = 1,p3++; ilut < nlut-1; ilut++,p3++ ) { if( !astISBAD( *p3 ) ) { *(p1++) = *p3; *(p2++) = astISBAD( p3[ -1 ] ) || astISBAD( p3[ +1 ] ); *(p4++) = ilut; } } /* Do the last input point (it has no upper neighbour). */ if( !astISBAD( *p3 ) ) { *p1 = *p3; *p2 = astISBAD( p3[ -1 ] ); *p4 = ilut; } } } /* Return the result. */ return result; } void astInitLutMapVtab_( AstLutMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitLutMapVtab * Purpose: * Initialise a virtual function table for a LutMap. * Type: * Protected function. * Synopsis: * #include "lutmap.h" * void astInitLutMapVtab( AstLutMapVtab *vtab, const char *name ) * Class Membership: * LutMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the LutMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsALutMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearLutInterp = ClearLutInterp; vtab->GetLutInterp = GetLutInterp; vtab->SetLutInterp = SetLutInterp; vtab->TestLutInterp = TestLutInterp; vtab->GetLutMapInfo = GetLutMapInfo; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; /* Declare the class dump, copy and delete functions.*/ astSetDump( vtab, Dump, "LutMap", "Map 1-d coordinates using a lookup table" ); astSetCopy( (AstObjectVtab *) vtab, Copy ); astSetDelete( (AstObjectVtab *) vtab, Delete ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a LutMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * LutMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated LutMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated LutMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated LutMap which is to be merged with * its neighbours. This should be a cloned copy of the LutMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * LutMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated LutMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstLutMap *map; /* Pointer to LutMap */ AstLutMap *neb; /* Pointer to neighbouring LutMap */ AstMapping *new; /* Pointer to replacement Mapping */ double a1; /* First input coordinate value */ double a2; /* Second input coordinate value */ double b1; /* First output coordinate value */ double b2; /* Second output coordinate value */ int equal; /* Are LutMaps equal? */ int i; /* Mapping index */ int ilo; /* Index of lower LutMap */ int invneb; /* Should the neigbour be used inverted? */ int old_inv; /* Original Invert value for neigbour */ int result; /* Result value to return */ int simpler; /* Mapping simplified? */ /* Initialise the returned result. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the nominated LutMap. */ map = (AstLutMap *) ( *map_list )[ where ]; /* See if the LutMap is linear. If so, it can probably be simplified. */ simpler = GetLinear( (AstMapping *) map, status ); if ( simpler ) { /* Obtain the range of input values corresponding to the first and last lookup table elements. */ a1 = map->start; a2 = map->start + map->inc * ( map->nlut - 1 ); /* Obtain the corresponding range of output values and check these values are not the same. */ b1 = map->lut[ 0 ]; b2 = map->lut[ map->nlut - 1 ]; if ( b1 != b2 ) { /* Create a new WinMap that implements an equivalent linear Mapping, allowing for the invert flag associated with the LutMap. */ if ( !( *invert_list )[ where ] ) { new = (AstMapping *) astWinMap( 1, &a1, &a2, &b1, &b2, "", status ); } else { new = (AstMapping *) astWinMap( 1, &b1, &b2, &a1, &a2, "", status ); } /* If OK, annul the original LutMap pointer and substitute the new one. Also clear the associated invert flag. */ if ( astOK ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = new; ( *invert_list )[ where ] = 0; /* Assign the result value. */ result = where; } } /* Otherwise, see if the LutMap is in series with its own inverse. If so the pair of LutMaps can be replaced by a UnitMap. */ } else if( series ) { /* Is the higher neighbour a LutMap? If so get a pointer to it, and note the index of the lower of the two adjacent LutMaps. */ if( where < ( *nmap - 1 ) && astIsALutMap( ( *map_list )[ where + 1 ] ) ){ neb = (AstLutMap *) ( *map_list )[ where + 1 ]; invneb = ( *invert_list )[ where + 1 ]; ilo = where; /* If not, is the lower neighbour a LutMap? If so get a pointer to it, and note the index of the lower of the two adjacent LutMaps. */ } else if( where > 0 && astIsALutMap( ( *map_list )[ where - 1 ] ) ){ neb = (AstLutMap *) ( *map_list )[ where - 1 ]; invneb = ( *invert_list )[ where - 1 ]; ilo = where - 1; } else { neb = NULL; } /* If a neighbouring LutMap was found, we can replace the pair by a UnitMap if the two LutMaps are equal but have opposite values for their Invert flags. Temporarily invert the neighbour, then compare the two LutMaps for equality, then re-invert the neighbour. */ if( neb ) { old_inv = astGetInvert( neb ); astSetInvert( neb, invneb ); astInvert( neb ); equal = astEqual( map, neb ); astSetInvert( neb, old_inv ); /* If the two LutMaps are equal but opposite, annul the first of the two Mappings, and replace it with a UnitMap. Also set the invert flag. */ if( equal ) { new = (AstMapping *) astUnitMap( 1, "", status ); (void) astAnnul( ( *map_list )[ ilo ] ); ( *map_list )[ ilo ] = new; ( *invert_list )[ ilo ] = 0; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ ilo + 1 ] ); for ( i = ilo + 2; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = where; } } } /* If an error occurred, clear the returned result. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a LutMap. * Type: * Private function. * Synopsis: * #include "lutmap.h" * void SetAttrib( AstObject *this, const char *setting ) * Class Membership: * LutMap member function (over-rides the astSetAttrib protected * method inherited from the Mapping class). * Description: * This function assigns an attribute value for a LutMap, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the LutMap. * setting * Pointer to a null-terminated string specifying the new attribute * value. */ /* Local Variables: */ AstLutMap *this; /* Pointer to the LutMap structure */ int lutinterp; /* LutInterp attribute value */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* LutInterp. */ /* ---------- */ if ( nc = 0, ( 1 == astSscanf( setting, "lutinterp= %d %n", &lutinterp, &nc ) ) && ( nc >= len ) ) { astSetLutInterp( this, lutinterp ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a LutMap. * Type: * Private function. * Synopsis: * #include "lutmap.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * LutMap member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a LutMap's attributes. * Parameters: * this * Pointer to the LutMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstLutMap *this; /* Pointer to the LutMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_object; /* Check the attribute name and test the appropriate attribute. */ /* LutInterp. */ /* ---------- */ if ( !strcmp( attrib, "lutinterp" ) ) { result = astTestLutInterp( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a LutMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "lutmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * LutMap member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a LutMap and a set of points encapsulated * in a PointSet and transforms the points so as to apply the * lookup table transformation. * Parameters: * this * Pointer to the LutMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate * transformation should be applied, while a zero value requests * the inverse transformation. * out * Pointer to a PointSet which will hold the transformed * (output) coordinate values. A NULL value may also be given, * in which case a new PointSet will be created by this * function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * - The number of coordinate values per point in the input * PointSet must equal 1. * - If an output PointSet is supplied, it must have space for * sufficient number of points (with 1 coordinate value per point) * to accommodate the result. Any excess space will be ignored. */ /* Local Variables: */ AstLutMap *map; /* Pointer to LutMap to be applied */ AstPointSet *result; /* Pointer to output PointSet */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *lut; /* Pointer to LUT */ double d1; /* Offset to I1 value */ double d2; /* Offset to I2 value */ double fract; /* Fractional interpolation distance */ double scale; /* Normalising scale factor */ double value_in; /* Input coordinate value */ double value_out; /* Output coordinate value */ double x; /* Value normalised to LUT increment */ double xi; /* Integer value of "x" */ int *flags; /* Flags indicating an adjacent bad value */ int *index; /* Translates reduced to original indices */ int i1; /* Lower adjacent LUT index */ int i2; /* Upper adjacent LUT index */ int i; /* New LUT index */ int istart; /* Original LUT index at start of interval */ int ix; /* "x" converted to an int */ int near; /* Perform nearest neighbour interpolation? */ int nlut; /* Number of LUT entries */ int nlutm1; /* Number of LUT entries minus one */ int npoint; /* Number of points */ int ok; /* Lookup table is not flat */ int point; /* Loop counter for points */ int up; /* LUT values are increasing? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the LutMap. */ map = (AstLutMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* Determine the numbers of points from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse mapping, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* Forward transformation. */ /* ----------------------- */ if( astOK ){ if ( forward ) { /* Obtain lookup table details. */ lut = map->lut; nlut = map->nlut; near = ( astGetLutInterp( map ) == NEAR ); nlutm1 = nlut - 1; /* Calculate the scale factor required. */ scale = 1.0 / map->inc; /* Loop to transform each input point. */ for ( point = 0; point < npoint; point++ ) { /* Extract the input coordinate value. */ value_in = ptr_in[ 0 ][ point ]; /* First check if this is the same value as we transformed last. If so, re-use the last result. */ if ( value_in == map->last_fwd_in ) { value_out = map->last_fwd_out; /* Check for bad input coordinates and generate a bad result if necessary. */ } else if ( value_in == AST__BAD ) { value_out = AST__BAD; /* For nearest-neighbour interpolation, return the value of the lookup table entry corresponding to the input coordinate. */ } else if( near ){ x = ( value_in - map->start ) * scale; xi = floor( x + 0.5 ); ix = (int) xi; if ( ix < 0 || ix >= nlut ) { value_out = AST__BAD; } else { value_out = lut[ ix ]; } /* Otherwise, (for linear interpolation) identify the lookup table entry corresponding to the input coordinate. */ } else { x = ( value_in - map->start ) * scale; xi = floor( x ); ix = (int) xi; /* If the input value lies below the first lookup table entry, extrapolate using the first two table values. */ if ( ix < 0 ) { if( lut[ 0 ] != AST__BAD && lut[ 1 ] != AST__BAD ) { value_out = lut[ 0 ] + x * ( lut[ 1 ] - lut[ 0 ] ); } else { value_out = AST__BAD; } /* If the input value lies above the last lookup table entry (or equals it), extrapolate using the last two table values. */ } else if ( ix >= nlutm1 ) { if( lut[ nlutm1 ] != AST__BAD && lut[ nlut - 2 ] != AST__BAD ) { value_out = lut[ nlutm1 ] + ( x - (double) ( nlutm1 ) ) * ( lut[ nlutm1 ] - lut[ nlut - 2 ] ); } else { value_out = AST__BAD; } /* Otherwise, interpolate between the adjacent entries. */ } else { if( lut[ ix ] != AST__BAD && lut[ ix + 1 ] != AST__BAD ) { fract = x - xi; value_out = lut[ ix ] * ( 1.0 - fract ) + lut[ ix + 1 ] * fract; } else { value_out = AST__BAD; } } } /* Assign the output coordinate value. */ ptr_out[ 0 ][ point ] = value_out; /* Retain the input and output coordinate values for possible re-use in future. */ map->last_fwd_in = value_in; map->last_fwd_out = value_out; } /* Inverse transformation. */ /* ----------------------- */ } else { /* Obtain details of the lookup table to be used by the inverse transformation. This is the same as the forward transformation lookup table, except that any bad values are omitted. Also, get a pointer to a array of flags that indicate if the corresponding lookup table entries were adjacent to a bad value or not in the full lookup table. */ if( map->luti ) { lut = map->luti; flags = map->flagsi; nlut = map->nluti; index = map->indexi; } else { lut = map->lut; flags = NULL; nlut = map->nlut; index = NULL; } near = ( astGetLutInterp( map ) == NEAR ); nlutm1 = nlut - 1; /* Loop to transform each input point. */ for ( point = 0; point < npoint; point++ ) { /* Extract the input coordinate value. */ value_in = ptr_in[ 0 ][ point ]; /* First check if this is the same value as we transformed last. If so, re-use the last result. */ if ( value_in == map->last_inv_in ) { value_out = map->last_inv_out; /* Check for bad input coordinates and generate a bad result if necessary. */ } else if ( value_in == AST__BAD ) { value_out = AST__BAD; /* Otherwise, we can determine an inverse. Note the inverse transformation will not be defined, so will not be attempted, unless all the table entries are monotonically increasing or decreasing, possibly with sections of equal or bad values. */ } else { up = ( lut[ nlutm1 ] > lut[ 0 ] ); /* Perform a binary search to identify two adjacent lookup table elements whose values bracket the input coordinate value. */ i1 = -1; i2 = nlutm1; while ( i2 > ( i1 + 1 ) ) { i = ( i1 + i2 ) / 2; *( ( ( value_in >= lut[ i ] ) == up ) ? &i1 : &i2 ) = i; } /* If the lower table value is equal to the required value, and either of its neighbours is also equal to the required value, then we have been asked to find the inverse in a flat region of the table, so return a bad value. Likewise, if the upper table value is equal to the required value, and either of its neighbours is also equal to the required value, then we have been asked to find the inverse in a flat region of the table, so return a bad value. */ ok = 1; if( lut[ i1 ] == value_in ) { if( i1 > 0 && lut[ i1 - 1 ] == value_in ) ok = 0; if( lut[ i2 ] == value_in ) ok = 0; } else if( lut[ i2 ] == value_in ) { if( i2 < nlutm1 && lut[ i2 + 1 ] == value_in ) ok = 0; if( lut[ i1 ] == value_in ) ok = 0; } if( !ok ) { value_out = AST__BAD; /* If both of the two table elements were adjacent to a bad value in the full lookup table, return a bad output value. */ } else if( flags && ( flags[ i1 ] && flags[ i2 ] ) ) { value_out = AST__BAD; /* Nearest neighbour interpolation: return the closest of i1 or i2. Return AST__BAD if the supplied value is less than either or greater than either. */ } else if( near ) { d1 = lut[ i1 ] - value_in; d2 = lut[ i2 ] - value_in; if( ( d1 > 0.0 && d2 > 0.0 ) || ( d1 < 0.0 && d2 < 0.0 ) ) { value_out = AST__BAD; } else { if( fabs( d1 ) < fabs( d2 ) ){ istart = index ? index[ i1 ] : i1; } else { istart = index ? index[ i2 ] : i2; } value_out = map->start + map->inc * istart; } /* Linear interpolation... */ } else { /* We are interested in the lower bracketing table element. If necessary, restrict this element's index to lie within the table. This causes extrapolation to occur (instead of interpolation) if the input value actually lies outside the range of the lookup table. */ if ( i1 < 0 ) i1 = 0; if ( i1 > ( nlut - 2 ) ) i1 = nlut - 2; /* Interpolate (or extrapolate) to derive the output coordinate value. */ istart = index ? index[ i1 ] : i1; value_out = map->start + map->inc * ( (double) istart + ( ( value_in - lut[ i1 ] ) / ( lut[ i1 + 1 ] - lut[ i1 ] ) ) ); } } /* Assign the output coordinate value. */ ptr_out[ 0 ][ point ] = value_out; /* Retain the input and output coordinate values for possible re-use in future. */ map->last_inv_in = value_in; map->last_inv_out = value_out; } } } /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* *att++ * Name: * LutInterp * Purpose: * Look-up table interpolation method. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute indicates the method to be used when finding the * output value of a LutMap for an input value part way between two * table entries. If it is set to 0 (the default) then linear * interpolation is used. Otherwise, nearest neighbour interpolation * is used. * * Using nearest neighbour interpolation causes AST__BAD to be returned * for any point which falls outside the bounds of the table. Linear * interpolation results in an extrapolated value being returned based * on the two end entries in the table. * Applicability: * LutMap * All LutMaps have this attribute. *att-- */ astMAKE_CLEAR(LutMap,LutInterp,lutinterp,-INT_MAX) astMAKE_GET(LutMap,LutInterp,int,LINEAR,( ( this->lutinterp == -INT_MAX ) ? LINEAR : this->lutinterp )) astMAKE_SET(LutMap,LutInterp,int,lutinterp,(( value == LINEAR ) ? LINEAR : NEAR )) astMAKE_TEST(LutMap,LutInterp,( this->lutinterp != -INT_MAX )) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for LutMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for LutMap objects. * Parameters: * objin * Pointer to the LutMap to be copied. * objout * Pointer to the LutMap being constructed. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstLutMap *out; /* Pointer to output LutMap */ AstLutMap *in; /* Pointer to input LutMap */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the input and output LutMaps. */ in= (AstLutMap *) objin; out = (AstLutMap *) objout; /* Nullify all output pointers. */ out->lut = NULL; out->luti = NULL; out->flagsi = NULL; out->indexi = NULL; /* Allocate memory and store a copy of the lookup table data. */ out->lut = astStore( NULL, in->lut, sizeof( double ) * (size_t) in->nlut ); /* Do the arrays used for the inverse transformation, if they exist. */ if( in->luti ) out->luti = astStore( NULL, in->luti, sizeof( double ) * (size_t) in->nluti ); if( in->flagsi ) out->flagsi = astStore( NULL, in->flagsi, sizeof( double ) * (size_t) in->nluti ); if( in->indexi ) out->indexi = astStore( NULL, in->indexi, sizeof( double ) * (size_t) in->nluti ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for LutMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for LutMap objects. * Parameters: * obj * Pointer to the LutMap to be deleted. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstLutMap *this; /* Pointer to LutMap */ /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) obj; /* Free the memory holding the lookup tables, etc. */ this->lut = astFree( this->lut ); this->luti = astFree( this->luti ); this->flagsi = astFree( this->flagsi ); this->indexi = astFree( this->indexi ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for LutMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the LutMap class to an output Channel. * Parameters: * this * Pointer to the LutMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstLutMap *this; /* Pointer to the LutMap structure */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ int ilut; /* Loop counter for table elements */ int ival; /* Integer value */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the LutMap structure. */ this = (AstLutMap *) this_object; /* Write out values representing the instance variables for the LutMap class. Accompany these with appropriate comment strings, possibly depending on the values being written. */ /* Number of lookup table elements. */ astWriteInt( channel, "Nlut", 1, 1, this->nlut, "Number of lookup table elements" ); /* Input coordinate at first element centre. */ astWriteDouble( channel, "Start", ( this->start != 0.0 ), 1, this->start, "Input value at first element" ); /* Element spacing. */ astWriteDouble( channel, "Incr", ( this->inc != 1.0 ), 1, this->inc, "Input value increment between elements" ); /* Interpolation method */ set = TestLutInterp( this, status ); ival = set ? GetLutInterp( this, status ) : astGetLutInterp( this ); astWriteInt( channel, "LutInt", set, 1, ival, "Interpolation method" ); /* Lookup table contents. */ for ( ilut = 0; ilut < this->nlut; ilut++ ) { if( this->lut[ ilut ] != AST__BAD ) { (void) sprintf( buff, "L%d", ilut + 1 ); astWriteDouble( channel, buff, 1, 1, this->lut[ ilut ], ilut ? "" : "Lookup table elements..." ); } } /* Undefine macros local to this function. */ #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsALutMap and astCheckLutMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(LutMap,Mapping) astMAKE_CHECK(LutMap) AstLutMap *astLutMap_( int nlut, const double lut[], double start, double inc, const char *options, int *status, ...) { /* *++ * Name: c astLutMap f AST_LUTMAP * Purpose: * Create a LutMap. * Type: * Public function. * Synopsis: c #include "lutmap.h" c AstLutMap *astLutMap( int nlut, const double lut[], c double start, double inc, c const char *options, ... ) f RESULT = AST_LUTMAP( NLUT, LUT, START, INC, OPTIONS, STATUS ) * Class Membership: * LutMap constructor. * Description: * This function creates a new LutMap and optionally initialises * its attributes. * * A LutMap is a specialised form of Mapping which transforms * 1-dimensional coordinates by using linear interpolation in a * lookup table. Each input coordinate value is first scaled to * give the index of an entry in the table by subtracting a * starting value (the input coordinate corresponding to the first * table entry) and dividing by an increment (the difference in * input coordinate value between adjacent table entries). * * The resulting index will usually contain a fractional part, so * the output coordinate value is then generated by interpolating * linearly between the appropriate entries in the table. If the * index lies outside the range of the table, linear extrapolation * is used based on the two nearest entries (i.e. the two entries * at the start or end of the table, as appropriate). * * If the lookup table entries increase or decrease monotonically, * then the inverse transformation may also be performed. * Parameters: c nlut f NLUT = INTEGER (Given) * The number of entries in the lookup table. This value must be * at least 2. c lut f LUT( NLUT ) = DOUBLE PRECISION (Given) c An array containing the "nlut" f An array containing the * lookup table entries. c start f START = DOUBLE PRECISION (Given) * The input coordinate value which corresponds to the first lookup * table entry. c inc f INC = DOUBLE PRECISION (Given) * The lookup table spacing (the increment in input coordinate * value between successive lookup table entries). This value * may be positive or negative, but must not be zero. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new LutMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new LutMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astLutMap() f AST_LUTMAP = INTEGER * A pointer to the new LutMap. * Notes: * - If the entries in the lookup table either increase or decrease * monotonically, then the new LutMap's TranInverse attribute will * have a value of one, indicating that the inverse transformation * can be performed. Otherwise, it will have a value of zero, so * that any attempt to use the inverse transformation will result * in an error. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstLutMap *new; /* Pointer to new LutMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the LutMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitLutMap( NULL, sizeof( AstLutMap ), !class_init, &class_vtab, "LutMap", nlut, lut, start, inc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new LutMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new LutMap. */ return new; } AstLutMap *astLutMapId_( int nlut, const double lut[], double start, double inc, const char *options, ... ) { /* * Name: * astLutMapId_ * Purpose: * Create a LutMap. * Type: * Private function. * Synopsis: * #include "lutmap.h" * AstLutMap *astLutMapId( int nlut, const double lut[], * double start, double inc, * const char *options, ... ) * Class Membership: * LutMap constructor. * Description: * This function implements the external (public) interface to the * astLutMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astLutMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astLutMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astLutMap_. * Returned Value: * The ID value associated with the new LutMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstLutMap *new; /* Pointer to new LutMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the LutMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitLutMap( NULL, sizeof( AstLutMap ), !class_init, &class_vtab, "LutMap", nlut, lut, start, inc ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new LutMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new LutMap. */ return astMakeId( new ); } AstLutMap *astInitLutMap_( void *mem, size_t size, int init, AstLutMapVtab *vtab, const char *name, int nlut, const double lut[], double start, double inc, int *status ) { /* *+ * Name: * astInitLutMap * Purpose: * Initialise a LutMap. * Type: * Protected function. * Synopsis: * #include "lutmap.h" * AstLutMap *astInitLutMap( void *mem, size_t size, int init, * AstLutMapVtab *vtab, const char *name, * int nlut, const double lut[], * double start, double inc ) * Class Membership: * LutMap initialiser. * Description: * This function is provided for use by class implementations to * initialise a new LutMap object. It allocates memory (if * necessary) to accommodate the LutMap plus any additional data * associated with the derived class. It then initialises a LutMap * structure at the start of this memory. If the "init" flag is * set, it also initialises the contents of a virtual function * table for a LutMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the LutMap is to be * initialised. This must be of sufficient size to accommodate * the LutMap data (sizeof(LutMap)) plus any data used by the * derived class. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the LutMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the LutMap structure, so a valid value must be * supplied even if not required for allocating memory. * init * A logical flag indicating if the LutMap's virtual function * table is to be initialised. If this value is non-zero, the * virtual function table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be * associated with the new LutMap. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * nlut * The number of elements in the lookup table. This value must * be at least 2. * lut * An array containing the "nlut" lookup table elements. * start * The input coordinate value which corresponds with the first * lookup table element. * inc * The lookup table element spacing (i.e. the increment in input * coordinate value between successive lookup table elements). * Returned Value: * A pointer to the new LutMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstLutMap *new; /* Pointer to new LutMap */ double *luti; /* Pointer to table for inverse transformation */ double *p; /* Pointer to next lut element */ int *flagsi; /* Pointer to flags for inverse transformation */ int *indexi; /* Pointer to translation from original to reduced */ int dirn; /* +1 => values increasing, -1 => values decreasing */ int ilut; /* Loop counter for LUT elements */ int nluti; /* Length of "luti" array */ /* Initialise. */ new = NULL; /* Check the global status. */ if ( !astOK ) return new; /* If necessary, initialise the virtual function table. */ if ( init ) astInitLutMapVtab( vtab, name ); /* Check that the number of lookup table elements is valid. */ if ( nlut < 2 ) { astError( AST__LUTIN, "astInitLutMap(%s): Invalid number of lookup " "table elements (%d).", status, name, nlut ); astError( AST__LUTIN, "This value should be at least 2." , status); /* Also check that the input value increment is not zero. */ } else if ( inc == 0.0 ) { astError( AST__LUTII, "astInitLutMap(%s): An input value increment of " "zero between lookup table elements is not allowed.", status, name ); /* Determine if the element values increase or decrease monotonically (except that adjacent entries can be equal). We can only implement the inverse transformation if this is so. The inverse transformation will generate AST__BAD output values for sections of the table that contain equal adjacent values, or hold AST__BAD values. */ } else { dirn = GetMonotonic( nlut, lut, &nluti, &luti, &flagsi, &indexi, status ); /* Initialise a Mapping structure (the parent class) as the first component within the LutMap structure, allocating memory if necessary. Specify that the Mapping should be defined in the forward direction, and conditionally in the inverse direction. */ new = (AstLutMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, 1, 1, 1, ( dirn != 0 ) ); if ( astOK ) { /* Initialise the LutMap data. */ /* ---------------------------- */ new->nlut = nlut; new->start = start; new->inc = inc; new->lutinterp = LINEAR; new->nluti = nluti; new->luti = luti; new->flagsi = flagsi; new->indexi = indexi; /* Allocate memory and store the lookup table. */ new->lut = astStore( NULL, lut, sizeof( double ) * (size_t) nlut ); /* Replace an NaN values by AST__BAD */ p = new->lut; for ( ilut = 0; ilut < nlut; ilut++, p++ ) { if( !astISFINITE(*p) ) *p = AST__BAD; } /* Initialise the retained input and output coordinate values. */ new->last_fwd_in = AST__BAD; new->last_fwd_out = AST__BAD; new->last_inv_in = AST__BAD; new->last_inv_out = AST__BAD; } /* If an error occurred, clean up by deleting the new LutMap. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new LutMap. */ return new; } AstLutMap *astLoadLutMap_( void *mem, size_t size, AstLutMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadLutMap * Purpose: * Load a LutMap. * Type: * Protected function. * Synopsis: * #include "lutmap.h" * AstLutMap *astLoadLutMap( void *mem, size_t size, * AstLutMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * LutMap loader. * Description: * This function is provided to load a new LutMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * LutMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a LutMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the LutMap is to be * loaded. This must be of sufficient size to accommodate the * LutMap data (sizeof(LutMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the LutMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the LutMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstLutMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new LutMap. If this is NULL, a pointer * to the (static) virtual function table for the LutMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "LutMap" is used instead. * Returned Value: * A pointer to the new LutMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstLutMap *new; /* Pointer to the new LutMap */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ int ilut; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Loop counter for table elements */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this LutMap. In this case the LutMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstLutMap ); vtab = &class_vtab; name = "LutMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitLutMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built LutMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "LutMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* Number of lookup table elements. */ new->nlut = astReadInt( channel, "nlut", 2 ); /* Starting input coordinate value. */ new->start = astReadDouble( channel, "start", 0.0 ); /* Input coordinate value increment. */ new->inc = astReadDouble( channel, "incr", 1.0 ); /* Interpolation method */ new->lutinterp = astReadInt( channel, "lutint", LINEAR ); if ( TestLutInterp( new, status ) ) SetLutInterp( new, new->lutinterp, status ); /* Allocate memory to hold the lookup table elements. */ new->lut = astMalloc( sizeof( double ) * (size_t) new->nlut ); /* If OK, loop to read each element. */ if ( astOK ) { for ( ilut = 0; ilut < new->nlut; ilut++ ) { (void) sprintf( buff, "l%d", ilut + 1 ); new->lut[ ilut ] = astReadDouble( channel, buff, AST__BAD ); } /* Initialise the retained input and output coordinate values. */ new->last_fwd_in = AST__BAD; new->last_fwd_out = AST__BAD; new->last_inv_in = AST__BAD; new->last_inv_out = AST__BAD; /* See if the array is monotonic increasing or decreasing. */ (void) GetMonotonic( new->nlut, new->lut, &(new->nluti), &(new->luti), &(new->flagsi), &(new->indexi), status ); } } /* If an error occurred, clean up by deleting the new LutMap. */ if ( !astOK ) new = astDelete( new ); /* Return the new LutMap pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ double *astGetLutMapInfo_( AstLutMap *this, double *start, double *inc, int *nlut, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,LutMap,GetLutMapInfo))( this, start, inc, nlut, status ); } ./ast-7.3.3/config.sub0000755000175000017500000007550012245363436013140 0ustar olesoles#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-05-12' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* | -skyos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ./ast-7.3.3/globals.h0000644000175000017500000001537412262533650012750 0ustar olesoles#if !defined( GLOBALS_INCLUDED ) /* Include this file only once */ #define GLOBALS_INCLUDED 1 /* If thread-safety is required... */ #if defined( THREAD_SAFE ) && ( defined( astCLASS ) || defined( astFORTRAN77) ) /* Include files: */ /* ============== */ /* AST includes */ #include "axis.h" #include "box.h" #include "channel.h" #include "circle.h" #include "cmpframe.h" #include "cmpmap.h" #include "cmpregion.h" #include "dsbspecframe.h" #include "dssmap.h" #include "ellipse.h" #include "error.h" #include "fitschan.h" #include "fitstable.h" #include "fluxframe.h" #include "frame.h" #include "frameset.h" #include "grismmap.h" #include "interval.h" #include "intramap.h" #include "keymap.h" #include "lutmap.h" #include "mapping.h" #include "mathmap.h" #include "matrixmap.h" #include "memory.h" #include "normmap.h" #include "nullregion.h" #include "object.h" #include "pcdmap.h" #include "permmap.h" #include "plot.h" #include "plot3d.h" #include "pointlist.h" #include "pointset.h" #include "polygon.h" #include "polymap.h" #include "prism.h" #include "ratemap.h" #include "region.h" #include "selectormap.h" #include "shiftmap.h" #include "skyaxis.h" #include "skyframe.h" #include "slamap.h" #include "specfluxframe.h" #include "specframe.h" #include "specmap.h" #include "sphmap.h" #include "stc.h" #include "stccatalogentrylocation.h" #include "stcobsdatalocation.h" #include "stcresourceprofile.h" #include "stcsearchlocation.h" #include "stcschan.h" #include "switchmap.h" #include "table.h" #include "timeframe.h" #include "timemap.h" #include "tranmap.h" #include "unitmap.h" #include "wcsmap.h" #include "winmap.h" #include "xml.h" #include "xmlchan.h" #include "zoommap.h" /* System includes */ #include /* Macros */ /* ====== */ /* The name of the variable used to access thread-specific global data */ #define AST__GLOBALS ast_globals /* Defines a macro that gives access to a specific global data item. */ #define astGLOBAL(class,name) (AST__GLOBALS->class.name) /* Declares the pointer for the structure holding thread-specific values for AST global data. */ #define astDECLARE_GLOBALS AstGlobals *AST__GLOBALS; /* A macro that should be invoked in each function that refers to a global data item. The "This" parameter should be a pointer to an Object, or NULL. It ensures the thread-specific data key has been created. It also allocates and initialises memory to hold the global data. */ #define astGET_GLOBALS(This) \ \ /* If the supplied Object pointer contains a pointer to the thread-specific \ data structure, return it. */ \ if( This && ((AstObject *)This)->globals ) { \ AST__GLOBALS = ((AstObject *)This)->globals; \ \ /* Otherwise, ensure that the thread specific data key has been created. */ \ } else if( pthread_once( &starlink_ast_globals_initialised, \ astGlobalsCreateKey_ ) ) { \ AST__GLOBALS = NULL; \ fprintf( stderr, "Starlink AST package initialisation failed." ); \ \ /* If the current thread does not yet have a structure to hold \ thread-specific global data, create one now (initialising its \ contents) and associate it with the thread speciifc data key. */ \ } else if( ( AST__GLOBALS = \ pthread_getspecific( starlink_ast_globals_key ) ) == NULL ) { \ AST__GLOBALS = astGlobalsInit_(); \ if( pthread_setspecific( starlink_ast_globals_key, AST__GLOBALS ) ) { \ fprintf( stderr, "Starlink AST failed to store Thread-Specific " \ "Data pointer." ); \ } \ } /* A macro that expands to the value of a unique integer identifier for the calling thread. */ #define AST__THREAD_ID (AST__GLOBALS->thread_identifier) \ #define astMAKE_INITGLOBALS(class) \ \ void astInit##class##Globals_( Ast##class##Globals *globals ){ \ GLOBAL_inits \ } /* Type definitions */ /* ================ */ typedef struct AstGlobals { int thread_identifier; AstMemoryGlobals Memory; AstErrorGlobals Error; AstObjectGlobals Object; AstAxisGlobals Axis; AstMappingGlobals Mapping; AstFrameGlobals Frame; AstChannelGlobals Channel; AstCmpMapGlobals CmpMap; AstKeyMapGlobals KeyMap; AstFitsChanGlobals FitsChan; AstFitsTableGlobals FitsTable; AstCmpFrameGlobals CmpFrame; AstDSBSpecFrameGlobals DSBSpecFrame; AstFrameSetGlobals FrameSet; AstLutMapGlobals LutMap; AstMathMapGlobals MathMap; AstPcdMapGlobals PcdMap; AstPointSetGlobals PointSet; AstSkyAxisGlobals SkyAxis; AstSkyFrameGlobals SkyFrame; AstSlaMapGlobals SlaMap; AstSpecFrameGlobals SpecFrame; AstSphMapGlobals SphMap; AstTimeFrameGlobals TimeFrame; AstWcsMapGlobals WcsMap; AstZoomMapGlobals ZoomMap; AstFluxFrameGlobals FluxFrame; AstSpecFluxFrameGlobals SpecFluxFrame; AstGrismMapGlobals GrismMap; AstIntraMapGlobals IntraMap; AstPlotGlobals Plot; AstPlot3DGlobals Plot3D; AstRegionGlobals Region; AstBoxGlobals Box; AstXmlGlobals Xml; AstXmlChanGlobals XmlChan; AstCircleGlobals Circle; AstCmpRegionGlobals CmpRegion; AstDssMapGlobals DssMap; AstEllipseGlobals Ellipse; AstIntervalGlobals Interval; AstMatrixMapGlobals MatrixMap; AstNormMapGlobals NormMap; AstNullRegionGlobals NullRegion; AstPermMapGlobals PermMap; AstPointListGlobals PointList; AstPolyMapGlobals PolyMap; AstPolygonGlobals Polygon; AstPrismGlobals Prism; AstRateMapGlobals RateMap; AstSelectorMapGlobals SelectorMap; AstShiftMapGlobals ShiftMap; AstSpecMapGlobals SpecMap; AstStcGlobals Stc; AstStcCatalogEntryLocationGlobals StcCatalogEntryLocation; AstStcObsDataLocationGlobals StcObsDataLocation; AstSwitchMapGlobals SwitchMap; AstTableGlobals Table; AstTimeMapGlobals TimeMap; AstTranMapGlobals TranMap; AstUnitMapGlobals UnitMap; AstWinMapGlobals WinMap; AstStcResourceProfileGlobals StcResourceProfile; AstStcSearchLocationGlobals StcSearchLocation; AstStcsChanGlobals StcsChan; } AstGlobals; /* Externally declared variables */ /* ============================= */ /* The pthreads key that is associated with the thread-specific data for each thread. Declared in global.c. */ extern pthread_key_t starlink_ast_globals_key; /* The pthreads key that is associated with the thread-specific status value for each thread. Declared in global.c. */ extern pthread_key_t starlink_ast_status_key; /* This is a flag indicating that the thread-specific data key has not yet been created. Declared in globals.c. */ extern pthread_once_t starlink_ast_globals_initialised; /* Function Prototypes: */ /* ==================== */ void astGlobalsCreateKey_( void ); AstGlobals *astGlobalsInit_( void ); /* If thread-safety is not required, define some null macros. */ #else #define astDECLARE_GLOBALS #define astGET_GLOBALS(This) #define astINIT_GLOBALS #endif #endif ./ast-7.3.3/pg3d.h0000644000175000017500000000414612262533650012155 0ustar olesoles#if !defined( PG3D_INCLUDED ) /* Include this file only once */ #define PG3D_INCLUDED /* *+ * Name: * pg3d.h * Type: * C include file. * Purpose: * Define the interface to the pg3d module * Invocation: * #include "pg3d.h" * Description: * This include file defines the interface to the pg3d module * (implemented in file grf3d_pgplot.c) and provides the type * definitions, function prototypes and macros, etc. needed to * use this module. * * The functions in the pg3d interface provide control of the view * of the 3D world coordinate system visible on the 2D PGPLOT * viewport. They are provided for users of the PGPLOT implementation * of the grf3D interface distributed with AST. No calls to these * functions are made from within AST itself. * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (JACH - UCLan) * History: * 20-JUN-2007 (DSB): * Original version. *- */ int PG3DRotateEye( int, float ); int PG3DSetCamera( float[3], float[3], float[3], float ); int PG3DSetEye( float[3] ); int PG3DSetTarget( float[3] ); int PG3DSetUp( float[3] ); int PG3DSetScreen( float ); int PG3DForward( float ); int PG3DAutoCamera( float[3], float[3] ); int PG3DFindNearest( int, float *, float *, float *, int * ); #endif ./ast-7.3.3/ftimemap.c0000644000175000017500000000701512262533650013113 0ustar olesoles/* *+ * Name: * ftimemap.c * Purpose: * Define a FORTRAN 77 interface to the AST TimeMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the TimeMap class. * Routines Defined: * AST_ISATIMEMAP * AST_TIMEADD * AST_TIMEMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * NG: Norman Gray (Starlink) * History: * 08-Sep-2003 (NG): * Original version (heavily based on fspecmap.c) */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "timemap.h" /* C interface to the TimeMap class */ F77_LOGICAL_FUNCTION(ast_isatimemap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISATIMEMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsATimeMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_timeadd)( INTEGER(THIS), CHARACTER(CVT), DOUBLE_ARRAY(ARGS), INTEGER(STATUS) TRAIL(CVT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(CVT) GENPTR_DOUBLE_ARRAY(ARGS) char *cvt; astAt( "AST_TIMEADD", NULL, 0 ); astWatchSTATUS( cvt = astString( CVT, CVT_length ); astTimeAdd( astI2P( *THIS ), cvt, ARGS ); astFree( cvt ); ) } F77_INTEGER_FUNCTION(ast_timemap)( INTEGER(FLAGS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FLAGS) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_TIMEMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astTimeMap( *FLAGS, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/frame.c0000644000175000017500000213134712262533650012413 0ustar olesoles/* *class++ * Name: * Frame * Purpose: * Coordinate system description. * Constructor Function: c astFrame f AST_FRAME * Description: * This class is used to represent coordinate systems. It does this * in rather the same way that a frame around a graph describes the * coordinate space in which data are plotted. Consequently, a * Frame has a Title (string) attribute, which describes the * coordinate space, and contains axes which in turn hold * information such as Label and Units strings which are used for * labelling (e.g.) graphical output. In general, however, the * number of axes is not restricted to two. * * Functions are available for converting Frame coordinate values * into a form suitable for display, and also for calculating * distances and offsets between positions within the Frame. * * Frames may also contain knowledge of how to transform to and * from related coordinate systems. * Inheritance: * The Frame class inherits from the Mapping class. * Attributes: * In addition to those attributes common to all Mappings, every * Frame also has the following attributes (if the Frame has only one * axis, the axis specifier can be omited from the following attribute * names): * * - AlignSystem: Coordinate system used to align Frames * - Bottom(axis): Lowest axis value to display * - Digits/Digits(axis): Number of digits of precision * - Direction(axis): Display axis in conventional direction? * - Domain: Coordinate system domain * - Dut1: Difference between the UT1 and UTC timescale * - Epoch: Epoch of observation * - Format(axis): Format specification for axis values * - Label(axis): Axis label * - MatchEnd: Match trailing axes? * - MaxAxes: Maximum number of Frame axes to match * - MinAxes: Minimum number of Frame axes to match * - Naxes: Number of Frame axes * - NormUnit(axis): Normalised axis physical units * - ObsAlt: Geodetic altitude of observer * - ObsLat: Geodetic latitude of observer * - ObsLon: Geodetic longitude of observer * - Permute: Permute axis order? * - PreserveAxes: Preserve axes? * - Symbol(axis): Axis symbol * - System: Coordinate system used to describe the domain * - Title: Frame title * - Top(axis): Highest axis value to display * - Unit(axis): Axis physical units * Functions: c In addition to those functions applicable to all Mappings, the c following functions may also be applied to all Frames: f In addition to those routines applicable to all Mappings, the f following routines may also be applied to all Frames: * c - astAngle: Calculate the angle subtended by two points at a third point c - astAxAngle: Find the angle from an axis, to a line through two points c - astAxDistance: Calculate the distance between two axis values c - astAxOffset: Calculate an offset along an axis c - astConvert: Determine how to convert between two coordinate systems c - astDistance: Calculate the distance between two points in a Frame c - astFindFrame: Find a coordinate system with specified characteristics c - astFormat: Format a coordinate value for a Frame axis c - astGetActiveUnit: Determines how the Unit attribute will be used c - astIntersect: Find the intersection between two geodesic curves c - astMatchAxes: Find any corresponding axes in two Frames c - astNorm: Normalise a set of Frame coordinates c - astOffset: Calculate an offset along a geodesic curve c - astOffset2: Calculate an offset along a geodesic curve in a 2D Frame c - astPermAxes: Permute the order of a Frame's axes c - astPickAxes: Create a new Frame by picking axes from an existing one c - astResolve: Resolve a vector into two orthogonal components c - astSetActiveUnit: Specify how the Unit attribute should be used c - astUnformat: Read a formatted coordinate value for a Frame axis f - AST_ANGLE: Find the angle subtended by two points at a third point f - AST_AXANGLE: Find the angle from an axis, to a line through two points f - AST_AXDISTANCE: Calculate the distance between two axis values f - AST_AXOFFSET: Calculate an offset along an axis f - AST_CONVERT: Determine how to convert between two coordinate systems f - AST_DISTANCE: Calculate the distance between two points in a Frame f - AST_FINDFRAME: Find a coordinate system with specified characteristics f - AST_FORMAT: Format a coordinate value for a Frame axis f - AST_GETACTIVEUNIT: Determines how the Unit attribute will be used f - AST_INTERSECT: Find the intersection between two geodesic curves f - AST_MATCHAXES: Find any corresponding axes in two Frames f - AST_NORM: Normalise a set of Frame coordinates f - AST_OFFSET: Calculate an offset along a geodesic curve f - AST_OFFSET2: Calculate an offset along a geodesic curve in a 2D Frame f - AST_PERMAXES: Permute the order of a Frame's axes f - AST_PICKAXES: Create a new Frame by picking axes from an existing one f - AST_RESOLVE: Resolve a vector into two orthogonal components f - AST_SETACTIVEUNIT: Specify how the Unit attribute should be used f - AST_UNFORMAT: Read a formatted coordinate value for a Frame axis * Notes: * - When used as a Mapping, a Frame implements a unit (null) * transformation in both the forward and inverse directions * (equivalent to a UnitMap). The Nin and Nout attribute values are * both equal to the number of Frame axes. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: B.S. Berry (Starlink) * History: * 1-MAR-1996 (RFWS): * Original version. * 4-JUN-1996 (RFWS): * Added the CleanDomain function to fold all Domain strings to * upper case and remove white space. * 12-JUL-1996 (RFWS): * Over-ride the astReportPoints method to provide * Frame-specific formatting. * 11-SEP-1996 (RFWS): * Added astGap (written by DSB). * 10-JUN-1997 (RFWS): * Re-implemented astConvert and astFindFrame. * 1-SEP-1997 (RFWS): * Added missing return statement in astAbbrev_. * 14-NOV-1997 (RFWS): * Fixed wrong amount of memory allocated in ValidateAxisSelection. * 20-NOV-1997 (RFWS): * Updated astConvert prologue. * 22-DEC-1997 (RFWS): * Updated astConvert prologue again. * 15-FEB-1998 (RFWS): * Added astUnformat. * 2-MAR-1999 (RFWS); * Fixed missing STATUS arguments in examples for AST_FINDFRAME * prologue. * 18-JUL-1999 (RFWS): * Fixed memory leak in ConvertX. * 21-JUN-2001 (DSB): * Added methods astAngle and astOffset2. * 29-AUG-2001 (DSB): * Added methods astAxDistance and astAxOffset. * 4-SEP-2001 (DSB): * Added method astResolve. * 9-SEP-2001 (DSB): * Added method astBear. * 21-SEP-2001 (DSB): * Replaced astBear with astAxAngle. * 10-OCT-2002 (DSB): * Added Top and Bottom. * 15-NOV-2002 (DSB): * Moved the System and Epoch attributes from the SkyFrame class to * this class. Added virtual method astValidateSystem, astSystemString, * astSystemCode. Added attribute AlignSystem. * 17-DEC-2002 (DSB): * Added the GetActiveUnit, TestActiveUnit and SetActiveUnit functions. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitFrameVtab * method. * 15-SEP-2003 (DSB): * Allow Frame attribute names to include an axis specifier within * GetAttrib, SetAttrib, TestAttrib and ClearAttrib (eg "Domain(1)" * is now accepted as equivalent to "Domain"). * 24-JAN-2004 (DSB): * o Added astFields. * o Added argument "fmt" to Abbrev. * 24-MAR-2004 (DSB): * Add protected function astIsUnitFrame. * 7-SEP-2004 (DSB): * Modified SetUnit to exclude any trailing spaces * 8-SEP-2004 (DSB): * - Added astResolvePoints. * - Override astEqual. * 29-NOV-2004 (DSB): * - Set/Get/Test/ClearAttrib: Allow axis specifier to be omitted from * axis attribute names if the Frame only has one axis. * 2-FEB-2005 (DSB): * - Avoid using astStore to allocate more storage than is supplied * in the "data" pointer. This can cause access violations since * astStore will then read beyond the end of the "data" area. * 17-FEB-2005 (DSB): * - Change use of ActiveUnit flag so that both target and template * Frames must have active units in order for the Mapping to take * account of differences in units. Previously, the test was based * on the template Frame alone. * 23-MAR-2005 (DSB): * - GetActiveUnit: Always return zero if the Frame contains any * SkyAxes. * 5-APR-2005 (DSB): * Correct error checking in Clear/Get/Set/TestAttrib. * 12-MAY-2005 (DSB): * Added astNormBox method. * 16-JUN-2005 (DSB): * Added documentation for the TimeFrame class. * 12-AUG-2005 (DSB): * Added ObsLat and ObsLon attributes. * 1-MAR-2006 (DSB): * Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM. * 15-MAY-2006 (DSB): * Remove unused global variable parent_equal. * 26-JUN-2006 (DSB): * Document the use of the Direction attribute by the Plot class. * 30-JUN-2006 (DSB): * Allow astAbbrev to have a null "str1" value. * 16-AUG-2006 (DSB): * Correct "Class Applicability" to "Applicability". * 5-OCT-2006 (DSB): * Increase the number of digits used when formating a ObsLon or * ObsLat value in GetAttrib. * 14-OCT-2006 (DSB): * - Add Dut1 attribute * 26-JAN-2007 (DSB): * Fix bug in NewUnit that causes segvio when changing axis symbols * to accomodate changes in units. * 17-MAY-2007 (DSB): * Added read-only attribute NormUnit. * 21-MAY-2007 (DSB): * Use rather than ignore the value returned by astTestAxisDigits in * TestAttrib. * 25-JUN-2007 (DSB): * Documentation typos. * 26-NOV-2007 (DSB): * In Clear/Get/Set/TestAttrib, include any appropriate axis index in * the attribute name when attempting to get the attribute value from * the primary frame * 17-NOV-2008 (DSB): * Correct parent class in invocation of astMAKE_ISA. * 14-JAN-2009 (DSB): * Added astIntersect. * 18-MAR-2009 (DSB): * Fixed bug in LineCrossing. * 18-JUN-2000 (DSB): * Added ObsAlt attribute. * 28-SEP-2009 (DSB): * Added astMatchAxes method. * 22-MAR-2011 (DSB): * Add astFrameGrid method. * 29-APR-2011 (DSB): * Prevent astFindFrame from matching a subclass template against a * superclass target. * 11-APR-2012 (DSB): * Change astValidateAxis so that it can permute in either direction. * 29-APR-2013 (DSB): * Added protected methods astSetFrameVariants and astGetFrameVariants. * 1-MAY-2013 (DSB): * Override the astDoNotSimplify method to indicate that Frames should * always be simplified. This is mainly because the STC class uses the * Ident attribute with Frames, and preventing such frames from * simplifying (which is what the parent astDoNotSimplify method does) * causes the STC tester in the ast_tester directory to fail. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS Frame /* Define numerical constants for use in this module. */ #define LABEL_BUFF_LEN 100 /* Max length of default axis Label string */ #define SYMBOL_BUFF_LEN 50 /* Max length of default axis Symbol string */ #define TITLE_BUFF_LEN 100 /* Max length of default title string */ #define GETATTRIB_BUFF_LEN 50 /* Max length of string returned by GetAttrib */ #define ASTFMTDECIMALYR_BUFF_LEN 50 /* Max length of string returned by GetAttrib */ #define ASTFORMATID_MAX_STRINGS 50 /* Number of string values buffer by astFormatID*/ /* Define the first and last acceptable System values. */ #define FIRST_SYSTEM AST__CART #define LAST_SYSTEM AST__CART /* Define macros to implement methods for accessing axis attributes. */ /* * Name: * MAKE_CLEAR * Purpose: * Implement a method to clear an attribute value for a Frame axis. * Type: * Private macro. * Synopsis: * #include "frame.h" * MAKE_CLEAR(attribute) * Class Membership: * Defined by the Frame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Clear( AstFrame *this, int axis ) * * and an external interface function of the form: * * void astClear_( AstFrame *this, int axis ) * * which implement a method for clearing an attribute value for a specified * axis of a Frame. * Parameters: * attribute * The name of the attribute to be cleared, as it appears in the * function name (e.g. Label in "astClearLabel"). * Notes: * - This macro assumes the existence of a method of the form: * * void astClearAxis( AstAxis *this ) * * which clears the required attribute for an Axis object. * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. */ /* Define the macro. */ #define MAKE_CLEAR(attribute) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Clear##attribute( AstFrame *this, int axis, int *status ) { \ AstAxis *ax; /* Pointer to Axis object */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index and obtain a pointer to the required Axis. */ \ (void) astValidateAxis( this, axis, 1, "astClear" #attribute ); \ ax = astGetAxis( this, axis ); \ \ /* Clear the Axis attribute. */ \ astClearAxis##attribute( ax ); \ \ /* Annul the Axis pointer. */ \ ax = astAnnul( ax ); \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astClear##attribute##_( AstFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,Frame,Clear##attribute))( this, axis, status ); \ } /* * Name: * MAKE_GET * Purpose: * Implement a method to get an attribute value for a Frame axis. * Type: * Private macro. * Synopsis: # #include "frame.h" * MAKE_GET(attribute,type,bad_value,default,assign_default) * Class Membership: * Defined by the Frame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( AstFrame *this, int axis ) * * and an external interface function of the form: * * Type astGet_( AstFrame *this, int axis ) * * which implement a method for getting an attribute value for a specified * axis of a Frame. * Parameters: * attribute * The name of the attribute whose value is to be obtained, as * it appears in the function name (e.g. Label in * "astGetLabel"). * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * default * A boolean (int) constant that indicates whether a new default value * should be returned by the method if the requested attribute has not * been set for the axis. If this value is zero, the axis default will * be used instead. * assign_default * An expression that evaluates to the new default value to be assigned. * This value is ignored if "default" is zero, but a valid (e.g. * constant) value should nevertheless be supplied. * Notes: * - This macro assumes the existence of a method of the form: * * astGetAxis( AstAxis *this ) * * which gets the required attribute for an Axis object. * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. */ /* Define the macro. */ #define MAKE_GET(attribute,type,bad_value,default,assign_default) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type Get##attribute( AstFrame *this, int axis, int *status ) { \ AstAxis *ax; /* Pointer to Axis object */ \ int digits_set; /* Axis Digits attribute set? */ \ int old_axis; /* Original (un-permuted) axis index */ \ type result; /* Result to be returned */ \ \ /* Initialise. */ \ result = (bad_value); \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate and permute the axis index and obtain a pointer to the required \ Axis. */ \ old_axis = axis; \ axis = astValidateAxis( this, axis, 1, "astGet" #attribute ); \ ax = astGetAxis( this, old_axis ); \ \ /* Since the Axis is "managed" by the enclosing Frame, we next test if any \ Axis attributes which may affect the result are undefined (i.e. have not \ been explicitly set). If so, we over-ride them, giving them temporary \ values dictated by the Frame. Only the Digits attribute is relevant \ here. */ \ digits_set = astTestAxisDigits( ax ); \ if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) ); \ \ /* If the default value is to be over-ridden, test if the Axis attribute has \ been set. Then, if required, obtain the attribute value from the Axis. */ \ if ( !(default) || astTestAxis##attribute( ax ) ) { \ result = astGetAxis##attribute( ax ); \ \ /* If required, assign the new default value. */ \ } else { \ result = (assign_default); \ } \ \ /* Clear Axis attributes which were temporarily over-ridden above and annul \ the Axis pointer. */ \ if ( !digits_set ) astClearAxisDigits( ax ); \ ax = astAnnul( ax ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } \ \ /* External interface. */ \ /* ------------------- */ \ type astGet##attribute##_( AstFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,Frame,Get##attribute))( this, axis, status ); \ } /* * Name: * MAKE_SET * Purpose: * Implement a method to set an attribute value for a Frame axis. * Type: * Private macro. * Synopsis: * #include "frame.h" * MAKE_SET(attribute,type) * Class Membership: * Defined by the Frame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( AstFrame *this, int axis, value ) * * and an external interface function of the form: * * void astSet_( AstFrame *this, int axis, value ) * * which implement a method for setting an attribute value for a specified * axis of a Frame. * Parameters: * attribute * The name of the attribute to be set, as it appears in the * function name (e.g. Label in "astSetLabel"). * type * The C type of the attribute. * Notes: * - This macro assumes the existence of a method of the form: * * void astSetAxis( AstAxis *this, value ) * * which sets the required attribute for an Axis object. * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. */ /* Define the macro. */ #define MAKE_SET(attribute,type) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Set##attribute( AstFrame *this, int axis, type value, int *status ) { \ AstAxis *ax; /* Pointer to Axis object */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index and obtain a pointer to the required Axis. */ \ (void) astValidateAxis( this, axis, 1, "astSet" #attribute ); \ ax = astGetAxis( this, axis ); \ \ /* Set the Axis attribute value. */ \ astSetAxis##attribute( ax, value ); \ \ /* Annul the Axis pointer. */ \ ax = astAnnul( ax ); \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astSet##attribute##_( AstFrame *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,Frame,Set##attribute))( this, axis, value, status ); \ } /* * Name: * MAKE_TEST * Purpose: * Implement a method to test if an attribute has been set for a Frame axis. * Type: * Private macro. * Synopsis: * #include "frame.h" * MAKE_TEST(attribute) * Class Membership: * Defined by the Frame class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static int Test( AstFrame *this, int axis ) * * and an external interface function of the form: * * int astTest_( AstFrame *this, int axis ) * * which implement a method for testing if an attribute has been set for a * specified axis of a Frame. * Parameters: * attribute * The name of the attribute to be tested, as it appears in the * function name (e.g. Label in "astTestLabel"). * Notes: * - This macro assumes the existence of a method of the form: * * void astTestAxis( AstAxis *this ) * * which tests the required attribute for an Axis object. * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. */ /* Define the macro. */ #define MAKE_TEST(attribute) \ \ /* Private member function. */ \ /* ------------------------ */ \ static int Test##attribute( AstFrame *this, int axis, int *status ) { \ AstAxis *ax; /* Pointer to Axis object */ \ int result; /* Value to be returned */ \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Validate the axis index and obtain a pointer to the required Axis. */ \ (void) astValidateAxis( this, axis, 1, "astTest" #attribute ); \ ax = astGetAxis( this, axis ); \ \ /* Test if the attribute has been set. */ \ result = astTestAxis##attribute( ax ); \ \ /* Annul the Axis pointer. */ \ ax = astAnnul( ax ); \ \ /* If an error occurred, clear the result value. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } \ \ /* External interface. */ \ /* ------------------- */ \ int astTest##attribute##_( AstFrame *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,Frame,Test##attribute))( this, axis, status ); \ } /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "pointset.h" /* Sets of points */ #include "unitmap.h" /* Unit Mapping */ #include "permmap.h" /* Coordinate permutation Mapping */ #include "cmpmap.h" /* Compound Mappings */ #include "axis.h" /* Coordinate Axis */ #include "skyaxis.h" /* Sky coordinate axes */ #include "skyframe.h" /* Celestial coordinate frames */ #include "channel.h" /* I/O channels */ #include "frame.h" /* Interface definition for this class */ #include "frameset.h" /* Collections of Frames */ #include "cmpframe.h" /* Compound Frames */ #include "pal.h" /* SLALIB library interface */ #include "unit.h" /* Units identification and mapping */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static void (* parent_cleanattribs)( AstObject *, int * ); static int (* parent_getobjsize)( AstObject *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* Define a variable to hold a SkyFrame which will be used for formatting and unformatting ObsLat and ObsLon values. */ static AstSkyFrame *skyframe; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->AstFormatID_Init = 0; \ globals->AstFormatID_Istr = 0; \ globals->Label_Buff[ 0 ] = 0; \ globals->Symbol_Buff[ 0 ] = 0; \ globals->Title_Buff[ 0 ] = 0; \ globals->AstFmtDecimalYr_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(Frame) #define class_init astGLOBAL(Frame,Class_Init) #define class_vtab astGLOBAL(Frame,Class_Vtab) #define getattrib_buff astGLOBAL(Frame,GetAttrib_Buff) #define astformatid_strings astGLOBAL(Frame,AstFormatID_Strings) #define astformatid_istr astGLOBAL(Frame,AstFormatID_Istr) #define astformatid_init astGLOBAL(Frame,AstFormatID_Init) #define label_buff astGLOBAL(Frame,Label_Buff) #define symbol_buff astGLOBAL(Frame,Symbol_Buff) #define title_buff astGLOBAL(Frame,Title_Buff) #define astfmtdecimalyr_buff astGLOBAL(Frame,AstFmtDecimalYr_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Buffer returned by GetAttrib. */ static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ]; /* Strings returned by astFormatID */ static char *astformatid_strings[ ASTFORMATID_MAX_STRINGS ]; /* Offset of next string in "AstFormatID_Strings" */ static int astformatid_istr; /* "AstFormatID_Strings" array initialised? */ static int astformatid_init; /* Default Label string buffer */ static char label_buff[ LABEL_BUFF_LEN + 1 ]; /* Default Symbol buffer */ static char symbol_buff[ SYMBOL_BUFF_LEN + 1 ]; /* Default Title string buffer */ static char title_buff[ TITLE_BUFF_LEN + 1 ]; /* Buffer for result string */ static char astfmtdecimalyr_buff[ ASTFMTDECIMALYR_BUFF_LEN + 1 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstFrameVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstAxis *GetAxis( AstFrame *, int, int * ); static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * ); static AstFrameSet *Convert( AstFrame *, AstFrame *, const char *, int * ); static AstFrameSet *ConvertX( AstFrame *, AstFrame *, const char *, int * ); static AstFrameSet *FindFrame( AstFrame *, AstFrame *, const char *, int * ); static void MatchAxes( AstFrame *, AstFrame *, int *, int * ); static void MatchAxesX( AstFrame *, AstFrame *, int *, int * ); static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * ); static AstPointSet *FrameGrid( AstFrame *, int, const double *, const double *, int * ); static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static char *CleanDomain( char *, int * ); static const char *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * ); static const char *Format( AstFrame *, int, double, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetDefaultLabel( int, int * ); static const char *GetDefaultSymbol( AstFrame *, int, int * ); static const char *GetDefaultTitle( AstFrame *, int * ); static const char *GetDomain( AstFrame *, int * ); static const char *GetFormat( AstFrame *, int, int * ); static const char *GetLabel( AstFrame *, int, int * ); static const char *GetNormUnit( AstFrame *, int, int * ); static const char *GetSymbol( AstFrame *, int, int * ); static const char *GetTitle( AstFrame *, int * ); static const char *GetUnit( AstFrame *, int, int * ); static const int *GetPerm( AstFrame *, int * ); static double Angle( AstFrame *, const double[], const double[], const double[], int * ); static double AxAngle( AstFrame *, const double[], const double[], int, int * ); static double AxDistance( AstFrame *, int, double, double, int * ); static double AxOffset( AstFrame *, int, double, double, int * ); static double Distance( AstFrame *, const double[], const double[], int * ); static double Gap( AstFrame *, int, double, int *, int * ); static double Offset2( AstFrame *, const double[2], double, double, double[2], int * ); static int AxIn( AstFrame *, int, double, double, double, int, int * ); static int ConsistentMaxAxes( AstFrame *, int, int * ); static int ConsistentMinAxes( AstFrame *, int, int * ); static int DefaultMaxAxes( AstFrame *, int * ); static int DefaultMinAxes( AstFrame *, int * ); static int DoNotSimplify( AstMapping *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * ); static int GetDigits( AstFrame *, int * ); static int GetDirection( AstFrame *, int, int * ); static int GetIsLinear( AstMapping *, int * ); static int GetIsSimple( AstMapping *, int * ); static int LineContains( AstFrame *, AstLineDef *, int, double *, int * ); static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * ); static int GetObjSize( AstObject *, int * ); static void CleanAttribs( AstObject *, int * ); static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * ); static double GetTop( AstFrame *, int, int * ); static int TestTop( AstFrame *, int, int * ); static void ClearTop( AstFrame *, int, int * ); static void SetTop( AstFrame *, int, double, int * ); static double GetBottom( AstFrame *, int, int * ); static int TestBottom( AstFrame *, int, int * ); static void ClearBottom( AstFrame *, int, int * ); static void SetBottom( AstFrame *, int, double, int * ); static AstSystemType GetSystem( AstFrame *, int * ); static int TestSystem( AstFrame *, int * ); static void ClearSystem( AstFrame *, int * ); static void SetSystem( AstFrame *, AstSystemType, int * ); static AstSystemType GetAlignSystem( AstFrame *, int * ); static int TestAlignSystem( AstFrame *, int * ); static void ClearAlignSystem( AstFrame *, int * ); static void SetAlignSystem( AstFrame *, AstSystemType, int * ); static double GetEpoch( AstFrame *, int * ); static int TestEpoch( AstFrame *, int * ); static void ClearEpoch( AstFrame *, int * ); static void SetEpoch( AstFrame *, double, int * ); static double GetObsLat( AstFrame *, int * ); static int TestObsLat( AstFrame *, int * ); static void ClearObsLat( AstFrame *, int * ); static void SetObsLat( AstFrame *, double, int * ); static double GetObsLon( AstFrame *, int * ); static int TestObsLon( AstFrame *, int * ); static void ClearObsLon( AstFrame *, int * ); static void SetObsLon( AstFrame *, double, int * ); static double GetObsAlt( AstFrame *, int * ); static int TestObsAlt( AstFrame *, int * ); static void ClearObsAlt( AstFrame *, int * ); static void SetObsAlt( AstFrame *, double, int * ); static double GetDut1( AstFrame *, int * ); static int TestDut1( AstFrame *, int * ); static void ClearDut1( AstFrame *, int * ); static void SetDut1( AstFrame *, double, int * ); static int GetActiveUnit( AstFrame *, int * ); static int TestActiveUnit( AstFrame *, int * ); static void SetActiveUnit( AstFrame *, int, int * ); static AstFrameSet *GetFrameVariants( AstFrame *, int * ); static void SetFrameVariants( AstFrame *, AstFrameSet *, int * ); static int GetFrameFlags( AstFrame *, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); static int GetMatchEnd( AstFrame *, int * ); static int GetMaxAxes( AstFrame *, int * ); static int GetMinAxes( AstFrame *, int * ); static int GetNaxes( AstFrame *, int * ); static int GetNin( AstMapping *, int * ); static int GetNout( AstMapping *, int * ); static int GetPermute( AstFrame *, int * ); static int GetPreserveAxes( AstFrame *, int * ); static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int TestDigits( AstFrame *, int * ); static int TestDirection( AstFrame *, int, int * ); static int TestDomain( AstFrame *, int * ); static int TestFormat( AstFrame *, int, int * ); static int TestLabel( AstFrame *, int, int * ); static int TestMatchEnd( AstFrame *, int * ); static int TestMaxAxes( AstFrame *, int * ); static int TestMinAxes( AstFrame *, int * ); static int TestPermute( AstFrame *, int * ); static int TestPreserveAxes( AstFrame *, int * ); static int TestSymbol( AstFrame *, int, int * ); static int TestTitle( AstFrame *, int * ); static int TestUnit( AstFrame *, int, int * ); static int IsUnitFrame( AstFrame *, int * ); static int Unformat( AstFrame *, int, const char *, double *, int * ); static int ValidateAxis( AstFrame *, int, int, const char *, int * ); static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * ); static AstSystemType SystemCode( AstFrame *, const char *, int * ); static const char *SystemString( AstFrame *, AstSystemType, int * ); static void AddUnderscores( char *, int * ); static void CheckPerm( AstFrame *, const int *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void ClearDigits( AstFrame *, int * ); static void ClearDirection( AstFrame *, int, int * ); static void ClearDomain( AstFrame *, int * ); static void ClearFormat( AstFrame *, int, int * ); static void ClearLabel( AstFrame *, int, int * ); static void ClearMatchEnd( AstFrame *, int * ); static void ClearMaxAxes( AstFrame *, int * ); static void ClearMinAxes( AstFrame *, int * ); static void ClearPermute( AstFrame *, int * ); static void ClearPreserveAxes( AstFrame *, int * ); static void ClearSymbol( AstFrame *, int, int * ); static void ClearTitle( AstFrame *, int * ); static void ClearUnit( AstFrame *, int, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * ); static void Norm( AstFrame *, double[], int * ); static void NormBox( AstFrame *, double[], double[], AstMapping *, int * ); static void Offset( AstFrame *, const double[], const double[], double, double[], int * ); static void Overlay( AstFrame *, const int *, AstFrame *, int * ); static void PermAxes( AstFrame *, const int[], int * ); static void PrimaryFrame( AstFrame *, int, AstFrame **, int *, int * ); static void ReportPoints( AstMapping *, int, AstPointSet *, AstPointSet *, int * ); static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SetAxis( AstFrame *, int, AstAxis *, int * ); static void SetDigits( AstFrame *, int, int * ); static void SetDirection( AstFrame *, int, int, int * ); static void SetDomain( AstFrame *, const char *, int * ); static void SetFormat( AstFrame *, int, const char *, int * ); static void SetFrameFlags( AstFrame *, int, int * ); static void SetLabel( AstFrame *, int, const char *, int * ); static void SetMatchEnd( AstFrame *, int, int * ); static void SetMaxAxes( AstFrame *, int, int * ); static void SetMinAxes( AstFrame *, int, int * ); static void SetPermute( AstFrame *, int, int * ); static void SetPreserveAxes( AstFrame *, int, int * ); static void SetSymbol( AstFrame *, int, const char *, int * ); static void SetTitle( AstFrame *, const char *, int * ); static void SetUnit( AstFrame *, int, const char *, int * ); static void NewUnit( AstAxis *, const char *, const char *, const char *, const char *, int * ); static void ValidateAxisSelection( AstFrame *, int, const int *, const char *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static const char *Abbrev( AstFrame *this, int axis, const char *fmt, const char *str1, const char *str2, int *status ) { /* *+ * Name: * astAbbrev * Purpose: * Abbreviate a formatted Frame axis value by skipping leading fields. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * const char *astAbbrev( AstFrame *this, int axis, const char *fmt, * const char *str1, const char *str2 ) * Class Membership: * Frame method. * Description: * This function compares two Frame axis values that have been * formatted (using astFormat) and determines if they have any * redundant leading fields (i.e. leading fields in common which * can be suppressed when tabulating the values or plotting them on * the axis of a graph). * Parameters: * this * Pointer to the Frame. * axis * The number of the Frame axis for which the values have been * formatted (axis numbering starts at zero for the first axis). * fmt * Pointer to a constant null-terminated string containing the * format specification used to format the two values. * str1 * Pointer to a constant null-terminated string containing the * first formatted value. If this is null, the returned pointer * points to the start of the final field in str2. * str2 * Pointer to a constant null-terminated string containing the * second formatted value. * Returned Value: * A pointer into the "str2" string which locates the first * character in the first field that differs between the two * formatted values. * * If the two values have no leading fields in common, the returned * value will point at the start of string "str2". If the two * values are equal, it will point at the terminating null at the * end of this string. * Notes: * - This function assumes that the format specification used was * the same when both values were formatted and that they both * apply to the same Frame axis. * - A pointer to the start of "str2" will be returned if this * function is invoked with the global error status set, or if it * should fail for any reason. *- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ const char *result; /* Result pointer to return */ /* Initialise. */ result = str2; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astAbbrev" ); ax = astGetAxis( this, axis ); /* Invoke the Axis astAxisAbbrev method to perform the processing. */ result = astAxisAbbrev( ax, fmt, str1, str2 ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = str2; /* Return the result. */ return result; } static void AddUnderscores( char *string, int *status ) { /* * Name: * AddUnderscores * Purpose: * Add underscores to a string in place of white space. * Type: * Private function. * Synopsis: * #include "frame.h" * void AddUnderscores( char *string, int *status ) * Class Membership: * Frame member function. * Description: * This function changes all white space characters in a string into * the underscore character '_'. * Parameters: * this * Pointer to the Frame. * string * Pointer to the null terminated string to be processed. * status * Pointer to the inherited status variable. */ /* Local Variables. */ int i; /* Loop counter for characters */ /* Inspect each character in the string. */ for ( i = 0; string[ i ]; i++ ) { /* If it is a white space character, replace it with an underscore. */ if ( isspace( string[ i ] ) ) string[ i ] = '_'; } } static double Angle( AstFrame *this, const double a[], const double b[], const double c[], int *status ) { /* *++ * Name: c astAngle f AST_ANGLE * Purpose: * Calculate the angle subtended by two points at a third point. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astAngle( AstFrame *this, const double a[], const double b[], c const double c[] ) f RESULT = AST_ANGLE( THIS, A, B, C, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * finds the angle at point B between the line joining points A and B, * and the line joining points C and B. These lines will in fact be * geodesic curves appropriate to the Frame in use. For instance, in * SkyFrame, they will be great circles. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c a f A( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the first point. c b f B( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the second point. c c f C( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the third point. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astAngle f AST_ANGLE = DOUBLE PRECISION * The angle in radians, from the line AB to the line CB. If the * Frame is 2-dimensional, it will be in the range $\pm \pi$, * and positive rotation is in the same sense as rotation from * the positive direction of axis 2 to the positive direction of * axis 1. If the Frame has more than 2 axes, a positive value will * always be returned in the range zero to $\pi$. * Notes: * - A value of AST__BAD will also be returned if points A and B are * co-incident, or if points B and C are co-incident. * - A value of AST__BAD will also be returned if this function is c invoked with the AST error status set, or if it should fail for f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- */ /* Local Variables: */ double *ab; /* Pointer to vector AB */ double *cb; /* Pointer to vector CB */ double cos; /* cosine of required angle */ double anga; /* Angle from +ve Y to the line BA */ double angc; /* Angle from +ve Y to the line BC */ double result; /* Result value to return */ double sla; /* Squared length of vector AB */ double slc; /* Squared length of vector CB */ double sp; /* Scalar product of AB and CB */ int axis; /* Axis index */ int naxes; /* Number of Frame axes */ int ok; /* Supplied points OK? */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Assume everything is ok */ ok = 1; /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); /* Obtain workspace. */ ab = (double *) astMalloc( sizeof(double)*naxes ); cb = (double *) astMalloc( sizeof(double)*naxes ); /* Check all positions are good, and form the vectors from b to a, and from b to c. Also find the squared length of each vector. */ if( astOK ) { sla = 0.0; slc = 0.0; for( axis = 0; axis < naxes; axis++ ) { if( a[ axis ] == AST__BAD || b[ axis ] == AST__BAD || c[ axis ] == AST__BAD ) { ok = 0; break; } else { ab[ axis ] = a[ axis ] - b[ axis ]; cb[ axis ] = c[ axis ] - b[ axis ]; sla += ( ab[ axis ] )*( ab[ axis ] ); slc += ( cb[ axis ] )*( cb[ axis ] ); } } /* Check that neither of the vectors have zero length. */ if( sla == 0 || slc == 0 ) ok = 0; /* Only proceed if these checks were passed. */ if ( ok ) { /* Deal first with 2-dimensional Frames. */ if( naxes == 2 ) { /* Find the angle from +ve Y to the line BA. */ anga = atan2( ab[ 0 ], ab[ 1 ] ); /* Find the angle from +ve Y to the line BC. */ angc = atan2( cb[ 0 ], cb[ 1 ] ); /* Find the difference, folded into the range +/- PI. */ result = palDrange( angc - anga ); /* Now deal with Frames with more than 2 axes. */ } else { /* Form the scalar product of the two vectors. */ sp = 0.0; for( axis = 0; axis < naxes; axis++ ) { sp += ab[ axis ]*cb[ axis ]; } /* Derive the required angle from the normalized scalar product. */ cos = sp/sqrt( sla*slc ); if( cos > 1.0 ) { cos = 1.0; } else if( cos < -1.0 ) { cos = -1.0; } result =acos( cos ); } } } /* Free the work space. */ ab = (double *) astFree( (void *) ab ); cb = (double *) astFree( (void *) cb ); /* Return the result. */ return result; } static double AxAngle( AstFrame *this, const double a[], const double b[], int axis, int *status ) { /* *++ * Name: c astAxAngle f AST_AXANGLE * Purpose: * Returns the angle from an axis, to a line through two points. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astAxAngle( AstFrame *this, const double a[], const double b[], int axis ) f RESULT = AST_AXANGLE( THIS, A, B, AXIS, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * finds the angle, as seen from point A, between the positive * direction of a specified axis, and the geodesic curve joining point * A to point B. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c a f A( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the first point. c b f B( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the second point. c axis f AXIS = INTEGER (Given) * The number of the Frame axis from which the angle is to be * measured (axis numbering starts at 1 for the first axis). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astAxAngle f AST_AXANGLE = DOUBLE PRECISION * The angle in radians, from the positive direction of the * specified axis, to the line AB. If the Frame is 2-dimensional, * it will be in the range [-PI/2,+PI/2], and positive rotation is in * the same sense as rotation from the positive direction of axis 2 * to the positive direction of axis 1. If the Frame has more than 2 * axes, a positive value will always be returned in the range zero * to PI. * Notes: c - The geodesic curve used by this function is the path of f - The geodesic curve used by this routine is the path of * shortest distance between two points, as defined by the c astDistance function. f AST_DISTANCE function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the require * position angle is undefined. *-- */ /* Local Variables: */ double *aa; /* Pointer to third point */ double ab; /* Absolute value of component */ double mxab; /* Largest absolute value of component */ double result; /* The returned value */ int iaxis; /* Axis index */ int naxes; /* Number of Frame axes */ int ok; /* Are values ok to use? */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the axis index. */ (void) astValidateAxis( this, axis - 1, 1, "astAxAngle" ); /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); /* Obtain workspace. */ aa = (double *) astMalloc( sizeof(double)*naxes ); /* Create a position which is offset slightly from point A in the positive direction of the specified axis. Also get the largest absolute value of any component of the vector AB. */ if( astOK ) { ok = 1; mxab = 0.0; for( iaxis = 0; iaxis < naxes; iaxis++ ) { if( a[ iaxis ] != AST__BAD && b[ iaxis ] != AST__BAD ) { aa[ iaxis ] = a[ iaxis ]; ab = fabs( a[ iaxis ] - b[ iaxis ] ); if( ab > mxab ) mxab = ab; } else { ok = 0; break; } } if( ok ) { if( a[ axis - 1 ] != 0.0 ) { aa[ axis - 1 ] += 10000.0*DBL_EPSILON*fabs( a[ axis - 1 ] ); } else if( b[ axis - 1 ] != 0.0 ) { aa[ axis - 1 ] = 10000.0*DBL_EPSILON*fabs( b[ iaxis - 1 ] ); } else if( mxab != 0.0 ) { aa[ axis - 1 ] = 10000.0*DBL_EPSILON*mxab; } else { aa[ axis - 1 ] = 1.0; } /* Use astAngle to get the required angle. */ result = astAngle( this, aa, a, b ); } } /* Free the workspace. */ aa = (double *) astFree( (void *) aa ); /* Return the result. */ return result; } static double AxDistance( AstFrame *this, int axis, double v1, double v2, int *status ) { /* *++ * Name: c astAxDistance f AST_AXDISTANCE * Purpose: * Find the distance between two axis values. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astAxDistance( AstFrame *this, int axis, double v1, double v2 ) f RESULT = AST_AXDISTANCE( THIS, AXIS, V1, V2, STATUS ) * Class Membership: * Frame method. * Description: c This function returns a signed value representing the axis increment f This routine returns a signed value representing the axis increment * from axis value v1 to axis value v2. * * For a simple Frame, this is a trivial operation returning the * difference between the two axis values. But for other derived classes * of Frame (such as a SkyFrame) this is not the case. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c axis f AXIS = INTEGER (Given) * The index of the axis to which the supplied values refer. The * first axis has index 1. c v1 f V1 = DOUBLE PRECISION (Given) * The first axis value. c v2 f V2 = DOUBLE PRECISION (Given) * The second axis value. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astAxDistance f AST_AXDISTANCE = DOUBLE PRECISION * The distance from the first to the second axis value. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input values has this value. * - A "bad" value will also be returned if this function is c invoked with the AST error status set, or if it should fail for f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- * Implementation Deficiencies; * - The protected interface for this function uses 1-based axis * numbering (like the public interface), rather than the more usual * zero-based system used by all other protected interfaces. There is * no real reason for this, and it should be changed at some time. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ double result; /* The returned answer */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis - 1, 1, "astAxDistance" ); ax = astGetAxis( this, axis - 1 ); /* Use the AxisDistance method associated with the Axis. */ if( astOK ) result = astAxisDistance( ax, v1, v2 ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* Return the result. */ return result; } static int AxIn( AstFrame *this, int axis, double lo, double hi, double val, int closed, int *status ){ /* *+ * Name: * astAxIn * Purpose: * Test if an axis value lies within a given interval. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astAxIn( AstFrame *this, int axis, double lo, double hi, double val, * int closed ) * Class Membership: * Frame member function. * Description: * This function returns non-zero if a given axis values lies within a * given axis interval. * Parameters: * this * Pointer to the Frame. * axis * The index of the axis. The first axis has index 0. * lo * The lower axis limit of the interval. * hi * The upper axis limit of the interval. * val * The axis value to be tested. * closed * If non-zero, then the lo and hi axis values are themselves * considered to be within the interval. Otherwise they are outside. * Returned Value: * Non-zero if the test value is inside the interval. * Applicability: * Frame * Uses simple Euclidean test * SkyFrame * All angles which are numerically between "lo" and "hi" are within * the interval. Angle outside this range are also within the interval * if they can be brought into the range by addition or subtraction * of a multiple of 2.PI. *- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ int result; /* Returned value */ /* For speed, omit the astOK check and axis validation (since this is protected code, AST should get it right). Obtain a pointer to the required Axis. */ ax = astGetAxis( this, axis ); /* Use the AxisIn method associated with the Axis. */ result = ax ? astAxisIn( ax, lo, hi, val, closed ) : 0; /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* Return the result. */ return result; } static double AxOffset( AstFrame *this, int axis, double v1, double dist, int *status ) { /* *++ * Name: c astAxOffset f AST_AXOFFSET * Purpose: * Add an increment onto a supplied axis value. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astAxOffset( AstFrame *this, int axis, double v1, double dist ) f RESULT = AST_AXOFFSET( THIS, AXIS, V1, DIST, STATUS ) * Class Membership: * Frame method. * Description: c This function returns an axis value formed by adding a signed axis f This routine returns an axis value formed by adding a signed axis * increment onto a supplied axis value. * * For a simple Frame, this is a trivial operation returning the * sum of the two supplied values. But for other derived classes * of Frame (such as a SkyFrame) this is not the case. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c axis f AXIS = INTEGER (Given) * The index of the axis to which the supplied values refer. The * first axis has index 1. c v1 f V1 = DOUBLE PRECISION (Given) * The original axis value. c dist f DIST = DOUBLE PRECISION (Given) * The axis increment to add to the original axis value. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astAxOffset f AST_AXOFFSET = DOUBLE PRECISION * The incremented axis value. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input values has this value. * - A "bad" value will also be returned if this function is c invoked with the AST error status set, or if it should fail for f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ double result; /* The returned answer */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis - 1, 1, "astAxOffset" ); ax = astGetAxis( this, axis - 1 ); /* Use the AxisOffset method associated with the Axis. */ if( astOK ) result = astAxisOffset( ax, v1, dist ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* Return the result. */ return result; } static void CheckPerm( AstFrame *this, const int *perm, const char *method, int *status ) { /* *+ * Name: * astCheckPerm * Purpose: * Check that an array contains a valid permutation. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astCheckPerm( AstFrame *this, const int *perm, const char *method ) * Class Membership: * Frame method. * Description: * This function checks the validity of a permutation array that * will be used to permute the order of a Frame's axes. If the * permutation specified by the array is not valid, an error is * reported and the global error status is set. Otherwise, the * function returns without further action. * Parameters: * this * Pointer to the Frame. * perm * Pointer to an array of integers with the same number of * elements as there are axes in the Frame. For each axis, the * corresponding integer gives the (zero based) axis index to be * used to identify the information for that axis (using the * un-permuted axis numbering). To be valid, the integers in * this array should therefore all lie in the range zero to * (naxes-1) inclusive, where "naxes" is the number of Frame * axes, and each value should occur exactly once. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate a permutation array. This method name is used * solely for constructing error messages. * Notes: * - Error messages issued by this function refer to the external * (public) numbering system used for axes (which is one-based), * whereas zero-based axis indices are used internally. *- */ /* Local Variables: */ int *there; /* Pointer to temporary array */ int axis; /* Loop counter for axes */ int naxes; /* Number of Frame axes */ int valid; /* Permutation array is valid? */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise. */ valid = 1; /* Obtain the number of Frame axes and allocate a temporary array of integers with the same number of elements. */ naxes = astGetNaxes( this ); there = astMalloc( sizeof( int ) * (size_t) naxes ); if ( astOK ) { /* Initialise the temporary array to zero. */ for ( axis = 0; axis < naxes; axis++ ) there[ axis ] = 0; /* Scan the permutation array, checking that each permuted axis index it contains is within the correct range. Note an error and quit checking if an invalid value is found. */ for ( axis = 0; axis < naxes; axis++ ) { if ( ( perm[ axis ] < 0 ) || ( perm[ axis ] >= naxes ) ) { valid = 0; break; /* Use the temporary array to count how many times each valid axis index occurs. */ } else { there[ perm[ axis ] ]++; } } /* If all the axis indices were within range, check to ensure that each value occurred only once. */ if ( valid ) { for ( axis = 0; axis < naxes; axis++ ) { /* Note an error and quit checking if any value did not occur exactly once. */ if ( there[ axis ] != 1 ) { valid = 0; break; } } } } /* Free the temporary array. */ there = astFree( there ); /* If an invalid permutation was detected and no other error has occurred, then report an error (note we convert to one-based axis numbering in the error message). */ if ( !valid && astOK ) { astError( AST__PRMIN, "%s(%s): Invalid axis permutation array.", status, method, astGetClass( this ) ); astError( AST__PRMIN, "Each axis index should lie in the range 1 to %d " "and should occur only once.", status, naxes ); } } static void CleanAttribs( AstObject *this_object, int *status ) { /* * Name: * CleanAttribs * Purpose: * Clear any invalid set attribute values. * Type: * Private function. * Synopsis: * #include "frame.h" * void CleanAttribs( AstObject *this_object, int *status ) * Class Membership: * Frame member function (over-rides the protected astCleanAttribs * method inherited from the Object class). * Description: * This function clears any attributes that are currently set to * invalid values in thr supplied object. * Parameters: * this * Pointer to the Object to be cleaned. */ /* Local Variables; */ AstAxis *ax; AstFrame *this; int i; int nax; int reporting; /* Check inherited status */ if( !astOK ) return; /* Get a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Defer error reporting, as required by the astCLEAN_ATTRIB macro. */ reporting = astReporting( 0 ); /* Clean attributes in any Objects contained within "this". */ nax = astGetNaxes( this ); for( i = 0; i < nax; i++ ) { ax = astGetAxis( this, i ); astCleanAttribs( ax ); ax = astAnnul( ax ); } /* Clean attributes of this class. */ astCLEAN_ATTRIB(System) astCLEAN_ATTRIB(AlignSystem) /* Re-establish error reporting. */ astReporting( reporting ); /* Invoke the method inherited form the parent to clean attributes defined by the parent class. */ (*parent_cleanattribs)( this_object, status ); } static char *CleanDomain( char *domain, int *status ) { /* * Name: * CleanDomain * Purpose: * Clean a Domain string and convert to upper case. * Type: * Private function. * Synopsis: * #include "frame.h" * char *CleanDomain( char *domain, int *status ) * Class Membership: * Frame member function. * Description: * This function removes all white space from a string and converts * other characters to upper case. It is intended for cleaning up * values supplied for the Domain attribute of a Frame. * Parameters: * domain * Pointer to the null terminated Domain string to be modified. * status * Pointer to the inherited status variable. * Returned Value: * The pointer value "domain" is always returned (even under error * conditions). */ /* Local Variables: */ int i; /* Loop counter for characters */ int j; /* Good character count */ /* Check the global error status. */ if ( !astOK ) return domain; /* Eliminate white space characters and convert the rest to upper case. */ for ( i = j = 0; domain[ i ]; i++ ) { if ( !isspace( domain[ i ] ) ) domain[ j++ ] = toupper( domain[ i ] ); } domain[ j ] = '\0'; /* Return the string pointer. */ return domain; } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Frame member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * Frame, so that the default value will subsequently be used. * Parameters: * this * Pointer to the Frame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis */ AstFrame *pfrm; /* Pointer to primary Frame containing axis */ AstFrame *this; /* Pointer to the Frame structure */ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */ char *axis_attrib; /* Pointer to axis attribute name */ const char *old_attrib; /* Pointer to supplied attribute name string */ int axis; /* Frame axis number */ int axis_nc; /* No. characters in axis attribute name */ int free_axis_attrib; /* Should axis_attrib be freed? */ int has_axis; /* Does attrib name include axis specifier? */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ int oldrep; /* Original error reporting state */ int paxis; /* Axis index within primary frame */ int used; /* Could the setting string be used? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Set a flag indicating if the attribute name includes an axis specifier. */ has_axis = ( strchr( attrib, '(' ) != NULL ); /* A flag indicating that we do not need to free the axis_attrib memory. */ free_axis_attrib = 0; /* Initialise things to avoid compiler warnings. */ axis_attrib = NULL; old_attrib = NULL; /* Jump back to here if we are trying the same attribute but with an explicit axis "(1)" added to the end of the name. */ L1: /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* Digits. */ /* ------- */ if ( !strcmp( attrib, "digits" ) ) { astClearDigits( this ); /* Digits(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { /* There is no function to clear the Digits attribute for an axis directly, so obtain a pointer to the Axis and use this to clear the attribute. */ (void) astValidateAxis( this, axis - 1, 1, "astClearDigits(axis)" ); ax = astGetAxis( this, axis - 1 ); astClearAxisDigits( ax ); ax = astAnnul( ax ); /* Direction(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearDirection( this, axis - 1 ); /* Epoch. */ /* ------ */ } else if ( !strcmp( attrib, "epoch" ) ) { astClearEpoch( this ); /* Top(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearTop( this, axis - 1 ); /* Bottom(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearBottom( this, axis - 1 ); /* Domain. */ /* ------- */ } else if ( !strcmp( attrib, "domain" ) ) { astClearDomain( this ); /* Format(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearFormat( this, axis - 1 ); /* Label(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearLabel( this, axis - 1 ); /* MatchEnd. */ /* --------- */ } else if ( !strcmp( attrib, "matchend" ) ) { astClearMatchEnd( this ); /* MaxAxes. */ /* -------- */ } else if ( !strcmp( attrib, "maxaxes" ) ) { astClearMaxAxes( this ); /* MinAxes. */ /* -------- */ } else if ( !strcmp( attrib, "minaxes" ) ) { astClearMinAxes( this ); /* Permute. */ /* -------- */ } else if ( !strcmp( attrib, "permute" ) ) { astClearPermute( this ); /* PreserveAxes. */ /* ------------- */ } else if ( !strcmp( attrib, "preserveaxes" ) ) { astClearPreserveAxes( this ); /* Symbol(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearSymbol( this, axis - 1 ); /* System. */ /* ------- */ } else if ( !strcmp( attrib, "system" ) ) { astClearSystem( this ); /* AlignSystem. */ /* ------------ */ } else if ( !strcmp( attrib, "alignsystem" ) ) { astClearAlignSystem( this ); /* Title. */ /* ------ */ } else if ( !strcmp( attrib, "title" ) ) { astClearTitle( this ); /* Unit(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearUnit( this, axis - 1 ); /* ObsLat. */ /* ------- */ } else if ( !strcmp( attrib, "obslat" ) ) { astClearObsLat( this ); /* ObsLon. */ /* ------- */ } else if ( !strcmp( attrib, "obslon" ) ) { astClearObsLon( this ); /* ObsAlt. */ /* ------- */ } else if ( !strcmp( attrib, "obsalt" ) ) { astClearObsAlt( this ); /* Dut1 */ /* --- */ } else if ( !strcmp( attrib, "dut1" ) ) { astClearDut1( this ); /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then report an error. */ } else if ( !strcmp( attrib, "naxes" ) || !strncmp( attrib, "normunit", 8 ) ) { astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Other axis attributes. */ /* ---------------------- */ /* If the attribute was not identified above, but appears to refer to a Frame axis, then it may refer to an Axis object of a derived type (which has additional attributes not recognised here). */ } else if( !free_axis_attrib && ( nc = 0, ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n", &axis_nc, &axis, &nc ) ) && ( nc >= len ) ) ) { /* Validate the axis index and extract the attribute name. */ (void) astValidateAxis( this, axis - 1, 1, "astClear" ); axis_attrib = astString( attrib, axis_nc ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis - 1 ); if( astOK ) { /* Assume that we will be able to use the attribute name. */ used = 1; /* Temporarily switch off error reporting so that if the following attempt to access the axis attribute fails, we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. Any errors reported in this context will simply be ignored, in particularly they are not deferred for later delivery. */ oldrep = astReporting( 0 ); /* Use the Axis astClearAttrib method to clear the attribute value. */ astClearAttrib( ax, axis_attrib ); /* If the above call failed with a status of AST__BADAT, indicating that the attribute name was not recognised, clear the status so that we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. */ if( astStatus == AST__BADAT ) { astClearStatus; /* Find the primary Frame containing the specified axis. */ astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); /* Only attempt to use the primary Frame if it is not the same as "this" - otherwise we could end up in an infinite loop. */ if( pfrm != this ) { /* astPrimaryFrame returns the original - unpermuted - axis index within the primary Frame. So we need to take into account any axis permutation which has been applied to the primary Frame when forming the attribute name to use below. Find the permuted (external) axis index which corresponds to the internal (unpermuted) axis index "paxis". */ paxis = astValidateAxis( pfrm, paxis, 0, "astClear" ); /* Modify the attribute name to refer to the axis numbering of the primary frame. */ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 ); /* Attempt to clear the attribute as an attribute of the primary Frame. */ astClearAttrib( pfrm, pfrm_attrib ); /* If this failed, clear the status and indicate that we have not managed to use the attribute name. */ if( !astOK ) { astClearStatus; used = 0; } } else { used = 0; } /* If not found attempt to clear the attribute value in the Axis, omitting the axis index. */ if( ! used ) { astClearAttrib( pfrm, axis_attrib ); if( !astOK ) { astClearStatus; } else { used = 1; } } /* Annul the primary Frame pointer. */ pfrm = astAnnul( pfrm ); } /* Re-instate the original error reporting state. */ astReporting( oldrep ); /* If we could not use the attribute name, attempt to clear the axis attribute again, this time retaining the error report. This is done to ensure the user gets an appropriate error message. */ if( !used ) astClearAttrib( ax, axis_attrib ); } /* Annul the Axis pointer and free the memory holding the attribute name. */ ax = astAnnul( ax ); axis_attrib = astFree( axis_attrib ); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, and the Frame has only 1 axis, and the attribute name does not already include an axis specifier, try again after appending "(1)" to the end of the attribute name. */ } else if( !has_axis && astGetNaxes( this ) == 1 ) { /* Take a copy of the supplied name, allowing 3 extra characters for the axis specifier "(1)". */ axis_attrib = astMalloc( len + 4 ); if( axis_attrib ) memcpy( axis_attrib, attrib, len ); /* Indicate we should free the axis_attrib memory. */ free_axis_attrib = 1; /* Add in the axis specifier. */ strcpy( axis_attrib + len, "(1)" ); /* Use the new attribute name instead of the supplied name. */ old_attrib = attrib; attrib = axis_attrib; /* Indicate the attribute name now has an axis specifier. */ has_axis = 1; /* Jump back to try interpreting the new attribute name. */ goto L1; /* Not recognised. */ /* --------------- */ /* If the attribute name is still not recognised, pass it on to the parent method for further interpretation. First re-instate the original attrib name string if it was changed above. */ } else { if( free_axis_attrib ) { attrib = old_attrib; axis_attrib = astFree( axis_attrib ); } (*parent_clearattrib)( this_object, attrib, status ); } } static void ClearUnit( AstFrame *this, int axis, int *status ) { /* * Name: * ClearUnit * Purpose: * Clear the Unit attribute of a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void ClearUnit( AstFrame *this, int axis, int *status ) * Class Membership: * Frame method. * Description: * This function clears the Unit value for an axis of a Frame. * Parameters: * this * Pointer to the Frame. * axis * The number of the axis (zero-based) for which the Unit value is to * be cleared. * unit * The new value to be set. * status * Pointer to the inherited status variable. * Returned Value: * void. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ const char *units; /* Pointer to units string */ char *old_units; /* Pointer to copy of original units */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the axis index. */ (void) astValidateAxis( this, axis, 1, "astSetUnit" ); /* Do nothing more if the attribute is already cleared. */ if( astTestUnit( this, axis ) ) { /* Obtain a pointer to the required Axis. */ ax = astGetAxis( this, axis ); /* Save a copy of the old units. */ units = astGetAxisUnit( ax ); old_units = astStore( NULL, units, strlen( units ) + 1 ); /* Clear the Axis Unit attribute value, and then get a pointer to the new default Units string. */ astClearAxisUnit( ax ); units = astGetUnit( this, axis ); /* The new unit may require the Label and/or Symbol to be changed, but only if the Frames ActiveUnit flag is set. */ if( astGetActiveUnit( this ) ) NewUnit( ax, old_units, units, "astSetUnit", astGetClass( this ), status ); /* Free resources. */ old_units = astFree( old_units ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); } } static int ConsistentMaxAxes( AstFrame *this, int value, int *status ) { /* * Name: * ConsistentMaxAxes * Purpose: * Ensure a consistent value when setting the MaxAxes attribute. * Type: * Private function. * Synopsis: * #include "frame.h" * int ConsistentMaxAxes( AstFrame *this, int value, int *status ) * Class Membership: * Frame member function. * Description: * This function accepts a value which is to be set for a Frame's MaxAxes * attribute and returns an appropriately adjusted value to be assigned * to the Frame structure's max_axes component. If necessary, the Frame's * MinAxes attribute is adjusted to remain consistent with the new MaxAxes * value (but note that the MaxAxes value itself is not assigned by this * function). * Parameters: * this * Pointer to the Frame. * value * The new value being set for the MaxAxes attribute. * status * Pointer to the inherited status variable. * Returned Value: * The value to be assigned to the max_axes component. * Notes: * - A value of -INT_MAX will be returned if this function is * invoked with the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return -INT_MAX; /* Ensure that the result value isn't negative. */ result = ( value >= 0 ) ? value : 0; /* Check if the MinAxes attribute is set. If not, its default value will be consistent with the MaxAxes value (the DefaultMinAxes function ensures this). Otherwise, obtain its value to check for consistency. */ if ( astTestMinAxes( this ) ) { /* If necessary, set a new MinAxes value to prevent it exceeding the MaxAxes value about to be returned. */ if ( astGetMinAxes( this ) > result ) astSetMinAxes( this, result ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = -INT_MAX; /* Return the result. */ return result; } static int ConsistentMinAxes( AstFrame *this, int value, int *status ) { /* * Name: * ConsistentMinAxes * Purpose: * Ensure a consistent value when setting the MinAxes attribute. * Type: * Private function. * Synopsis: * #include "frame.h" * int ConsistentMinAxes( AstFrame *this, int value, int *status ) * Class Membership: * Frame member function. * Description: * This function accepts a value which is to be set for a Frame's MinAxes * attribute and returns an appropriately adjusted value to be assigned * to the Frame structure's min_axes component. If necessary, the Frame's * MaxAxes attribute is adjusted to remain consistent with the new MinAxes * value (but note that the MinAxes value itself is not assigned by this * function). * Parameters: * this * Pointer to the Frame. * value * The new value being set for the MinAxes attribute. * status * Pointer to the inherited status variable. * Returned Value: * The value to be assigned to the min_axes component. * Notes: * - A value of -INT_MAX will be returned if this function is * invoked with the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ int result; /* Result to be returned */ /* Check the global error status. */ if ( !astOK ) return -INT_MAX; /* Ensure that the result value isn't negative. */ result = ( value >= 0 ) ? value : 0; /* Check if the MaxAxes attribute is set. If not, its default value will be consistent with the MinAxes value (the DefaultMaxAxes function ensures this). Otherwise, obtain its value to check for consistency. */ if ( astTestMaxAxes( this ) ) { /* If necessary, set a new MaxAxes value to prevent it being less than the MinAxes value about to be returned. */ if ( astGetMaxAxes( this ) < result ) astSetMaxAxes( this, result ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = -INT_MAX; /* Return the result. */ return result; } static AstFrameSet *Convert( AstFrame *from, AstFrame *to, const char *domainlist, int *status ) { /* *++ * Name: c astConvert f AST_CONVERT * Purpose: * Determine how to convert between two coordinate systems. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c AstFrameSet *astConvert( AstFrame *from, AstFrame *to, c const char *domainlist ) f RESULT = AST_CONVERT( FROM, TO, DOMAINLIST, STATUS ) * Class Membership: * Frame method. * Description: * This function compares two Frames and determines whether it is * possible to convert between the coordinate systems which they * represent. If conversion is possible, it returns a FrameSet * which describes the conversion and which may be used (as a * Mapping) to transform coordinate values in either direction. * * The same function may also be used to determine how to convert * between two FrameSets (or between a Frame and a FrameSet, or * vice versa). This mode is intended for use when (for example) * two images have been calibrated by attaching a FrameSet to each. c astConvert might then be used to search for a f AST_CONVERT might then be used to search for a * celestial coordinate system that both images have in common, and * the result could then be used to convert between the pixel * coordinates of both images -- having effectively used their * celestial coordinate systems to align them. * * When using FrameSets, there may be more than one possible * intermediate coordinate system in which to perform the * conversion (for instance, two FrameSets might both have * celestial coordinates, detector coordinates, pixel coordinates, * etc.). A comma-separated list of coordinate system domains may * therefore be given which defines a priority order to use when * selecting the intermediate coordinate system. The path used for * conversion must go via an intermediate coordinate system whose * Domain attribute matches one of the domains given. If conversion * cannot be achieved using the first domain, the next one is * considered, and so on, until success is achieved. * Parameters: c from f FROM = INTEGER (Given) * Pointer to a Frame which represents the "source" coordinate * system. This is the coordinate system in which you already * have coordinates available. * * If a FrameSet is given, its current Frame (as determined by * its Current attribute) is taken to describe the source * coordinate system. Note that the Base attribute of this * FrameSet may be modified by this function to indicate which * intermediate coordinate system was used (see under * "FrameSets" in the "Applicability" section for details). c to f TO = INTEGER (Given) * Pointer to a Frame which represents the "destination" * coordinate system. This is the coordinate system into which * you wish to convert your coordinates. * * If a FrameSet is given, its current Frame (as determined by * its Current attribute) is taken to describe the destination * coordinate system. Note that the Base attribute of this * FrameSet may be modified by this function to indicate which * intermediate coordinate system was used (see under * "FrameSets" in the "Applicability" section for details). c domainlist f DOMAINLIST = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string containing a f A character string containing a * comma-separated list of Frame domains. This may be used to * define a priority order for the different intermediate * coordinate systems that might be used to perform the * conversion. * * The function will first try to obtain a conversion by making * use only of an intermediate coordinate system whose Domain * attribute matches the first domain in this list. If this * fails, the second domain in the list will be used, and so on, * until conversion is achieved. A blank domain (e.g. two * consecutive commas) indicates that all coordinate systems * should be considered, regardless of their domains. * * This list is case-insensitive and all white space is ignored. * If you do not wish to restrict the domain in this way, c you should supply an empty string. This is normally f you should supply a blank string. This is normally * appropriate if either of the source or destination coordinate * systems are described by Frames (rather than FrameSets), * since there is then usually only one possible choice of * intermediate coordinate system. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astConvert() f AST_CONVERT = INTEGER * If the requested coordinate conversion is possible, the * function returns a pointer to a FrameSet which describes the * conversion. Otherwise, a null Object pointer (AST__NULL) is * returned without error. * * If a FrameSet is returned, it will contain two Frames. Frame * number 1 (its base Frame) will describe the source coordinate c system, corresponding to the "from" parameter. Frame number 2 f system, corresponding to the FROM argument. Frame number 2 * (its current Frame) will describe the destination coordinate c system, corresponding to the "to" parameter. The Mapping f system, corresponding to the TO argument. The Mapping * which inter-relates these two Frames will perform the * required conversion between their respective coordinate * systems. * * Note that a FrameSet may be used both as a Mapping and as a * Frame. If the result is used as a Mapping (e.g. with c astTran2), then it provides a means of converting coordinates f AST_TRAN2), then it provides a means of converting coordinates * from the source to the destination coordinate system (or * vice versa if its inverse transformation is selected). If it * is used as a Frame, its attributes will describe the * destination coordinate system. * Applicability: * DSBSpecFrame * If the AlignSideBand attribute is non-zero, alignment occurs in the * upper sideband expressed within the spectral system and standard of * rest given by attributes AlignSystem and AlignStdOfRest. If * AlignSideBand is zero, the two DSBSpecFrames are aligned as if * they were simple SpecFrames (i.e. the SideBand is ignored). * Frame * This function applies to all Frames. Alignment occurs within the * coordinate system given by attribute AlignSystem. * FrameSet c If either of the "from" or "to" parameters is a pointer to a f If either of the FROM or TO arguments is a pointer to a c FrameSet, then astConvert will attempt to convert from the f FrameSet, then AST_CONVERT will attempt to convert from the c coordinate system described by the current Frame of the "from" f coordinate system described by the current Frame of the FROM c FrameSet to that described by the current Frame of the "to" f FrameSet to that described by the current Frame of the TO * FrameSet. * * To achieve this, it will consider all of the Frames within * each FrameSet as a possible way of reaching an intermediate * coordinate system that can be used for the conversion. There * is then the possibility that more than one conversion path * may exist and, unless the choice is sufficiently restricted c by the "domainlist" string, the sequence in which the Frames f by the DOMAINLIST string, the sequence in which the Frames * are considered can be important. In this case, the search * for a conversion path proceeds as follows: c - Each field in the "domainlist" string is considered in turn. f - Each field in the DOMAINLIST string is considered in turn. * - The Frames within each FrameSet are considered in a * specific order: (1) the base Frame is always considered * first, (2) after this come all the other Frames in * Frame-index order (but omitting the base and current Frames), * (3) the current Frame is always considered last. However, if * either FrameSet's Invert attribute is set to a non-zero value * (so that the FrameSet is inverted), then its Frames are * considered in reverse order. (Note that this still means that * the base Frame is considered first and the current Frame * last, because the Invert value will also cause these Frames * to swap places.) * - All source Frames are first considered (in the appropriate * order) for conversion to the first destination Frame. If no * suitable intermediate coordinate system emerges, they are * then considered again for conversion to the second * destination Frame (in the appropriate order), and so on. * - Generally, the first suitable intermediate coordinate * system found is used. However, the overall Mapping between * the source and destination coordinate systems is also * examined. Preference is given to cases where both the * forward and inverse transformations are defined (as indicated * by the TranForward and TranInverse attributes). If only one * transformation is defined, the forward one is preferred. * - If the domain of the intermediate coordinate system matches c the current "domainlist" field, the conversion path is f the current DOMAINLIST field, the conversion path is c accepted. Otherwise, the next "domainlist" field is considered f accepted. Otherwise, the next DOMAINLIST field is considered * and the process repeated. * * If conversion is possible, the Base attributes of the two * FrameSets will be modified on exit to identify the Frames * used to access the intermediate coordinate system which was * finally accepted. * * Note that it is possible to force a particular Frame within a * FrameSet to be used as the basis for the intermediate * coordinate system, if it is suitable, by (a) focussing * attention on c it by specifying its domain in the "domainlist" string, or (b) f it by specifying its domain in the DOMAINLIST string, or (b) * making it the base Frame, since this is always considered * first. * SpecFrame * Alignment occurs within the spectral system and standard of rest * given by attributes AlignSystem and AlignStdOfRest. * TimeFrame * Alignment occurs within the time system and time scale given by * attributes AlignSystem and AlignTimeScale. * Examples: c cvt = astConvert( a, b, "" ); f CVT = AST_CONVERT( A, B, ' ', STATUS ) * Attempts to convert between the coordinate systems represented c by "a" and "b" (assumed to be Frames). If successful, a FrameSet f by A and B (assumed to be Frames). If successful, a FrameSet c is returned via the "cvt" pointer which may be used to apply the f is returned via the CVT pointer which may be used to apply the c conversion to sets of coordinates (e.g. using astTran2). f conversion to sets of coordinates (e.g. using AST_TRAN2). c cvt = astConvert( astSkyFrame(""), astSkyFrame("Equinox=2005"), "" ); f CVT = AST_CONVERT( AST_SKYFRAME( ' ', STATUS ), AST_SKYFRAME( 'Equinox=2005', STATUS ), ' ', STATUS ) * Creates a FrameSet which describes precession in the default * FK5 celestial coordinate system between equinoxes J2000 (also c the default) and J2005. The returned "cvt" pointer may then f the default) and J2005. The returned CVT pointer may then c be passed to astTran2 to apply this precession correction to f be passed to AST_TRAN2 to apply this precession correction to * any number of coordinate values given in radians. * * Note that the returned FrameSet also contains information * about how to format coordinate values. This means that * setting its Report attribute to 1 is a simple way to obtain * printed output (formatted in sexagesimal notation) to show * the coordinate values before and after conversion. c cvt = astConvert( a, b, "sky,detector," ); f CVT = AST_CONVERT( A, B, 'SKY,DETECTOR,', STATUS ) * Attempts to convert between the coordinate systems c represented by the current Frames of "a" and "b" f represented by the current Frames of A and B * (now assumed to be FrameSets), via the intermediate "SKY" * coordinate system. This, by default, is the Domain * associated with a celestial coordinate system represented by * a SkyFrame. * * If this fails (for example, because either FrameSet lacks * celestial coordinate information), then the user-defined * "DETECTOR" coordinate system is used instead. If this also * fails, then all other possible ways of achieving conversion * are considered before giving up. * c The returned pointer "cvt" indicates whether conversion was f The returned pointer CVT indicates whether conversion was * possible and will have the value AST__NULL if it was not. If c conversion was possible, "cvt" will point at a new FrameSet f conversion was possible, CVT will point at a new FrameSet * describing the conversion. * * The Base attributes of the two FrameSets c will be set by astConvert to indicate which of their Frames was f will be set by AST_CONVERT to indicate which of their Frames was * used for the intermediate coordinate system. This means that * you can subsequently determine which coordinate system was * used by enquiring the Domain attribute of either base Frame. * Notes: * - The Mapping represented by the returned FrameSet results in * alignment taking place in the coordinate system specified by the c AlignSystem attribute of the "to" Frame. See the description of the f AlignSystem attribute of the TO Frame. See the description of the * AlignSystem attribute for further details. * - When aligning (say) two images, which have been calibrated by * attaching FrameSets to them, it is usually necessary to convert * between the base Frames (representing "native" pixel * coordinates) of both FrameSets. This may be achieved by * inverting the FrameSets (e.g. using astInvert) so as to * interchange their base and current Frames before using * astConvert. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * This function is simply a wrap-up for the protected astConvertX * method which performs the required processing but swaps the order * of the first two arguments. This is a trick to allow the * astConvert method to be over-ridden by derived classes on the * basis of the class of either of the first two arguments. */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Invoke the "astConvertX" method with the first two arguments swapped. */ return astConvertX( to, from, domainlist ); } static AstFrameSet *ConvertX( AstFrame *to, AstFrame *from, const char *domainlist, int *status ) { /* *+ * Name: * astConvertX * Purpose: * Determine how to convert between two coordinate systems. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstFrameSet *astConvertX( AstFrame *to, AstFrame *from, * const char *domainlist ) * Class Membership: * Frame method. * Description: * This function performs the processing for the public astConvert * method and has exactly the same interface except that the order * of the first two arguments is swapped. This is a trick to allow * the astConvert method to be over-ridden by derived classes on * the basis of the class of either of its first two arguments. * * See the astConvert method for details of the interface. *- * Implementation Deficiencies: * - This function's job is basically to negotiate with two Frames * to try and find a mutually agreeable coordinate system for * conversion. Ideally, it should be able to juggle the number of * axes, etc. to do this. At present, however, the implementation * is much simpler. This is adequate for the Frame classes which * exist at the time of writing, but the implementation may need * beefing up in future. * - One likely problem is with attributes which default in both * the source and destination Frames. This means they also default * in the common coordinate system. If these default values were to * differ when matching different target Frames, however, we would * be in trouble, because the common coordinate system would not * then be remaining constant. The longer-term solution to this is * probably to provide some mechanism to "fix" all attribute values * for a Frame, by taking any attributes that are un-set and * explicitly setting a firm value (equal to the default) so they * cannot then change. */ /* Local Variables: */ AstFrameSet *result; /* Pointer to Mapping to be returned */ AstFrame *ftmp; /* Pointer to returned Frame */ AstMapping **map1_address; /* Location of first Mapping pointer */ AstMapping **map2_address; /* Location of second Mapping pointer */ AstMapping *common0; /* Initial common coordinate system */ AstMapping *common1; /* Improved common coordinate system */ AstMapping *common2; /* Final common coordinate system */ AstMapping *frame1; /* Pointer to Frame for first match */ AstMapping *frame2; /* Pointer to Frame for second match */ AstMapping *from_map; /* Pointer to "from" Mapping */ AstMapping *map; /* Pointer to conversion Mapping */ AstMapping *result_map; /* Pointer to result Mapping */ AstMapping *tmp; /* Temporary Mapping pointer */ AstMapping *to_map; /* Pointer to "to" Mapping */ char *domain; /* Pointer to result domain */ char *domain_end; /* Pointer to null at end of domain */ char *domainlist_copy; /* Pointer to copy of domainlist */ int *axes1; /* Pointer to axis assignments */ int *axes2; /* Pointer to axis assignments */ int best_score; /* Score assigned to best match */ int icom; /* Common coordinate system loop counter */ int match1; /* First match succeeded? */ int match2; /* Second match succeeded? */ int match; /* Overall match found? */ int perfect; /* Perfect match found? */ int score; /* Score assigned to match */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Further initialisation. */ result_map = NULL; /* Make a temporary copy of the domains list. */ domainlist_copy = astStore( NULL, domainlist, strlen( domainlist ) + (size_t) 1 ); if ( astOK ) { /* Loop to inspect each comma-separated field in the domains list until an error occurs, all the domains are used up, or a match is found. */ domain = domainlist_copy; match = 0; while ( astOK && domain && !match ) { /* Change the comma at the end of each field to a null to terminate the domain. Then convert the domain to upper case and eliminate white space. */ if ( ( domain_end = strchr( domain, ',' ) ) ) *domain_end = '\0'; CleanDomain( domain, status ); /* For any given domain, we will ignore imperfect matches in favour of better ones by assigning a score to each match. Initialise the best score value for the current domain. */ best_score = -1; /* Loop to consider both the "to" and "from" Frames in turn as the basis of a possible common coordinate system. Quit looping early if an error occurs or a perfect match is found. */ perfect = 0; for ( icom = 0; astOK && !perfect && ( icom <= 1 ); icom++ ) { /* Make a copy of the Frame representing the initial guess at a common coordinate system. We will use this to probe the other Frame. Ensure that axes are not preserved (so that we convert to the common axis number/order). */ common0 = astCopy( icom ? from : to ); astSetPreserveAxes( common0, 0 ); /* Also, if the current domain is not blank, set the Domain attribute (so we will only find coordinate systems which match the current "domainlist" field). */ if ( *domain ) astSetDomain( common0, domain ); /* Obtain a pointer to the other Frame. */ frame1 = astClone( icom ? to : from ); /* Set the address at which to store the resulting Mapping pointer. */ map1_address = icom ? &to_map : &from_map; /* See if conversion from "frame1" to the common coordinate system is possible. If successful, this results in a new approximation ("common1") to the possible common coordinate system. */ match1 = astMatch( common0, frame1, 1, &axes1, &axes2, map1_address, &ftmp ); common1 = (AstMapping *) ftmp; /* If successful, free memory allocated for the axis association arrays, which are not needed. */ if ( astOK && match1 ) { axes1 = astFree( axes1 ); axes2 = astFree( axes2 ); /* Using the improved approximation to the common coordinate system, now test if conversion from the alternative Frame "frame2" is possible. */ frame2 = astClone( icom ? from : to ); map2_address = icom ? &from_map : &to_map; astSetPreserveAxes( common1, 0 ); match2 = astMatch( common1, frame2, 1, &axes1, &axes2, map2_address, &ftmp ); common2 = (AstMapping *) ftmp; /* If successful, free memory allocated for the axis association arrays, which are not needed. */ if ( astOK && match2 ) { axes1 = astFree( axes1 ); axes2 = astFree( axes2 ); /* Invert the "to" Mapping and concatenate the two Mappings to describe the conversion between the "from" and "to" Frames. Then simplify the result. */ astInvert( to_map ); tmp = (AstMapping *) astCmpMap( from_map, to_map, 1, "", status ); map = astSimplify( tmp ); tmp = astAnnul( tmp ); /* Assign a score that favours Mappings with both transformations available over those with only one, and Mappings with only a forward transformation over those with only an inverse transformation. */ score = ( astGetTranForward( map ) ? 2 : 0 ) + ( astGetTranInverse( map ) ? 1 : 0 ); /* If the new score is better than the previous one (or is the first one), note that we have a possible match. */ if ( astOK && ( score > best_score ) ) { match = 1; /* Update the best score and note if it indicates a perfect match (in which case we can stop searching at this point). */ best_score = score; perfect = ( best_score >= 3 ); /* Annul any previous result Mapping pointer and replace it with this better one. */ if ( result_map ) result_map = astAnnul( result_map ); result_map = astClone( map ); } /* Annul pointers to all the intermediate Objects. */ map = astAnnul( map ); common2 = astAnnul( common2 ); *map2_address = astAnnul( *map2_address ); } frame2 = astAnnul( frame2 ); common1 = astAnnul( common1 ); *map1_address = astAnnul( *map1_address ); } frame1 = astAnnul( frame1 ); common0 = astAnnul( common0 ); } /* Go on to consider the next field in the domains list. */ domain = domain_end ? domain_end + 1 : NULL; } } /* Free the domain list copy. */ domainlist_copy = astFree( domainlist_copy ); /* If returning a result, build the result FrameSet. Then annul the result Mapping pointer. */ if ( result_map ) { result = astFrameSet( from, "", status ); astAddFrame( result, AST__BASE, result_map, to ); result_map = astAnnul( result_map ); } /* If an error occurred, annul the result FrameSet pointer. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static int DefaultMaxAxes( AstFrame *this, int *status ) { /* * Name: * DefaultMaxAxes * Purpose: * Obtain the MaxAxes attribute from a Frame structure, with defaulting. * Type: * Private function. * Synopsis: * #include "frame.h" * int DefaultMaxAxes( AstFrame *this, int *status ) * Class Membership: * Frame member function. * Description: * This function inspects the max_axes component of a Frame structure and * derives a value for the MaxAxes attribute. If the component's value * indicates that the attribute has not been set, a suitable default is * returned which is consistent with the state of the Frames's MinAxes * attribute. * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * The value to be used for the MaxAxes attribute. */ /* Local Variables. */ int result; /* Result to be returned */ int min_axes; /* Value of MinAxes attribute */ /* Check the global error status. */ if ( !astOK ) return 0; /* If the Frame's max_axes component is set, return its value. */ if ( this->max_axes != -INT_MAX ) { result = this->max_axes; /* Otherwise, the preferred default value is the number of Frame axes. */ } else { result = astGetNaxes( this ); /* Before returning this value, check if the MinAxes attribute is set. If it is, obtain its value. */ if ( astTestMinAxes( this ) ) { min_axes = astGetMinAxes( this ); /* If necessary, increase the MaxAxes default value so that it is not less than MinAxes. */ if ( result < min_axes ) result = min_axes; } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static int DefaultMinAxes( AstFrame *this, int *status ) { /* * Name: * DefaultMinAxes * Purpose: * Obtain the MinAxes attribute from a Frame structure, with defaulting. * Type: * Private function. * Synopsis: * #include "frame.h" * int DefaultMinAxes( AstFrame *this, int *status ) * Class Membership: * Frame member function. * Description: * This function inspects the min_axes component of a Frame structure and * derives a value for the MinAxes attribute. If the component's value * indicates that the attribute has not been set, a suitable default is * returned which is consistent with the state of the Frames's MaxAxes * attribute. * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * The value to be used for the MinAxes attribute. */ /* Local Variables: */ int result; /* Result to be returned */ int max_axes; /* Value of MaxAxes attribute */ /* Check the global error status. */ if ( !astOK ) return 0; /* If the Frame's min_axes component is set, return its value. */ if ( this->min_axes != -INT_MAX ) { result = this->min_axes; /* Otherwise, the preferred default value is the number of Frame axes. */ } else { result = astGetNaxes( this ); /* Before returning this value, check if the MaxAxes attribute is set. If it is, obtain its value. */ if ( astTestMaxAxes( this ) ) { max_axes = astGetMaxAxes( this ); /* If necessary, reduce the MinAxes default value so that it does not exceed MaxAxes. */ if ( result > max_axes ) result = max_axes; } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static double Distance( AstFrame *this, const double point1[], const double point2[], int *status ) { /* *++ * Name: c astDistance f AST_DISTANCE * Purpose: * Calculate the distance between two points in a Frame. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astDistance( AstFrame *this, c const double point1[], const double point2[] ) f RESULT = AST_DISTANCE( THIS, POINT1, POINT2, STATUS ) * Class Membership: * Frame method. * Description: * This function finds the distance between two points whose Frame * coordinates are given. The distance calculated is that along * the geodesic curve that joins the two points. * * For example, in a basic Frame, the distance calculated will be * the Cartesian distance along the straight line joining the two * points. For a more specialised Frame describing a sky coordinate * system, however, it would be the distance along the great circle * passing through two sky positions. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c point1 f POINT1( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute) containing the coordinates of the first point. c point2 f POINT2( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * containing the coordinates of the second point. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astDistance f AST_DISTANCE = DOUBLE PRECISION * The distance between the two points. * Notes: * - This function will return a "bad" result value (AST__BAD) if * any of the input coordinates has this value. * - A "bad" value will also be returned if this function is c invoked with the AST error status set, or if it should fail for f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- */ /* Local Variables: */ double delta; /* Separation along an axis */ double result; /* Result value to return */ int axis; /* Loop counter for axes */ int naxes; /* Number of Frame axes */ /* Initialise. */ result = AST__BAD; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); if ( astOK ) { /* Loop to determine the Cartesian distance between the points. */ result = 0.0; for ( axis = 0; axis < naxes; axis++ ) { /* If any of the coordinates supplied is bad, set the distance to be bad and quit looping. */ if ( ( point1[ axis ] == AST__BAD ) || ( point2[ axis ] == AST__BAD ) ) { result = AST__BAD; break; /* Otherwise, accumulate the sum of squared separations along each axis. */ } else { delta = point1[ axis ] - point2[ axis ]; result += ( delta * delta ); } } /* Take the square root to find the distance (if valid). */ if ( result != AST__BAD ) result = sqrt( result ); } /* Return the result. */ return result; } static int DoNotSimplify( AstMapping *this, int *status ) { /* * Name: * DoNotSimplify * Purpose: * Check if a Mapping is appropriate for simplification. * Type: * Private function. * Synopsis: * #include "object.h" * int DoNotSImplify( AstMapping *this ); * Class Membership: * CmpMap member function (over-rides the astDoNotSimplify protected * method inherited from the parent class). * Description: * This function returns a flag indivating if the supplied Mapping is * appropriate for simplification. * Parameters: * this * Pointer to the Mapping. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the supplied Mapping is not appropriate for * simplification, and zero otherwise. * Notes: * - A value of 0 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Unlike basic Mappings, Frames that have a set value for the Ident can be simplified. So always return zero. */ return 0; } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two Frames are equivalent. * Type: * Private function. * Synopsis: * #include "frame.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * Frame member function (over-rides the astEqual protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two Frames are equivalent. * Parameters: * this * Pointer to the first Frame. * that * Pointer to the second Frame. * status * Pointer to the inherited status variable. * Returned Value: * One if the Frames are equivalent, zero otherwise. * Notes: * - The two Frames are considered equivalent if the Mapping between * them is a UnitMap. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstFrame *that; /* Pointer to the second Frame structure */ AstFrame *this; /* Pointer to the first Frame structure */ AstFrameSet *fs; /* FrameSet connecting the two Frames */ AstMapping *map1; /* Mapping connecting the two Frames */ AstMapping *map2; /* Simplified mapping connecting two Frames */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Checks that the second object is of the same class as the first . */ if( !strcmp( astGetClass( this_object ), astGetClass( that_object ) ) ){ /* Obtain pointers to the two Frame structures. */ this = (AstFrame *) this_object; that = (AstFrame *) that_object; /* Get the Mapping between them, and see if it is a UnitMap. */ fs = astConvert( that, this, "" ); if( fs ) { map1 = astGetMapping( fs, AST__BASE, AST__CURRENT ); map2 = astSimplify( map1 ); result = astIsAUnitMap( map2 ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); fs = astAnnul( fs ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int Fields( AstFrame *this, int axis, const char *fmt, const char *str, int maxfld, char **fields, int *nc, double *val, int *status ) { /* *+ * Name: * astFields * Purpose: * Identify numerical fields within a formatted Axis value. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astFields( AstFrame *this, int axis, const char *fmt, * const char *str, int maxfld, char **fields, * int *nc, double *val ) * Class Membership: * Frame method. * Description: * This function identifies the numerical fields within a Frame axis * value that has been formatted using astAxisFormat. It assumes that * the value was formatted using the supplied format string. It also * returns the equivalent floating point value. * Parameters: * this * Pointer to the Frame. * axis * The number of the Frame axis for which the values have been * formatted (axis numbering starts at zero for the first axis). * fmt * Pointer to a constant null-terminated string containing the * format used when creating "str". * str * Pointer to a constant null-terminated string containing the * formatted value. * maxfld * The maximum number of fields to identify within "str". * fields * A pointer to an array of at least "maxfld" character pointers. * Each element is returned holding a pointer to the start of the * corresponding field in "str" (in the order in which they occur * within "str"), or NULL if no corresponding field can be found. * nc * A pointer to an array of at least "maxfld" integers. Each * element is returned holding the number of characters in the * corresponding field, or zero if no corresponding field can be * found. * val * Pointer to a location at which to store the value * equivalent to the returned field values. If this is NULL, * it is ignored. * Returned Value: * The number of fields succesfully identified and returned. * Notes: * - Leading and trailing spaces are ignored. * - If the formatted value is not consistent with the supplied format * string, then a value of zero will be returned, "fields" will be * returned holding NULLs, "nc" will be returned holding zeros, and * "val" is returned holding VAL__BAD. * - Fields are counted from the start of the formatted string. If the * string contains more than "maxfld" fields, then trailing fields are * ignored. * - If this function is invoked with the global error status set, or * if it should fail for any reason, then a value of zero will be returned * as the function value, and "fields", "nc" and "val" will be returned * holding their supplied values *- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ int result; /* Result field count to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astFields" ); ax = astGetAxis( this, axis ); /* Invoke the Axis astAxisFields method to perform the processing. */ result = astAxisFields( ax, fmt, str, maxfld, fields, nc, val ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the returned value. */ if ( !astOK ) result = 0; /* Return the result. */ return result; } static AstFrameSet *FindFrame( AstFrame *target, AstFrame *template, const char *domainlist, int *status ) { /* *++ * Name: c astFindFrame f AST_FINDFRAME * Purpose: * Find a coordinate system with specified characteristics. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c AstFrameSet *astFindFrame( AstFrame *target, AstFrame *template, c const char *domainlist ) f RESULT = AST_FINDFRAME( TARGET, TEMPLATE, DOMAINLIST, STATUS ) * Class Membership: * Frame method. * Description: * This function uses a "template" Frame to search another Frame * (or FrameSet) to identify a coordinate system which has a * specified set of characteristics. If a suitable coordinate * system can be found, the function returns a pointer to a * FrameSet which describes the required coordinate system and how * to convert coordinates to and from it. * * This function is provided to help answer general questions about * coordinate systems, such as typically arise when coordinate * information is imported into a program as part of an initially * unknown dataset. For example: * - Is there a wavelength scale? * - Is there a 2-dimensional coordinate system? * - Is there a celestial coordinate system? * - Can I plot the data in ecliptic coordinates? * * You can also use this function as a means of reconciling a * user's preference for a particular coordinate system (for * example, what type of axes to draw) with what is actually * possible given the coordinate information available. * * To perform a search, you supply a "target" Frame (or FrameSet) * which represents the set of coordinate systems to be searched. * If a basic Frame is given as the target, this set of coordinate * systems consists of the one described by this Frame, plus all * other "virtual" coordinate systems which can potentially be * reached from it by applying built-in conversions (for example, * any of the celestial coordinate conversions known to the AST * library would constitute a "built-in" conversion). If a FrameSet * is given as the target, the set of coordinate systems to be * searched consists of the union of those represented by all the * individual Frames within it. * * To select from this large set of possible coordinate systems, * you supply a "template" Frame which is an instance of the type * of Frame you are looking for. Effectively, you then ask the * function to "find a coordinate system that looks like this". * * You can make your request more or less specific by setting * attribute values for the template Frame. If a particular * attribute is set in the template, then the function will only * find coordinate systems which have exactly the same value for * that attribute. If you leave a template attribute un-set, * however, then the function has discretion about the value the * attribute should have in any coordinate system it finds. The * attribute will then take its value from one of the actual * (rather than virtual) coordinate systems in the target. If the * target is a FrameSet, its Current attribute will be modified to * indicate which of its Frames was used for this purpose. * * The result of this process is a coordinate system represented by * a hybrid Frame which acquires some attributes from the template * (but only if they were set) and the remainder from the * target. This represents the "best compromise" between what you * asked for and what was available. A Mapping is then generated * which converts from the target coordinate system to this hybrid * one, and the returned FrameSet encapsulates all of this * information. * Parameters: c target f TARGET = INTEGER (Given) * Pointer to the target Frame (or FrameSet). * * Note that if a FrameSet is supplied (and a suitable * coordinate system is found), then its Current attribute will * be modified to indicate which Frame was used to obtain * attribute values which were not specified by the template. * This Frame will, in some sense, represent the "closest" * non-virtual coordinate system to the one you requested. c template f TEMPLATE = INTEGER (Given) * Pointer to the template Frame, which should be an instance of * the type of Frame you wish to find. If you wanted to find a * Frame describing a celestial coordinate system, for example, * then you might use a SkyFrame here. See the "Examples" * section for more ideas. c domainlist f DOMAINLIST = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string containing a f A character string containing a * comma-separated list of Frame domains. This may be used to * establish a priority order for the different types of * coordinate system that might be found. * * The function will first try to find a suitable coordinate * system whose Domain attribute equals the first domain in this * list. If this fails, the second domain in the list will be * used, and so on, until a result is obtained. A blank domain * (e.g. two consecutive commas) indicates that any coordinate * system is acceptable (subject to the template) regardless of * its domain. * * This list is case-insensitive and all white space is ignored. * If you do not wish to restrict the domain in this way, c you should supply an empty string. f you should supply a blank string. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astFindFrame() f AST_FINDFRAME = INTEGER * If the search is successful, the function returns a pointer * to a FrameSet which contains the Frame found and a * description of how to convert to (and from) the coordinate * system it represents. Otherwise, a null Object pointer * (AST__NULL) is returned without error. * * If a FrameSet is returned, it will contain two Frames. Frame * number 1 (its base Frame) represents the target coordinate * system and will be the same as the (base Frame of the) * target. Frame number 2 (its current Frame) will be a Frame * representing the coordinate system which the function * found. The Mapping which inter-relates these two Frames will * describe how to convert between their respective coordinate * systems. * * Note that a FrameSet may be used both as a Mapping and as a * Frame. If the result is used as a Mapping (e.g. with * astTran2), then it provides a means of converting coordinates * from the target coordinate system into the new coordinate * system that was found (and vice versa if its inverse * transformation is selected). If it is used as a Frame, its * attributes will describe the new coordinate system. * Applicability: * Frame * This function applies to all Frames. * FrameSet * If the target is a FrameSet, the possibility exists that * several of the Frames within it might be matched by the * template. Unless the choice is sufficiently restricted by c the "domainlist" string, the sequence in which Frames are f the DOMAINLIST string, the sequence in which Frames are * searched can then become important. In this case, the search * proceeds as follows: c - Each field in the "domainlist" string is considered in turn. f - Each field in the DOMAINLIST string is considered in turn. * - An attempt is made to match the template to each of the * target's Frames in the order: (1) the current Frame, (2) the * base Frame, (3) each remaining Frame in the order of being * added to the target FrameSet. * - Generally, the first match found is used. However, the * Mapping between the target coordinate system and the * resulting Frame is also examined. Preference is given to * cases where both the forward and inverse transformations are * defined (as indicated by the TranForward and TranInverse * attributes). If only one transformation is defined, the * forward one is preferred. * - If a match is found and the domain of the resulting Frame also c matches the current "domainlist" field, it is f matches the current DOMAINLIST field, it is c accepted. Otherwise, the next "domainlist" field is considered f accepted. Otherwise, the next DOMAINLIST field is considered * and the process repeated. * * If a suitable coordinate system is found, the Current * attribute of the target FrameSet will be modified on exit to * identify the Frame whose match with the target was eventually * accepted. * Examples: c result = astFindFrame( target, astFrame( 3, "" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 3, ' ', STATUS ), ' ', STATUS ) * Searches for a 3-dimensional coordinate system in the target * Frame (or FrameSet). No attributes have been set in the c template Frame (created by astFrame), so no restriction has f template Frame (created by AST_FRAME), so no restriction has * been placed on the required coordinate system, other than * that it should have 3 dimensions. The first suitable Frame c found will be returned as part of the "result" FrameSet. f found will be returned as part of the RESULT FrameSet. c result = astFindFrame( target, astSkyFrame( "" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( ' ', STATUS ), ' ', STATUS ) * Searches for a celestial coordinate system in the target * Frame (or FrameSet). The type of celestial coordinate system c is unspecified, so astFindFrame will return the first one f is unspecified, so AST_FINDFRAME will return the first one c found as part of the "result" FrameSet. If the target is f found as part of the RESULT FrameSet. If the target is * a FrameSet, then its Current attribute will be updated to * identify the Frame that was used. * * If no celestial coordinate system can be found, a value of * AST__NULL will be returned without error. c result = astFindFrame( target, astSkyFrame( "MaxAxes=100" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'MaxAxes=100', STATUS ), ' ', STATUS ) * This is like the last example, except that in the event of the * target being a CmpFrame, the component Frames encapsulated by the * CmpFrame will be searched for a SkyFrame. If found, the returned * Mapping will included a PermMap which selects the required axes * from the target CmpFrame. * * This is acomplished by setting the MaxAxes attribute of the * template SkyFrame to a large number (larger than or equal to the * number of axes in the target CmpFrame). This allows the SkyFrame * to be used as a match for Frames containing from 2 to 100 axes. c result = astFindFrame( target, astSkyFrame( "System=FK5" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'System=FK5', STATUS ), ' ', STATUS ) * Searches for an equatorial (FK5) coordinate system in the * target. The Equinox value for the coordinate system has not * been specified, so will be obtained from the target. If the * target is a FrameSet, its Current attribute will be updated * to indicate which SkyFrame was used to obtain this value. c result = astFindFrame( target, astFrame( 2, "" ), "sky,pixel," ); f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 2, ' ', STATUS ), 'SKY,PIXEL,', STATUS ) * Searches for a 2-dimensional coordinate system in the * target. Initially, a search is made for a suitable coordinate * system whose Domain attribute has the value "SKY". If this * search fails, a search is then made for one with the domain * "PIXEL". If this also fails, then any 2-dimensional c coordinate system is returned as part of the "result" f coordinate system is returned as part of the RESULT * FrameSet. * * Only if no 2-dimensional coordinate systems can be reached by * applying built-in conversions to any of the Frames in the * target will a value of AST__NULL be returned. c result = astFindFrame( target, astFrame( 1, "Domain=WAVELENGTH" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'Domain=WAVELENGTH', STATUS ), ' ', STATUS ) * Searches for any 1-dimensional coordinate system in the * target which has the domain "WAVELENGTH". c result = astFindFrame( target, astFrame( 1, "" ), "wavelength" ); f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, ' ', STATUS ), 'WAVELENGTH', STATUS ) * This example has exactly the same effect as that above. It * illustrates the equivalence of the template's Domain attribute c and the fields in the "domainlist" string. f and the fields in the DOMAINLIST string. c result = astFindFrame( target, astFrame( 1, "MaxAxes=3" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'MaxAxes=3', STATUS ), ' ', STATUS ) * This is a more advanced example which will search for any * coordinate system in the target having 1, 2 or 3 c dimensions. The Frame returned (as part of the "result" f dimensions. The Frame returned (as part of the RESULT * FrameSet) will always be 1-dimensional, but will be related * to the coordinate system that was found by a suitable Mapping * (e.g. a PermMap) which simply extracts the first axis. * * If we had wanted a Frame representing the actual (1, 2 or * 3-dimensional) coordinate system found, we could set the * PreserveAxes attribute to a non-zero value in the template. c result = astFindFrame( target, astSkyFrame( "Permute=0" ), "" ); f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'Permute=0', STATUS ), ' ', STATUS ) * Searches for any celestial coordinate system in the target, * but only finds one if its axes are in the conventional * (longitude,latitude) order and have not been permuted c (e.g. with astPermAxes). f (e.g. with AST_PERMAXES). * Notes: * - The Mapping represented by the returned FrameSet results in * alignment taking place in the coordinate system specified by the c AlignSystem attribute of the "template" Frame. See the description f AlignSystem attribute of the TEMPLATE Frame. See the description * of the AlignSystem attribute for further details. * - Beware of setting the Domain attribute of the template and then c using a "domainlist" string which does not include the template's domain f using a DOMAINLIST string which does not include the template's domain * (or a blank field). If you do so, no coordinate system will be * found. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * More on Using Templates: * A Frame (describing a coordinate system) will be found by this * function if (a) it is "matched" by the template you supply, and c (b) the value of its Domain attribute appears in the "domainlist" f (b) the value of its Domain attribute appears in the DOMAINLIST * string (except that a blank field in this string permits any * domain). A successful match by the template depends on a number * of criteria, as outlined below: * - In general, a template will only match another Frame which * belongs to the same class as the template, or to a derived (more * specialised) class. For example, a SkyFrame template will match * any other SkyFrame, but will not match a basic * Frame. Conversely, a basic Frame template will match any class * of Frame. * - The exception to this is that a Frame of any class can be used to * match a CmpFrame, if that CmpFrame contains a Frame of the same * class as the template. Note however, the MaxAxes and MinAxes * attributes of the template must be set to suitable values to allow * it to match the CmpFrame. That is, the MinAxes attribute must be * less than or equal to the number of axes in the target, and the MaxAxes * attribute must be greater than or equal to the number of axes in * the target. * - If using a CmpFrame as a template frame, the MinAxes and MaxAxes * for the template are determined by the MinAxes and MaxAxes values of * the component Frames within the template. So if you want a template * CmpFrame to be able to match Frames with different numbers of axes, * then you must set the MaxAxes and/or MinAxes attributes in the component * template Frames, before combining them together into the template * CmpFrame. * - If a template has a value set for any of its main attributes, then * it will only match Frames which have an identical value for that * attribute (or which can be transformed, using a built-in * conversion, so that they have the required value for that * attribute). If any attribute in the template is un-set, however, * then Frames are matched regardless of the value they may have * for that attribute. You may therefore make a template more or * less specific by choosing the attributes for which you set * values. This requirement does not apply to 'descriptive' attributes * such as titles, labels, symbols, etc. * - An important application of this principle involves the Domain * attribute. Setting the Domain attribute of the template has the * effect of restricting the search to a particular type of Frame * (with the domain you specify). Conversely, if the Domain * attribute is not set in the template, then the domain of the * Frame found is not relevant, so all Frames are searched. Note * that the c "domainlist" string provides an alternative way of restricting the f DOMAINLIST string provides an alternative way of restricting the * search in the same manner, but is a more convenient interface if * you wish to search automatically for another domain if the first * search fails. * - Normally, a template will only match a Frame which has the * same number of axes as itself. However, for some classes of * template, this default behaviour may be changed by means of the * MinAxes, MaxAxes and MatchEnd attributes. In addition, the * behaviour of a template may be influenced by its Permute and * PreserveAxes attributes, which control whether it matches Frames * whose axes have been permuted, and whether this permutation is * retained in the Frame which is returned (as opposed to returning * the axes in the order specified in the template, which is the * default behaviour). You should consult the descriptions of these * attributes for details of this more advanced use of templates. *-- */ /* Local Variables: */ AstFrame *frame; /* Pointer to result Frame */ AstFrameSet *result; /* Pointer to result FrameSet */ AstMapping *map; /* Pointer to result Mapping */ AstMapping *tmp; /* Temporary Mapping pointer */ char *domain_copy; /* Pointer to copy of result domain */ char *domainlist_copy; /* Pointer to copy of domains list */ const char *domain; /* Pointer to result Domain value */ int *target_axes; /* Pointer to target axis assignments */ int *template_axes; /* Pointer to template axis assignments */ int i; /* Loop counter for characters */ int j; /* Character index */ int match; /* Template matched target? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Allocate space to store a copy of the domains list, with added commas. */ domainlist_copy = astMalloc( strlen( domainlist ) + (size_t) 3 ); if ( astOK ) { /* Make a copy of the domains list, with an extra comma added at each end. Also remove all white space and convert to upper case. */ domainlist_copy[ 0 ] = ','; for ( i = 0, j = 1; domainlist[ i ]; i++ ) { if ( !isspace( domainlist[ i ] ) ) { domainlist_copy[ j++ ] = toupper( domainlist[ i ] ); } } domainlist_copy[ j++ ] = ','; domainlist_copy[ j ] = '\0'; /* Invoke the protected astMatch method associated with the template Frame. This matches the template to the target and returns information about how to convert between the target and the Frame it found (if any). */ match = astMatch( template, target, 0, &template_axes, &target_axes, &map, &frame ); /* If successful, obtain a pointer to the Domain string of the result Frame. Allocate space for a copy of this string, with added commas. */ if ( match && astOK ) { domain = astGetDomain( frame ); if ( astOK ) { domain_copy = astMalloc( strlen( domain ) + (size_t) 3 ); if ( astOK ) { /* Make a copy of the domain, adding an extra comma at each end. */ domain_copy[ 0 ] = ','; for ( i = 0, j = 1; domain[ i ]; i++ ) { domain_copy[ j++ ] = domain[ i ]; } domain_copy[ j++ ] = ','; domain_copy[ j ] = '\0'; /* Test if the domain appears in the domains list (with added commas). If not, test if a blank domain (which permits the result Frame to have any Domain) appears instead. */ if ( strstr( domainlist_copy, domain_copy ) || strstr( domainlist_copy, ",," ) ) { /* If the result Frame is acceptable, simplify the result Mapping. */ tmp = astSimplify( map ); map = astAnnul( map ); map = tmp; /* Build the result FrameSet. */ result = astFrameSet( target, "", status ); astAddFrame( result, AST__BASE, map, frame ); } } /* Free the copy of the result domain. */ domain_copy = astFree( domain_copy ); } /* Free space and annul pointers allocated by astMatch. */ template_axes = astFree( template_axes ); target_axes = astFree( target_axes ); map = astAnnul( map ); frame = astAnnul( frame ); } } /* Free the copy of the domains list. */ domainlist_copy = astFree( domainlist_copy ); /* If an error occurred, annul any result pointer. */ if ( !astOK && result ) result = astAnnul( result ); /* Return the result. */ return result; } const char *astFmtDecimalYr_( double year, int digits, int *status ) { /* *+ * Name: * astFmtDecimalYr * Purpose: * Format an epoch expressed in years as a decimal string. * Type: * Protected function. * Synopsis: * #include "frame.h" * const char *astFmtDecimalYr( double year, int digits ) * Class Membership: * Frame member function. * Description: * This function formats an epoch expressed in years as a decimal string * and returns a pointer to the result. It is intended for formatting * Frame Epoch values, etc, for display. * Parameters: * year * The epoch to be formatted. * digits * The number of digits of precision required. * Returned Value: * Pointer to a null terminated string containing the formatted value. * Notes: * - The result string is stored in static memory and may be * over-written by a subsequent invocation of this function. * - A NULL pointer is returned if this function is invoked with * the global error status set or if it should fail for any reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ int nc; /* Number of characters in buffer */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* Limit the precision to what is meaningful. */ digits = ( digits > DBL_DIG ) ? DBL_DIG : digits; /* Format the year value. Use "g" format to avoid buffer overflow and to get useful diagnostic output if a silly value is given. */ nc = sprintf( astfmtdecimalyr_buff, "%#.*g", digits, year ); /* Loop to remove redundant zeros from the end of the result. */ while ( astfmtdecimalyr_buff[ --nc ] == '0' ) astfmtdecimalyr_buff[ nc ] = '\0'; /* If the last character is now a decimal point, put back one zero. */ if ( astfmtdecimalyr_buff[ nc ] == '.' ) { astfmtdecimalyr_buff[ ++nc ] = '0'; astfmtdecimalyr_buff[ ++nc ] = '\0'; } /* Return the result. */ return astfmtdecimalyr_buff; } static const char *Format( AstFrame *this, int axis, double value, int *status ) { /* *+ * Name: * astFormat * Purpose: * Format a coordinate value for a Frame axis. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * const char *astFormat( AstFrame *this, int axis, double value ) * Class Membership: * Frame method. * Description: * This function returns a pointer to a string containing the * formatted (character) version of a coordinate value for a Frame * axis. The formatting applied is determined by the Frame's * attributes and, in particular, by any Format attribute string * that has been set for the axis. A suitable default format will * be applied if necessary. * Parameters: * this * Pointer to the Frame. * axis * The number of the Frame axis for which formatting is to be * performed (axis numbering starts at zero for the first axis). * value * The coordinate value to be formatted. * Returned Value: * A pointer to a null-terminated string containing the formatted * value. * Notes: * - The returned string pointer may point at memory allocated * within the Frame, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Frame. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic astFormat method available * via the protected interface to the Frame class. The public * interface to this method is provided by the astFormatId_ * function. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ const char *result; /* Pointer value to return */ int digits_set; /* Axis Digits attribute set? */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astFormat" ); ax = astGetAxis( this, axis ); /* Test if any Axis attributes which may affect the result are undefined (i.e. have not been explicitly set). If so, we over-ride them, giving them temporary values dictated by the Frame. Only the Digits attribute is relevant here. */ digits_set = astTestAxisDigits( ax ); if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) ); /* Format the value. */ result = astAxisFormat( ax, value ); /* Clear any Axis attributes that were temporarily over-ridden. */ if ( !digits_set ) astClearAxisDigits( ax ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = NULL; /* Return the result. */ return result; } static AstPointSet *FrameGrid( AstFrame *this, int size, const double *lbnd, const double *ubnd, int *status ){ /* *+ * Name: * astFrameGrid * Purpose: * Return a grid of points covering a rectangular area of a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstPointSet *astFrameGrid( AstFrame *this_frame, int size, * const double *lbnd, const double *ubnd ) * Class Membership: * Frame method. * Description: * This function returns a PointSet containing positions spread * approximately evenly throughtout a specified rectangular area of * the Frame. * Parameters: * this * Pointer to the Frame. * size * The preferred number of points in the returned PointSet. The * actual number of points in the returned PointSet may be * different, but an attempt is made to stick reasonably closely to * the supplied value. * lbnd * Pointer to an array holding the lower bound of the rectangular * area on each Frame axis. The array should have one element for * each Frame axis. * ubnd * Pointer to an array holding the upper bound of the rectangular * area on each Frame axis. The array should have one element for * each Frame axis. * Returned Value: * A pointer to a new PointSet holding the grid of points. * Notes: * - A NULL pointer is returned if an error occurs. *- */ /* Local Variables: */ AstPointSet *result; const char *unit; double **ptr; double *gmean; double *step; int *maxi; int *nsame; int *ntick; int *pi; int bad; int iax; int ipp; int jax; int naxes; int np; int ntick0; /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get the number of axes in the Frame. */ naxes = astGetNaxes( this ); /* Allocate an array to hold the number of ticks along each axis. */ ntick = astMalloc( sizeof(int)*naxes ); /* Allocate an array to hold the geometric mean of the lengths of the axes that have the same units as the current axis. */ gmean = astMalloc( naxes*sizeof(double) ); /* Allocate an array to hold the number of axes that share the same unit. */ nsame = astMalloc( naxes*sizeof(int) ); if( astOK ) { /* For each axis, find the total number of axes in the Frame that have the same unit string. Also, find the product of the lengths of these axes. */ bad = 0; for( iax = 0; iax < naxes; iax++ ) { nsame[ iax ] = 1; if( ubnd[ iax ] == AST__BAD && lbnd[ iax ] == AST__BAD ) { bad = 1; break; } gmean[ iax ] = ubnd[ iax ] - lbnd[ iax ]; unit = astGetUnit( this, iax ); for( jax = 0; jax < naxes; jax++ ) { if( jax != iax ) { if( astOK && !strcmp( unit, astGetUnit( this, jax ) ) ) { nsame[ iax ]++; gmean[ iax ] *= ubnd[ jax ] - lbnd[ jax ]; } } } } /* Do nothing if any bad bounds were supplied, or if the size is less than 1. */ if( !bad && size >= 1 ) { /* Get the nominal number of ticks per axis. */ ntick0 = pow( size, 1.0/(double)naxes ); if( ntick0 < 2 ) ntick0 = 2; /* Convert the dimension products into geometric means. */ for( iax = 0; iax < naxes; iax++ ) { gmean[ iax ] = pow( fabs(gmean[ iax ]), 1.0/(double)nsame[ iax ] ); } /* The number of ticks to use on each axis is equal to the nominal number multiplied by the ratio of the axis length to the geometric mean of the axis lengths that sahare the same unit string. This gives more ticks on the longer axes within any group of common-unit axes, whilst retaining the overall number of ticks (roughly). Also find the total number of points. */ np = 1; for( iax = 0; iax < naxes; iax++ ) { ntick[ iax ] = ntick0*( ubnd[ iax ] - lbnd[ iax ] )/gmean[ iax ]; if( ntick[ iax ] < 2 ) ntick[ iax ] = 2; np *= ntick[ iax ]; } /* Create a PointSet large enough to hold this many points. */ result = astPointSet( np, naxes, " ", status ); ptr = astGetPoints( result ); /* Allocate memory to hold the max indices on each axis. */ maxi = astMalloc( sizeof( int )*(size_t) naxes ); /* Allocate memory to hold the indices of the current position.*/ pi = astMalloc( sizeof( int )*(size_t) naxes ); /* Allocate memory to hold the step size for each axis. */ step = astMalloc( sizeof( double )*(size_t) naxes ); if( astOK ) { /* For every axis, set up the step size, initialise the current position to the lower bound, and store a modified upper limit which includes some safety marging to allow for rounding errors. */ for( iax = 0; iax < naxes; iax++ ) { step[ iax ] = ( ubnd[ iax ] - lbnd[ iax ] )/( ntick[ iax ] - 1 ); pi[ iax ] = 0; maxi[ iax ] = ntick[ iax ] - 1; } /* Initialise the index of the next position to store. */ ipp = 0; /* Loop round adding points to the array until the whole volume has been done. */ iax = 0; while( iax < naxes ) { /* Add the current point to the supplied array, and increment the index of the next point to add. */ for( iax = 0; iax < naxes; iax++ ) { ptr[ iax ][ ipp ] = lbnd[ iax ] + pi[ iax ]*step[ iax ]; } ipp++; /* We now move the current position on to the next sample */ iax = 0; while( iax < naxes ) { pi[ iax ]++; if( pi[ iax ] > maxi[ iax ] ) { pi[ iax ] = 0; iax++; } else { break; } } } } /* Free resources. */ maxi = astFree( maxi ); pi = astFree( pi ); step = astFree( step ); /* Report error if supplied values were bad. */ } else if( astOK ) { if( bad ) { astError( AST__ATTIN, "astFrameGrid(%s): One of more of the " "supplied bounds is AST__BAD (programming error).", status, astGetClass( this ) ); } else if( size < 1 ) { astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid " "size (%d) is invalid (programming error).", status, astGetClass( this ), size ); } } } /* Free resources. */ ntick = astFree( ntick ); nsame = astFree( nsame ); gmean = astFree( gmean ); /* Annul the returned PointSet if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the PointSet holding the grid. */ return result; } static double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) { /* *+ * Name: * astGap * Purpose: * Find a "nice" gap for tabulating Frame axis values. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * double astGap( AstFrame *this, int axis, double gap, int *ntick ) * Class Membership: * Frame method. * Description: * This function returns a gap size which produces a nicely spaced * series of formatted values for a Frame axis, the returned gap * size being as close as possible to the supplied target gap * size. It also returns a convenient number of divisions into * which the gap can be divided. * Parameters: * this * Pointer to the Frame. * axis * The number of the axis (zero-based) for which a gap is to be found. * gap * The target gap size. * ntick * Address of an int in which to return a convenient number of * divisions into which the gap can be divided. * Returned Value: * The nice gap size. * Notes: * - A value of zero is returned if the target gap size is zero. * - A negative gap size is returned if the supplied gap size is negative. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ double result; /* The nice gap value */ /* Check the global error status. */ if ( !astOK ) return 0.0; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astGap" ); ax = astGetAxis( this, axis ); /* Find the gap. */ result = astAxisGap( ax, gap, ntick ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0.0; /* Return the result. */ return result; } static int GetActiveUnit( AstFrame *this, int *status ){ /* *++ * Name: c astGetActiveUnit f AST_GETACTIVEUNIT * Purpose: * Determines how the Unit attribute will be used. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c int astGetActiveUnit( AstFrame *this ) f RESULT = AST_GETACTIVEUNIT( THIS, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * returns the current value of the ActiveUnit flag for a Frame. See c the description of the astSetActiveUnit function f the description of the AST_SETACTIVEUNIT routine * for a description of the ActiveUnit flag. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetActiveUnit f AST_GETACTIVEUNIT = LOGICAL * The current value of the ActiveUnit flag. * Notes: c - A zero value will be returned if this function is c invoked with the AST error status set, or if it should fail for f - A value of .FALSE. will be returned if this function is f invoked with STATUS set to an error value, or if it should fail for * any reason. *-- */ /* Local Variables: */ AstAxis *ax; /* Pointer to axis structure */ int i; /* Index of axis in Frame */ int has_skyaxis; /* Does Frame contain any SkyAxes? */ int nax; /* Number of axes in Frame */ int result; /* The returned value */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* See if the Frame contains a SkyAxis. */ has_skyaxis = 0; nax = astGetNaxes( this ); for( i = 0; i < nax; i++ ) { ax = astGetAxis( this, i ); if( astIsASkyAxis( ax ) ) has_skyaxis = 1; ax = astAnnul( ax ); } /* If the Frame contains a SkyAxis the ActiveUnit flag is always zero. */ if( !has_skyaxis ) { /* Otherwise, get the value from the Frame. If it has not yet been assigned a value return the value zero. */ result = this->active_unit; if( result == -INT_MAX ) result = 0; } /* Return the result. */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Frame member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a Frame, formatted as a character string. * Parameters: * this * Pointer to the Frame. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - The returned string pointer may point at memory allocated * within the Frame, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the Frame. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstAxis *ax; /* Pointer to Axis */ AstFrame *pfrm; /* Pointer to primary Frame containing axis */ AstFrame *this; /* Pointer to the Frame structure */ AstSystemType system; /* System code */ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */ char *axis_attrib; /* Pointer to axis attribute name */ const char *old_attrib; /* Pointer to supplied attribute name string */ const char *result; /* Pointer value to return */ double dval; /* Double attibute value */ double epoch; /* Epoch attribute value (as MJD) */ int axis; /* Frame axis number */ int axis_nc; /* No. characters in axis attribute name */ int digits; /* Digits attribute value */ int direction; /* Direction attribute value */ int free_axis_attrib; /* Should axis_attrib be freed? */ int has_axis; /* Does attrib name include axis specifier? */ int len; /* Length of attrib string */ int match_end; /* MatchEnd attribute value */ int max_axes; /* MaxAxes attribute value */ int min_axes; /* MinAxes attribute value */ int naxes; /* Naxes attribute value */ int nc; /* No. characters read by astSscanf */ int oldrep; /* Original error reporting state */ int paxis; /* Axis index within primary frame */ int permute; /* Permute attribute value */ int preserve_axes; /* PreserveAxes attribute value */ int used; /* Could the setting string be used? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Set a flag indicating if the attribute name includes an axis specifier. */ has_axis = ( strchr( attrib, '(' ) != NULL ); /* A flag indicating that we do not need to free the axis_attrib memory. */ free_axis_attrib = 0; /* Initialise things to avoid compiler warnings. */ axis_attrib = NULL; old_attrib = NULL; /* Jump back to here if we are trying the same attribute but with an explicit axis "(1)" added to the end of the name. */ L1: /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Save the number of axes in the Frame for later use. */ naxes = astGetNaxes( this ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* Digits. */ /* ------- */ if ( !strcmp( attrib, "digits" ) ) { digits = astGetDigits( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", digits ); result = getattrib_buff; } /* Digits(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { /* There is no function to obtain the Digits attribute value for an axis directly, so obtain a pointer to the Axis and use this to obtain the value. Use the Frame's Digits attribute instead if the Axis attribute value is not set. */ (void) astValidateAxis( this, axis - 1, 1, "astGetDigits(axis)" ); ax = astGetAxis( this, axis - 1 ); if ( astTestAxisDigits( ax ) ) { digits = astGetAxisDigits( ax ); } else { digits = astGetDigits( this ); } ax = astAnnul( ax ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", digits ); result = getattrib_buff; } /* Direction(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { direction = astGetDirection( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", direction ); result = getattrib_buff; } /* Epoch. */ /* ------ */ } else if ( !strcmp( attrib, "epoch" ) ) { epoch = astGetEpoch( this ); if ( astOK ) { /* Format the Epoch as decimal years. Use a Besselian epoch if it will be less than 1984.0, otherwise use a Julian epoch. */ result = astFmtDecimalYr( ( epoch < palEpj2d( 1984.0 ) ) ? palEpb( epoch ) : palEpj( epoch ), DBL_DIG ); } /* Top(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetTop( this, axis -1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Bottom(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetBottom( this, axis -1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Domain. */ /* ------- */ } else if ( !strcmp( attrib, "domain" ) ) { result = astGetDomain( this ); /* Format(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astGetFormat( this, axis - 1 ); /* Label(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astGetLabel( this, axis - 1 ); /* MatchEnd. */ /* --------- */ } else if ( !strcmp( attrib, "matchend" ) ) { match_end = astGetMatchEnd( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", match_end ); result = getattrib_buff; } /* MaxAxes. */ /* -------- */ } else if ( !strcmp( attrib, "maxaxes" ) ) { max_axes = astGetMaxAxes( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", max_axes ); result = getattrib_buff; } /* MinAxes. */ /* -------- */ } else if ( !strcmp( attrib, "minaxes" ) ) { min_axes = astGetMinAxes( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", min_axes ); result = getattrib_buff; } /* Naxes. */ /* -----_ */ } else if ( !strcmp( attrib, "naxes" ) ) { (void) sprintf( getattrib_buff, "%d", naxes ); result = getattrib_buff; /* Permute. */ /* -------- */ } else if ( !strcmp( attrib, "permute" ) ) { permute = astGetPermute( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", permute ); result = getattrib_buff; } /* PreserveAxes. */ /* ------------- */ } else if ( !strcmp( attrib, "preserveaxes" ) ) { preserve_axes = astGetPreserveAxes( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", preserve_axes ); result = getattrib_buff; } /* Symbol(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astGetSymbol( this, axis - 1 ); /* AlignSystem. */ /* ------------ */ /* Obtain the AlignSystem code and convert to a string. */ } else if ( !strcmp( attrib, "alignsystem" ) ) { system = astGetAlignSystem( this ); if ( astOK ) { result = astSystemString( this, system ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid " "AlignSystem identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); } } /* System. */ /* ------- */ /* Obtain the System code and convert to a string. */ } else if ( !strcmp( attrib, "system" ) ) { system = astGetSystem( this ); if ( astOK ) { result = astSystemString( this, system ); /* Report an error if the value was not recognised. */ if ( !result ) { astError( AST__SCSIN, "astGetAttrib(%s): Corrupt %s contains invalid " "System identification code (%d).", status, astGetClass( this ), astGetClass( this ), (int) system ); } } /* Title. */ /* ------ */ } else if ( !strcmp( attrib, "title" ) ) { result = astGetTitle( this ); /* Unit(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astGetUnit( this, axis - 1 ); /* NormUnit(axis). */ /* --------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "normunit(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astGetNormUnit( this, axis - 1 ); /* ObsLat. */ /* ------- */ } else if ( !strcmp( attrib, "obslat" ) ) { dval = astGetObsLat( this ); if ( astOK ) { /* If not already created, create an FK5 J2000 SkyFrame which will be used for formatting and unformatting ObsLon and ObsLat values. */ if( !skyframe ) { astBeginPM; skyframe = astSkyFrame("system=FK5,equinox=J2000,format(2)=dms.2", status ); astEndPM; } /* Display absolute value preceded by "N" or "S" as appropriate. */ if( dval < 0 ) { (void) sprintf( getattrib_buff, "S%s", astFormat( skyframe, 1, -dval ) ); } else { (void) sprintf( getattrib_buff, "N%s", astFormat( skyframe, 1, dval ) ); } result = getattrib_buff; } /* ObsLon. */ /* ------- */ } else if ( !strcmp( attrib, "obslon" ) ) { dval = astGetObsLon( this ); if ( astOK ) { /* Put into range +/- PI. */ dval = palDrange( dval ); /* If not already created, create an FK5 J2000 SkyFrame which will be used for formatting and unformatting ObsLon and ObsLat values. */ if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status ); astEndPM; } /* Display absolute value preceded by "E" or "W" as appropriate. */ if( dval < 0 ) { (void) sprintf( getattrib_buff, "W%s", astFormat( skyframe, 1, -dval ) ); } else { (void) sprintf( getattrib_buff, "E%s", astFormat( skyframe, 1, dval ) ); } result = getattrib_buff; } /* ObsAlt. */ /* ------- */ } else if ( !strcmp( attrib, "obsalt" ) ) { dval = astGetObsAlt( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Dut1. */ /* ---- */ } else if ( !strcmp( attrib, "dut1" ) ) { dval = astGetDut1( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* Other axis attributes. */ /* ---------------------- */ /* If the attribute was not identified above, but appears to refer to a Frame axis, then it may refer to an Axis object of a derived type (which has additional attributes not recognised here). */ } else if ( !free_axis_attrib && ( nc = 0, ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n", &axis_nc, &axis, &nc ) ) && ( nc >= len ) ) ) { /* Validate the axis index and extract the attribute name. */ (void) astValidateAxis( this, axis - 1, 1, "astGet" ); axis_attrib = astString( attrib, axis_nc ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis - 1 ); if( astOK ) { /* Assume that we will be able to use the attribute name. */ used = 1; /* Temporarily switch off error reporting so that if the following attempt to access the axis attribute fails, we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. Any errors reported in this context will simply be ignored, in particularly they are not deferred for later delivery. */ oldrep = astReporting( 0 ); /* Use the Axis astGetAttrib method to obtain the result. */ result = astGetAttrib( ax, axis_attrib ); /* If the above call failed with a status of AST__BADAT, indicating that the attribute name was not recognised, clear the status so that we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. */ if( astStatus == AST__BADAT ) { astClearStatus; /* Find the primary Frame containing the specified axis. */ astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); /* Only attempt to use the primary Frame if it is not the same as "this" - otherwise we could end up in an infinite loop. */ if( pfrm != this ) { /* astPrimaryFrame returns the original - unpermuted - axis index within the primary Frame. So we need to take into account any axis permutation which has been applied to the primary Frame when forming the attribute name to use below. Find the permuted (external) axis index which corresponds to the internal (unpermuted) axis index "paxis". */ paxis = astValidateAxis( pfrm, paxis, 0, "astGet" ); /* Modify the attribute name to refer to the axis numbering of the primary frame. */ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 ); /* Attempt to use the Axis astGetAttrib method to obtain the result. */ result = astGetAttrib( pfrm, pfrm_attrib ); /* If this failed, clear the status and indicate that we have not managed to use the attribute name. */ if( !astOK ) { astClearStatus; used = 0; } } else { used = 0; } /* If not found attempt to get the attribute value from the Axis, omitting the axis index. */ if( ! used ) { result = astGetAttrib( pfrm, axis_attrib ); if( !astOK ) { astClearStatus; } else { used = 1; } } /* Annul the primary Frame pointer. */ pfrm = astAnnul( pfrm ); } /* Re-instate the original error reporting state. */ astReporting( oldrep ); /* If we could not use the attribute name, attempt to get the axis attribute again, this time retaining the error report. This is done to ensure the user gets an appropriate error message. */ if( !used ) result = astGetAttrib( ax, axis_attrib ); } /* Annul the Axis pointer and free the memory holding the attribute name. */ ax = astAnnul( ax ); axis_attrib = astFree( axis_attrib ); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, and the Frame has only 1 axis, and the attribute name does not already include an axis specifier, try again after appending "(1)" to the end of the attribute name. */ } else if( !has_axis && naxes == 1 ) { /* Take a copy of the supplied name, allowing 3 extra characters for the axis specifier "(1)". */ axis_attrib = astMalloc( len + 4 ); if( axis_attrib ) memcpy( axis_attrib, attrib, len ); /* Indicate we should free the axis_attrib memory. */ free_axis_attrib = 1; /* Add in the axis specifier. */ strcpy( axis_attrib + len, "(1)" ); /* Use the new attribute name instead of the supplied name. */ old_attrib = attrib; attrib = axis_attrib; /* Indicate the attribute name now has an axis specifier. */ has_axis = 1; /* Jump back to try interpreting the new attribute name. */ goto L1; /* Not recognised. */ /* --------------- */ /* If the attribute name is still not recognised, pass it on to the parent method for further interpretation. First re-instate the original attrib name string if it was changed above. */ } else { if( free_axis_attrib ) { attrib = old_attrib; axis_attrib = astFree( axis_attrib ); } result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static AstAxis *GetAxis( AstFrame *this, int axis, int *status ) { /* *+ * Name: * astGetAxis * Purpose: * Obtain a pointer to a specified Axis from a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstAxis *astGetAxis( AstFrame *this, int axis ) * Class Membership: * Frame method. * Description: * This function returns a pointer to the Axis object associated * with one of the axes of a Frame. This object describes the * quantity which is represented along that axis. * Parameters: * this * Pointer to the Frame. * axis * The number of the axis (zero-based) for which an Axis pointer is * required. * Returned Value: * A pointer to the requested Axis object. * Notes: * - The reference count of the requested Axis object will be * incremented by one to reflect the additional pointer returned by * this function. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstAxis *result; /* Pointer to Axis */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise. */ result = NULL; /* Validate and permute the axis index. */ axis = astValidateAxis( this, axis, 1, "astGetAxis" ); /* If OK, clone the required Axis pointer. */ if ( astOK ) result = astClone( this->axis[ axis ] ); /* Return the result. */ return result; } static const char *GetDefaultLabel( int axis, int *status ) { /* * Name: * GetDefaultLabel * Purpose: * Return a pointer to a default axis Label string. * Type: * Private function. * Synopsis: * #include "frame.h" * const char *GetDefaultLabel( int axis, int *status ) * Class Membership: * Frame member function * Description: * This function returns a pointer to a string holding a default axis * Label value. * Parameters: * axis * Zero based axis index. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a static null-terminated string containing the attribute * value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* Format the axis index, putting the string in a global buffer. */ (void) sprintf( label_buff, "Axis %d", axis + 1 ); /* Return a pointer to the global buffer. */ return label_buff; } static const char *GetDefaultSymbol( AstFrame *this, int axis, int *status ) { /* * Name: * GetDefaultSymbol * Purpose: * Return a pointer to a default axis Symbol string. * Type: * Private function. * Synopsis: * #include "frame.h" * const char *GetDefaultSymbol( AstFrame *this, int axis, int *status ) * Class Membership: * Frame member function * Description: * This function returns a pointer to a string holding a default axis * Symbol value. * Parameters: * this * Pointer to the Frame. * axis * Zero based axis index. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a static null-terminated string containing the attribute * value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Note we use "sprintf" once to determine how many characters are produced by the "%d" format string and then limit the number of characters used from the Domain string in the second invocation of "sprintf" so that the total length of the default Symbol string does not exceed SYMBOL_BUFF_LEN characters. */ (void) sprintf( symbol_buff, "%.*s%d", SYMBOL_BUFF_LEN - sprintf( symbol_buff, "%d", axis + 1 ), astTestDomain( this ) ? astGetDomain( this ) : "x", axis + 1 ); /* Use the AddUnderscores function to replace any white space in the Symbol string with underscore characters. */ AddUnderscores( symbol_buff, status ); /* Return a pointer to the global buffer. */ return symbol_buff; } static const char *GetDefaultTitle( AstFrame *this, int *status ) { /* * Name: * GetDefaultTitle * Purpose: * Return a pointer to a default Title string. * Type: * Private function. * Synopsis: * #include "frame.h" * const char *GetDefaultTitle( AstFrame *this, int *status ) * Class Membership: * Frame member function * Description: * This function returns a pointer to a string holding a default Title value. * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a static null-terminated string containing the attribute * value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Create the Title value and put it in the global buffer. */ (void) sprintf( title_buff, "%d-d coordinate system", astGetNaxes( this ) ); /* Return a pointer to the global buffer. */ return title_buff; } static int GetFrameFlags( AstFrame *this, int *status ){ /* *+ * Name: * astGetFrameFlags * Purpose: * Return the bit mask of flags associated with a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * int *astGetFrameFlags( astFrame *this ) * Class Membership: * Frame virtual function. * Description: * This function returns a bit mask holding the current set of flags * associated with a Frame. See astSetFrameFlags for details of these * flags. * Parameters: * this * The Frame. * Returned Value: * The bit mask. * Notes: * - Zero is returned if this function is invoked with * the global error status set or if it should fail for any reason. *- */ /* Check the global error status. */ if ( !astOK ) return 0; /* Return the result. */ return this->flags; } static int GetIsLinear( AstMapping *this_mapping, int *status ){ /* * Name: * GetIsLinear * Purpose: * Return the value of the IsLinear attribute for a Frame. * Type: * Private function. * Synopsis: * #include "mapping.h" * void GetIsLinear( AstMapping *this, int *status ) * Class Membership: * Frame member function (over-rides the protected astGetIsLinear * method inherited from the Mapping class). * Description: * This function returns the value of the IsLinear attribute for a * Frame, which is always one because a Frame is treated like a UnitMap. * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. */ return 1; } static int GetIsSimple( AstMapping *this_mapping, int *status ){ /* * Name: * GetIsSimple * Purpose: * Return the value of the IsSimple attribute for a Frame. * Type: * Private function. * Synopsis: * #include "mapping.h" * void GetIsSimple( AstMapping *this, int *status ) * Class Membership: * Frame member function (over-rides the protected astGetIsSimple * method inherited from the Mapping class). * Description: * This function returns the value of the IsSimple attribute for a * Frame, which is always zero because Frames are not immutable (unlike * non-Frame Mappings). * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. */ return 0; } static int GetNaxes( AstFrame *this, int *status ) { /* *+ * Name: * astGetNaxes * Purpose: * Determine how many axes a Frame has. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astGetNaxes( AstFrame *this ) * Class Membership: * Frame method. * Description: * This function returns the number of axes for a Frame. * Parameters: * this * Pointer to the Frame. * Returned Value: * The number of Frame axes. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return 0; /* Return the number of Frame axes. */ return this->naxes; } static int GetNin( AstMapping *this_mapping, int *status ) { /* * Name: * GetNin * Purpose: * Get the number of input coordinates for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * int GetNin( AstMapping *this, int *status ) * Class Membership: * Frame member function (over-rides the astGetNin method inherited * from the Mapping class). * Description: * This function returns the number of input coordinate values * required per point by a Frame, when used as a Mapping (i.e. the * number of dimensions of the space in which input points reside). * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * Number of coordinate values required. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *this; /* Pointer to Frame structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_mapping; /* Return the number of Frame axes. */ result = astGetNaxes( this ); /* Return the result. */ return result; } static int GetNout( AstMapping *this_mapping, int *status ) { /* * Name: * GetNout * Purpose: * Get the number of output coordinates for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * int GetNout( AstMapping *this, int *status ) * Class Membership: * Frame member function (over-rides the astGetNout method * inherited from the Mapping class). * Description: * This function returns the number of output coordinate values * generated per point by a Frame, when used as a Mapping (i.e. the * number of dimensions of the space in which output points * reside). * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * Number of coordinate values generated. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *this; /* Pointer to Frame structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_mapping; /* Return the number of Frame axes. */ result = astGetNaxes( this ); /* Return the result. */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "frame.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * Frame member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied Frame, * in bytes. * Parameters: * this * Pointer to the Frame. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstFrame *this; /* Pointer to Frame structure */ int axis; /* Axis index */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the FrameSet structure. */ this = (AstFrame *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by this class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->variants ); result += astTSizeOf( this->domain ); result += astTSizeOf( this->title ); result += astTSizeOf( this->axis ); result += astTSizeOf( this->perm ); for ( axis = 0; axis < this->naxes; axis++ ) { result += astGetObjSize( this->axis[ axis ] ); } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const int *GetPerm( AstFrame *this, int *status ) { /* *+ * Name: * astGetPerm * Purpose: * Access the axis permutation array for a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * const int *astGetPerm( AstFrame *this ) * Class Membership: * Frame method. * Description: * This function returns a pointer to the axis permutation array * for a Frame. This array constitutes a lookup-table that converts * between an axis number supplied externally and the corresponding * index in the Frame's internal axis arrays. * Parameters: * this * Pointer to the Frame. * Returned Value: * Pointer to the Frame's axis permutation array (a constant array * of int). Each element of this contains the (zero-based) * internal axis index to be used in place of the external index * which is used to address the permutation array. If the Frame has * zero axes, this pointer will be NULL. * Notes: * - This protected method is provided to assist class * implementations which need to implement axis-dependent * extensions to Frame methods, and which therefore need to know * how a Frames's external axis index is converted for internal * use. * - The pointer returned by this function gives direct access to * data internal to the Frame object. It remains valid only so long * as the Frame exists. The permutation array contents may be * modified by other functions which operate on the Frame and this * may render the returned pointer invalid. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Return a pointer to the axis permutation array. */ return this->perm; } static AstFrameSet *GetFrameVariants( AstFrame *this, int *status ){ /* *+ * Name: * astGetFrameVariants * Purpose: * Returns the FrameSet holding the available Frame variants. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstFrameSet *astGetFrameVariants( AstFrame *this ) * Class Membership: * Frame method. * Description: * This function returns a pointer to any FrameSet previously stored * in the Frame using method astSetVariants. * Parameters: * this * Pointer to the Frame. * Returned Value: * astGetFrameVariants * A pointer to the FrameSet. It should be annulled using astAnnul * when no longer needed. NULL will be returned if no FrameSet is * stored in the Frame. * Notes: * - A NULL value will be returned if this function is invoked with the * AST error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstFrameSet *result; /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a clone of any FrameSet pointer. */ if( this->variants ) result = astClone( this->variants ); /* Return the result. */ return result; } void astInitFrameVtab_( AstFrameVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitFrameVtab * Purpose: * Initialise a virtual function table for a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * void astInitFrameVtab( AstFrameVtab *vtab, const char *name ) * Class Membership: * Frame vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the Frame class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAFrame ) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->Abbrev = Abbrev; vtab->CheckPerm = CheckPerm; vtab->ClearDigits = ClearDigits; vtab->ClearDirection = ClearDirection; vtab->ClearDomain = ClearDomain; vtab->ClearFormat = ClearFormat; vtab->ClearLabel = ClearLabel; vtab->ClearMatchEnd = ClearMatchEnd; vtab->ClearMaxAxes = ClearMaxAxes; vtab->ClearMinAxes = ClearMinAxes; vtab->ClearPermute = ClearPermute; vtab->ClearPreserveAxes = ClearPreserveAxes; vtab->ClearSymbol = ClearSymbol; vtab->ClearTitle = ClearTitle; vtab->ClearUnit = ClearUnit; vtab->Convert = Convert; vtab->ConvertX = ConvertX; vtab->Angle = Angle; vtab->Distance = Distance; vtab->Fields = Fields; vtab->FindFrame = FindFrame; vtab->MatchAxes = MatchAxes; vtab->MatchAxesX = MatchAxesX; vtab->Format = Format; vtab->Gap = Gap; vtab->GetAxis = GetAxis; vtab->GetDigits = GetDigits; vtab->GetDirection = GetDirection; vtab->GetDomain = GetDomain; vtab->GetFormat = GetFormat; vtab->GetLabel = GetLabel; vtab->GetMatchEnd = GetMatchEnd; vtab->GetMaxAxes = GetMaxAxes; vtab->GetMinAxes = GetMinAxes; vtab->GetNaxes = GetNaxes; vtab->GetPerm = GetPerm; vtab->GetPermute = GetPermute; vtab->GetPreserveAxes = GetPreserveAxes; vtab->GetSymbol = GetSymbol; vtab->GetTitle = GetTitle; vtab->GetUnit = GetUnit; vtab->GetNormUnit = GetNormUnit; vtab->Intersect = Intersect; vtab->IsUnitFrame = IsUnitFrame; vtab->Match = Match; vtab->Norm = Norm; vtab->NormBox = NormBox; vtab->AxDistance = AxDistance; vtab->AxOffset = AxOffset; vtab->AxIn = AxIn; vtab->AxAngle = AxAngle; vtab->FrameGrid = FrameGrid; vtab->Offset = Offset; vtab->Offset2 = Offset2; vtab->Resolve = Resolve; vtab->ResolvePoints = ResolvePoints; vtab->LineDef = LineDef; vtab->LineContains = LineContains; vtab->LineCrossing = LineCrossing; vtab->LineOffset = LineOffset; vtab->Overlay = Overlay; vtab->PermAxes = PermAxes; vtab->PickAxes = PickAxes; vtab->PrimaryFrame = PrimaryFrame; vtab->SetAxis = SetAxis; vtab->SetDigits = SetDigits; vtab->SetDirection = SetDirection; vtab->SetDomain = SetDomain; vtab->SetFormat = SetFormat; vtab->SetLabel = SetLabel; vtab->SetMatchEnd = SetMatchEnd; vtab->SetMaxAxes = SetMaxAxes; vtab->SetMinAxes = SetMinAxes; vtab->SetPermute = SetPermute; vtab->SetPreserveAxes = SetPreserveAxes; vtab->SetSymbol = SetSymbol; vtab->SetTitle = SetTitle; vtab->SetUnit = SetUnit; vtab->SubFrame = SubFrame; vtab->TestDigits = TestDigits; vtab->TestDirection = TestDirection; vtab->TestDomain = TestDomain; vtab->TestFormat = TestFormat; vtab->TestLabel = TestLabel; vtab->TestMatchEnd = TestMatchEnd; vtab->TestMaxAxes = TestMaxAxes; vtab->TestMinAxes = TestMinAxes; vtab->TestPermute = TestPermute; vtab->TestPreserveAxes = TestPreserveAxes; vtab->TestSymbol = TestSymbol; vtab->TestTitle = TestTitle; vtab->TestUnit = TestUnit; vtab->Unformat = Unformat; vtab->ValidateAxis = ValidateAxis; vtab->ValidateAxisSelection = ValidateAxisSelection; vtab->ValidateSystem = ValidateSystem; vtab->SystemString = SystemString; vtab->SystemCode = SystemCode; vtab->GetFrameFlags = GetFrameFlags; vtab->SetFrameFlags = SetFrameFlags; vtab->TestActiveUnit = TestActiveUnit; vtab->GetActiveUnit = GetActiveUnit; vtab->SetActiveUnit = SetActiveUnit; vtab->GetFrameVariants = GetFrameVariants; vtab->SetFrameVariants = SetFrameVariants; vtab->ClearSystem = ClearSystem; vtab->GetSystem = GetSystem; vtab->SetSystem = SetSystem; vtab->TestSystem = TestSystem; vtab->ClearAlignSystem = ClearAlignSystem; vtab->GetAlignSystem = GetAlignSystem; vtab->SetAlignSystem = SetAlignSystem; vtab->TestAlignSystem = TestAlignSystem; vtab->ClearTop = ClearTop; vtab->GetTop = GetTop; vtab->SetTop = SetTop; vtab->TestTop = TestTop; vtab->ClearBottom = ClearBottom; vtab->GetBottom = GetBottom; vtab->SetBottom = SetBottom; vtab->TestBottom = TestBottom; vtab->ClearEpoch = ClearEpoch; vtab->GetEpoch = GetEpoch; vtab->SetEpoch = SetEpoch; vtab->TestEpoch = TestEpoch; vtab->ClearObsLat = ClearObsLat; vtab->TestObsLat = TestObsLat; vtab->GetObsLat = GetObsLat; vtab->SetObsLat = SetObsLat; vtab->ClearObsLon = ClearObsLon; vtab->TestObsLon = TestObsLon; vtab->GetObsLon = GetObsLon; vtab->SetObsLon = SetObsLon; vtab->ClearObsAlt = ClearObsAlt; vtab->TestObsAlt = TestObsAlt; vtab->GetObsAlt = GetObsAlt; vtab->SetObsAlt = SetObsAlt; vtab->ClearDut1 = ClearDut1; vtab->GetDut1 = GetDut1; vtab->SetDut1 = SetDut1; vtab->TestDut1 = TestDut1; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_cleanattribs = object->CleanAttribs; object->CleanAttribs = CleanAttribs; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ mapping = (AstMappingVtab *) vtab; object->Equal = Equal; mapping->GetIsLinear = GetIsLinear; mapping->GetIsSimple = GetIsSimple; mapping->GetNin = GetNin; mapping->GetNout = GetNout; mapping->ReportPoints = ReportPoints; mapping->Transform = Transform; mapping->MapSplit = MapSplit; mapping->DoNotSimplify = DoNotSimplify; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "Frame", "Coordinate system description" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static void Intersect( AstFrame *this, const double a1[2], const double a2[2], const double b1[2], const double b2[2], double cross[2], int *status ) { /* *++ * Name: c astIntersect f AST_INTERSECT * Purpose: * Find the point of intersection between two geodesic curves. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astIntersect( AstFrame *this, const double a1[2], c const double a2[2], const double b1[2], c const double b2[2], double cross[2] ) f CALL AST_INTERSECT( THIS, A1, A2, B1, B2, CROSS, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * finds the coordinate values at the point of intersection between * two geodesic curves. Each curve is specified by two points on * the curve. It can only be used with 2-dimensional Frames. * * For example, in a basic Frame, it will find the point of * intersection between two straight lines. But for a SkyFrame it * will find an intersection of two great circles. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c a1 f A1( 2 ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of the * first point on the first geodesic curve. c a2 f A2( 2 ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of a * second point on the first geodesic curve. It should not be * co-incident with the first point. c b1 f B1( 2 ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of the * first point on the second geodesic curve. c b2 f B2( 2 ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of a * second point on the second geodesic curve. It should not be * co-incident with the first point. c cross f CROSS( 2 ) = DOUBLE PRECISION (Returned) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * in which the coordinates of the required intersection will * be returned. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - For SkyFrames each curve will be a great circle, and in general * each pair of curves will intersect at two diametrically opposite * points on the sky. The returned position is the one which is * closest to point c "a1". f A1. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the two * points defining either geodesic are co-incident, or if the two * curves do not intersect. c - The geodesic curve used by this function is the path of f - The geodesic curve used by this routine is the path of * shortest distance between two points, as defined by the c astDistance function. f AST_DISTANCE function. * - An error will be reported if the Frame is not 2-dimensional. *-- */ /* Local Variables: */ double ca; /* Y axis intercept of line a */ double cb; /* Y axis intercept of line b */ double dxa; /* X range spanned by line a */ double dxb; /* X range spanned by line b */ double ma; /* Gradient of line a */ double mb; /* Gradient of line b */ int naxes; /* Number of Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Initialize bad values. */ cross[ 0 ] = AST__BAD; cross[ 1 ] = AST__BAD; /* Determine the number of Frame axes. */ naxes = astGetNaxes( this ); /* Report an error if the Frame is not 2 dimensional. */ if( naxes != 2 && astOK ) { astError( AST__NAXIN, "astIntersect(%s): Invalid number of Frame axes (%d)." " astIntersect can only be used with 2 dimensonal Frames.", status, astGetClass( this ), naxes ); } /* Check that all supplied values are OK. */ if ( ( a1[ 0 ] != AST__BAD ) && ( a1[ 1 ] != AST__BAD ) && ( a2[ 0 ] != AST__BAD ) && ( a2[ 1 ] != AST__BAD ) && ( b1[ 0 ] != AST__BAD ) && ( b1[ 1 ] != AST__BAD ) && ( b2[ 0 ] != AST__BAD ) && ( b2[ 1 ] != AST__BAD ) ) { /* Find the x increments spanned by the two lines. */ /* Check the first line is not vertical. */ dxa = a2[ 0 ] - a1[ 0 ]; dxb = b2[ 0 ] - b1[ 0 ]; if( dxa != 0.0 ) { /* Find the gradient and Y axis intercept of the first line. */ ma = ( a2[ 1 ] - a1[ 1 ] )/dxa; ca = a1[ 1 ] - a1[ 0 ]*ma; /* Check the second line is not vertical. */ if( dxb != 0.0 ) { /* Find the gradient and Y axis intercept of the second line. */ mb = ( b2[ 1 ] - b1[ 1 ] )/dxb; cb = b1[ 1 ] - b1[ 0 ]*mb; /* Check the lines are not parallel. */ if( ma != mb ) { /* Find the intersection of the two lines. */ cross[ 0 ] = ( cb -ca )/( ma - mb ); cross[ 1 ] = ( ( ma + mb )*cross[ 0 ] + ca + cb )/2; } /* If the second line is vertical but the first is not. */ } else if( b1[ 1 ] != b2[ 1 ] ){ cross[ 0 ] = b1[ 0 ]; cross[ 1 ] = ma*b1[ 0 ] + ca; } /* First line is vertical but second is not. */ } else if( dxb != 0.0 && a1[ 1 ] != a2[ 1 ] ){ /* Find the gradient and Y axis intercept of the second line. */ mb = ( b2[ 1 ] - b1[ 1 ] )/dxb; cb = b1[ 1 ] - b1[ 0 ]*mb; /* Find the intercection. */ cross[ 0 ] = a1[ 0 ]; cross[ 1 ] = mb*a1[ 0 ] + cb; } } } static int IsUnitFrame( AstFrame *this, int *status ){ /* *+ * Name: * astIsUnitFrame * Purpose: * Is this Frame equivalent to a UnitMap? * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astIsUnitFrame( AstFrame *this ) * Class Membership: * Frame method. * Description: * This function returns a flag indicating if the supplied Frame is * equivalent to a UnitMap when treated as a Mapping (note, the Frame * class inherits from Mapping and therefore every Frame is also a Mapping). * Parameters: * this * Pointer to the Frame. * Returned Value: * A non-zero value is returned if the supplied Frame is equivalent to * a UnitMap when treated as a Mapping. *- */ /* Check the local error status. */ if( !astOK ) return 0; /* The base Frame class is always equivalent to a UnitMap. */ return 1; } static int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) { /* *+ * Name: * astLineContains * Purpose: * Determine if a line contains a point. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astLineContains( AstFrame *this, AstLineDef *l, int def, double *point ) * Class Membership: * Frame method. * Description: * This function determines if the supplied point is on the supplied * line within the supplied Frame. The start point of the line is * considered to be within the line, but the end point is not. The tests * are that the point of closest approach of the line to the point should * be between the start and end, and that the distance from the point to * the point of closest aproach should be less than 1.0E-7 of the length * of the line. * Parameters: * this * Pointer to the Frame. * l * Pointer to the structure defining the line. * def * Should be set non-zero if the "point" array was created by a * call to astLineCrossing (in which case it may contain extra * information following the axis values),and zero otherwise. * point * Point to an array containing the axis values of the point to be * tested, possibly followed by extra cached information (see "def"). * Returned Value: * A non-zero value is returned if the line contains the point. * Notes: * - The pointer supplied for "l" should have been created using the * astLineDef method. These structures contained cached information about * the lines which improve the efficiency of this method when many * repeated calls are made. An error will be reported if the structure * does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. *- */ /* Local Variables: */ int result; double dx, dy, p; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Check that the line refers to the supplied Frame. */ if( l->frame != this ) { astError( AST__INTER, "astLineContains(%s): The supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); /* If the point is good, find the offsets from the start of the line. */ } else if( point[ 0 ] != AST__BAD && point[ 1 ] != AST__BAD ) { dx = point[ 0 ] - l->start[ 0 ]; dy = point[ 1 ] - l->start[ 1 ]; /* Check the nearest point on the line is between the start and end. Exclude the end point. */ p = dx*l->dir[ 0 ] + dy*l->dir[ 1 ]; if( p >= 0.0 && p < l->length ) { /* Check the distance from the point to the nearest point on the line is not further than 1.0E-7 of the length of the line. */ if( fabs( dx*l->q[ 0 ] + dy*l->q[ 1 ] ) <= 1.0E-7*l->length ) { result = 1; } } } /* Return zero if an error occurred. */ if( !astOK ) result = 0; /* Return a pointer to the output structure. */ return result; } static int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2, double **cross, int *status ) { /* *+ * Name: * astLineCrossing * Purpose: * Determine if two lines cross. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astLineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2, * double **cross ) * Class Membership: * Frame method. * Description: * This function determines if the two suplied line segments cross, * and if so returns the axis values at the point where they cross. * A flag is also returned indicating if the crossing point occurs * within the length of both line segments, or outside one or both of * the line segments. * Parameters: * this * Pointer to the Frame. * l1 * Pointer to the structure defining the first line. * l2 * Pointer to the structure defining the second line. * cross * Pointer to a location at which to put a pointer to a dynamically * alocated array containing the axis values at the crossing. If * NULL is supplied no such array is returned. Otherwise, the returned * array should be freed using astFree when no longer needed. If the * lines are parallel (i.e. do not cross) then AST__BAD is returned for * all axis values. Note usable axis values are returned even if the * lines cross outside the segment defined by the start and end points * of the lines. The order of axes in the returned array will take * account of the current axis permutation array if appropriate. Note, * sub-classes such as SkyFrame may append extra values to the end * of the basic frame axis values. A NULL pointer is returned if an * error occurs. * Returned Value: * A non-zero value is returned if the lines cross at a point which is * within the [start,end) segment of the lines that are flagged as * finite (if a line is marked as infinite any crossing is assumed to * be within the bounds of the line). If the crossing point is outside * this segment on either (inifinte) line, or if the lines are parallel, * zero is returned. Note, the start point is considered to be inside * the length of the segment, but the end point is outside. * Notes: * - The pointers supplied for "l1" and "l2" should have been created * using the astLineDef method. These structures contained cached * information about the lines which improve the efficiency of this method * when many repeated calls are made. An error will be reported if * either structure does not refer to the Frame specified by "this". * - Zero will be returned if this function is invoked with the global * error status set, or if it should fail for any reason. *- */ /* Local Variables: */ double *crossing; /* Returned array */ double den; /* Denominator */ double dx; /* Offset in start X values */ double dy; /* Offset in start Y values */ double t1; /* Distance from start of line 1 to crossing */ double t2; /* Distance from start of line 2 to crossing */ int result; /* Returned value */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise. */ result = 0; crossing = astMalloc( sizeof(double)*2 ); /* Check that both lines refer to the supplied Frame. */ if( l1->frame != this ) { astError( AST__INTER, "astLineCrossing(%s): First supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); } else if( l2->frame != this ) { astError( AST__INTER, "astLineCrossing(%s): Second supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); } else if( crossing ){ /* Each of the lines can be represented as "p = start + t.v" where start is the start position, v is the unit vector pointing from start to end, and t is the scalar distance from the start position. So to find the intersection put "start1 + t1.v1 = start2 + t2.v2" and solve for t1 and t2. */ den = (l1->dir[ 0 ])*(l2->dir[ 1 ]) - (l2->dir[ 0 ])*(l1->dir[ 1 ]); if( den != 0.0 ) { dx = l2->start[ 0 ] - l1->start[ 0 ]; dy = l2->start[ 1 ] - l1->start[ 1 ]; t1 = ( l2->dir[ 1 ]*dx - l2->dir[ 0 ]*dy )/den; t2 = ( l1->dir[ 1 ]*dx - l1->dir[ 0 ]*dy )/den; /* Store the crossing point, using the smaller t value to redue error. */ if( fabs( t1 ) < fabs( t2 ) ) { crossing[ 0 ] = l1->start[ 0 ] + t1*l1->dir[ 0 ]; crossing[ 1 ] = l1->start[ 1 ] + t1*l1->dir[ 1 ]; } else { crossing[ 0 ] = l2->start[ 0 ] + t2*l2->dir[ 0 ]; crossing[ 1 ] = l2->start[ 1 ] + t2*l2->dir[ 1 ]; } /* See if the intersection is within the length of both lines (excluding the end points). If a line is flagged as infinite, set the "t" parameter to zero to make it look like the crossing is within the line. */ if( l1->infinite ) t1 = 0.0; if( l2->infinite ) t2 = 0.0; if( t1 >= 0.0 && t1 < l1->length && t2 >= 0.0 && t2 < l2->length ) result = 1; } else { crossing[ 0 ] = AST__BAD; crossing[ 1 ] = AST__BAD; } } /* Return zero if an error occurred. */ if( !astOK ) { crossing = astFree( crossing ); result = 0; } /* Return the crossing pointer. */ if( cross ) { *cross = crossing; } else if( crossing ){ crossing = astFree( crossing ); } /* Return a pointer to the output structure. */ return result; } static AstLineDef *LineDef( AstFrame *this, const double start[2], const double end[2], int *status ) { /* *+ * Name: * astLineDef * Purpose: * Creates a structure describing a line segment in a 2D Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstLineDef *astLineDef( AstFrame *this, const double start[2], * const double end[2] ) * Class Membership: * Frame method. * Description: * This function creates a structure containing information describing a * given line segment within the supplied 2D Frame. This may include * information which allows other methods such as astLineCrossing to * function more efficiently. Thus the returned structure acts as a * cache to store intermediate values used by these other methods. * Parameters: * this * Pointer to the Frame. Must have 2 axes. * start * An array of 2 doubles marking the start of the line segment. * end * An array of 2 doubles marking the end of the line segment. * Returned Value: * Pointer to the memory structure containing the description of the * line. This structure should be freed using astFree when no longer * needed. A NULL pointer is returned (without error) if any of the * supplied axis values are AST__BAD. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstLineDef *result; /* Pointer to output structure */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Check the Frame has 2 axes. */ if( astGetNaxes( this ) != 2 ) { astError( AST__INTER, "astLineDef(%s): The supplied %s is not 2 " "dimensional (internal AST proramming error).", status, astGetClass( this ), astGetClass( this ) ); } /* Check the axis values are good */ if( start[ 0 ] != AST__BAD && start[ 1 ] != AST__BAD && end[ 0 ] != AST__BAD && end[ 1 ] != AST__BAD ) { /* Allocate memory for the returned structure. */ result = astMalloc( sizeof( AstLineDef ) ); if( result ) { /* Store the supplied axis values in the returned structure. */ result->start[ 0 ] = start[ 0 ]; result->start[ 1 ] = start[ 1 ]; result->end[ 0 ] = end[ 0 ]; result->end[ 1 ] = end[ 1 ]; /* Store the length of the line segment. */ result->length = astDistance( this, start, end ); /* Store a unit vector pointing from the start to the end. */ if( result->length > 0.0 ) { result->dir[ 0 ] = ( end[ 0 ] - start[ 0 ] )/result->length; result->dir[ 1 ] = ( end[ 1 ] - start[ 1 ] )/result->length; } else { result->dir[ 0 ] = 1.0; result->dir[ 1 ] = 0.0; } /* Store a unit vector perpendicular to the line, such that the vector points to the left, as vewied from the observer, when moving from the start to the end of the line. */ result->q[ 0 ] = -result->dir[ 1 ]; result->q[ 1 ] = result->dir[ 0 ]; /* Store a pointer to the defining Frame. */ result->frame = this; /* Indicate that the line is considered to be terminated at the start and end points. */ result->infinite = 0; } } /* Free the returned pointer if an error occurred. */ if( !astOK ) result = astFree( result ); /* Return a pointer to the output structure. */ return result; } static void LineOffset( AstFrame *this, AstLineDef *line, double par, double prp, double point[2], int *status ){ /* *+ * Name: * astLineOffset * Purpose: * Find a position close to a line. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void LineOffset( AstFrame *this, AstLineDef *line, double par, * double prp, double point[2] ) * Class Membership: * Frame method. * Description: * This function returns a position formed by moving a given distance along * the supplied line, and then a given distance away from the supplied line. * Parameters: * this * Pointer to the Frame. * line * Pointer to the structure defining the line. * par * The distance to move along the line from the start towards the end. * prp * The distance to move at right angles to the line. Positive * values result in movement to the left of the line, as seen from * the observer, when moving from start towards the end. * Notes: * - The pointer supplied for "line" should have been created using the * astLineDef method. This structure contains cached information about the * line which improves the efficiency of this method when many repeated * calls are made. An error will be reported if the structure does not * refer to the Frame specified by "this". *- */ /* Check the global error status. */ if ( !astOK ) return; /* Check that the line refers to the supplied Frame. */ if( line->frame != this ) { astError( AST__INTER, "astLineOffset(%s): The supplied line does " "not relate to the supplied %s (AST internal programming " "error).", status, astGetClass( this ), astGetClass( this ) ); /* This implementation uses simple flat geometry. */ } else { point[ 0 ] = line->start[ 0 ] + par*line->dir[ 0 ] + prp*line->q[ 0 ]; point[ 1 ] = line->start[ 1 ] + par*line->dir[ 1 ] + prp*line->q[ 1 ]; } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * CmpMap member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstFrame *this; /* Pointer to Frame structure */ int i; /* Loop count */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the Frame structure. */ this = (AstFrame *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ for( i = 0; i < this->naxes; i++ ) { if( !result ) result = astManageLock( this->axis[ i ], mode, extra, fail ); } if( this->variants && !result ) result = astManageLock( this->variants, mode, extra, fail ); return result; } #endif static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * Frame method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing Frame. This is only possible if the specified inputs * correspond to some subset of the Frame outputs. That is, there * must exist a subset of the Frame outputs for which each output * depends only on the selected Frame inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied Frame, then a NULL Mapping is returned. * Parameters: * this * Pointer to the Frame to be split (the Frame is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied Frame, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied Frame has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied Frame. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ int *result; /* Returned pointer */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Pick the selected axes from the Frame. */ *map = (AstMapping *) astPickAxes( (AstFrame *) this_map, nin, in, NULL ); /* Return a copy of the supplied axis array.*/ result = astStore( NULL, in, sizeof( int )*(size_t) nin ); /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static int Match( AstFrame *template, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { /* *+ * Name: * astMatch * Purpose: * Determine if conversion is possible between two coordinate systems. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astMatch( AstFrame *template, AstFrame *target, int matchsub, * int **template_axes, int **target_axes, * AstMapping **map, AstFrame **result ) * Class Membership: * Frame method. * Description: * This function matches a "template" frame to a "target" frame and * determines whether it is possible to convert coordinates between * them. If it is, a mapping that performs the transformation is * returned along with a new Frame that describes the coordinate * system that results when this mapping is applied to the "target" * coordinate system. In addition, information is returned to allow * the axes in this "result" Frame to be associated with the * corresponding axes in the "target" and "template" Frames from * which they are derived. * Parameters: * template * Pointer to the template Frame. This describes the coordinate * system (or set of possible coordinate systems) into which we * wish to convert our coordinates. * target * Pointer to the target Frame. This describes the coordinate * system in which we already have coordinates. * matchsub * If zero then a match only occurs if the template is of the same * class as the target, or of a more specialised class. If non-zero * then a match can occur even if this is not the case (i.e. if the * target is of a more specialised class than the template). In * this latter case, the target is cast down to the class of the * template. NOTE, this argument is handled by the global method * wrapper function "astMatch_", rather than by the class-specific * implementations of this method. * template_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the (zero-based) index of the * template Frame axis from which it is derived. If it is not * derived from any template frame axis, a value of -1 will be * returned instead. * target_axes * Address of a location where a pointer to int will be returned * if the requested coordinate conversion is possible. This * pointer will point at a dynamically allocated array of * integers with one element for each axis of the "result" Frame * (see below). It must be freed by the caller (using astFree) * when no longer required. * * For each axis in the result Frame, the corresponding element * of this array will return the (zero-based) index of the * target Frame axis from which it is derived. If it is not * derived from any target Frame axis, a value of -1 will be * returned instead. * map * Address of a location where a pointer to a new Mapping will * be returned if the requested coordinate conversion is * possible. If returned, the forward transformation of this * Mapping may be used to convert coordinates between the * "target" Frame and the "result" Frame (see below) and the * inverse transformation will convert in the opposite * direction. * result * Address of a location where a pointer to a new Frame will be * returned if the requested coordinate conversion is * possible. If returned, this Frame describes the coordinate * system that results from applying the returned Mapping * (above) to the "target" coordinate system. In general, this * Frame will combine attributes from (and will therefore be * more specific than) both the target and the template * Frames. In particular, when the template allows the * possibility of transformaing to any one of a set of * alternative coordinate systems, the "result" Frame will * indicate which of the alternatives was used. * Returned Value: * A non-zero value is returned if the requested coordinate * conversion is possible. Otherwise zero is returned (this will * not in itself result in an error condition). * Notes: * - By default, the "result" frame will have its number of axes * and axis order determined by the "template" Frame. However, if * the PreserveAxes attribute of the template frame is non-zero, * then the axis count and axis order of the "target" frame will be * used instead. * - The template_axes and target_axes arrays are provided so that * if the caller needs to permute the target and/or template axes * before invoking this function, it is possible to deduce how the * result axes should be permuted so as to correspond with the * original template/target axis order. * - For result axes that do not correspond with a template and/or * target axis (where a value of -1 is returned in the * template_axes and/or target_axes arrays), the caller has no * clear way of knowing where these axes should appear in any * permuted order. In this case, the relative position of these * axes within the result Frame (with respect to axes that do have * template/target axis associations) will be used to convey this * information. Such axes should be taken to be associated either * with the next preceding or following axis (depending on the * AST__MATCHEND flag of the template frame) which does have an * association. * - If the result Frame has zero axes, then NULL pointer values * will be returned for *template_axes and *target_axes. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * This implementation addresses the matching of a Frame class * object to other types of Frames (i.e. the target may be from a * derived class). A Frame will match any other type of Frame with * an acceptable number of axes but will not distinguish axis order * (i.e. it will match the axes in whatever order they are * given). If the template Frame has a value set for its Domain * attribute, then it will only match another Frame with the same * Domain. */ /* Local Variables: */ char *template_domain; /* Pointer to copy of template domain */ const char *ptr; /* Pointer to domain string */ const char *target_domain; /* Pointer to target domain string */ int match; /* Template matches target? */ int match_end; /* Match final axes of target? */ int max_axes; /* Maximum acceptable number of axes */ int min_axes; /* Minimum acceptable nu,ber of axes */ int preserve_axes; /* Preserve target axes? */ int result_axis; /* Loop counter for result axes */ int result_naxes; /* Number of result axes */ int target_naxes; /* Number of target axes */ int template_naxes; /* Number of template axes */ /* Initialise the returned values. */ *template_axes = NULL; *target_axes = NULL; *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* The first requirement for a match is that the target object is a Frame. This is already known to be true, as it forms part of the argument validation for this function. */ /* The second requirement is that the number of target axes is acceptable. Obtain the number of target axes and the minimum and maximum number of axes that the template will match. */ target_naxes = astGetNaxes( target ); min_axes = astGetMinAxes( template ); max_axes = astGetMaxAxes( template ); /* Test if the number of target axes is acceptable. */ if ( astOK ) { match = ( ( target_naxes >= min_axes ) && ( target_naxes <= max_axes ) ); } /* The third requirement is that if the template has its Domain attribute defined, then the target must also have the same Domain (although it need not be set - the default will do). First check if the template has a domain. */ if ( astOK && match ) { if ( astTestDomain( template ) ) { /* Obtain a pointer to the template domain. Then allocate memory and make a copy of it (this is necessary as we will next inquire the domain of the target and may over-write the buffer holding the template's domain). */ ptr = astGetDomain( template ); if ( astOK ) { template_domain = astStore( NULL, ptr, strlen( ptr ) + (size_t) 1 ); /* Obtain a pointer to the target domain. */ target_domain = astGetDomain( target ); /* Compare the domain strings for equality. Then free the memory allocated above. */ match = astOK && !strcmp( template_domain, target_domain ); template_domain = astFree( template_domain ); } } } /* If the template matches, obtain the values of the template's PreserveAxes and MatchEnd attributes and determine the number of template axes. */ if ( astOK && match ) { preserve_axes = astGetPreserveAxes( template ); match_end = astGetMatchEnd( template ); template_naxes = astGetNaxes( template ); /* If the PreserveAxes attribute is non-zero, the target axes should be preserved, so the number of result axes equals the number of target axes. Otherwise the number of template axes is used. */ result_naxes = preserve_axes ? target_naxes : template_naxes; /* Allocate memory for the arrays of axis associations to be returned. */ *template_axes = astMalloc( sizeof( int ) * (size_t) result_naxes ); *target_axes = astMalloc( sizeof( int ) * (size_t) result_naxes ); if ( astOK ) { /* Loop through each of the result axes. */ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { /* Set up the axis associations. By default, associate the first result axis with the first template/target axis. */ (*template_axes)[ result_axis ] = result_axis; (*target_axes)[ result_axis ] = result_axis; /* However, if the MatchEnd attribute is non-zero, associate the last result axis with the last template/target axis (this only makes a difference if there is a difference in the number of axes). */ if ( match_end ) { (*template_axes)[ result_axis ] += template_naxes - result_naxes; (*target_axes)[ result_axis ] += target_naxes - result_naxes; } /* If any of the associations would be with a template/target axis that doesn't exist, then use an axis index of -1 for the association instead. */ if ( ( (*template_axes)[ result_axis ] < 0 ) || ( (*template_axes)[ result_axis ] >= template_naxes ) ) { (*template_axes)[ result_axis ] = -1; } if ( ( (*target_axes)[ result_axis ] < 0 ) || ( (*target_axes)[ result_axis ] >= target_naxes ) ) { (*target_axes)[ result_axis ] = -1; } } /* Use the target's astSubFrame method to select the required axes from it, overlaying the template's attributes on to the resulting Frame. This process also generates the required Mapping between the target and result Frames. */ match = astSubFrame( target, template, result_naxes, *target_axes, *template_axes, map, result ); } } /* If an error occurred, free any allocated memory and reset the result. */ if ( !astOK || !match ) { *template_axes = astFree( *template_axes ); *target_axes = astFree( *target_axes ); match = 0; } /* Return the result. */ return match; } static void MatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes, int *status ) { /* *++ * Name: c astMatchAxes f AST_MATCHAXES * Purpose: * Find any corresponding axes in two Frames. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astMatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes ) f CALL AST_MATCHAXES( FRM1, FRM2, AXES, STATUS ) * Class Membership: * Frame method. * Description: * This function looks for corresponding axes within two supplied * Frames. An array of integers is returned that contains an element * for each axis in the second supplied Frame. An element in this array * will be set to zero if the associated axis within the second Frame * has no corresponding axis within the first Frame. Otherwise, it * will be set to the index (a non-zero positive integer) of the * corresponding axis within the first supplied Frame. * Parameters: c frm1 f FRM1 = INTEGER (Given) * Pointer to the first Frame. c frm2 f FRM2 = INTEGER (Given) * Pointer to the second Frame. c axes f AXES = INTEGER( * ) (Returned) c Pointer to an f An * integer array in which to return the indices of the axes (within * the first Frame) that correspond to each axis within the second * Frame. Axis indices start at 1. A value of zero will be stored * in the returned array for each axis in the second Frame that has * no corresponding axis in the first Frame. * * The number of elements in this array must be greater than or * equal to the number of axes in the second Frame. f STATUS = INTEGER (Given and Returned) f The global status. * Applicability: * Frame * This function applies to all Frames. * Notes: * - Corresponding axes are identified by the fact that a Mapping can * be found between them using c astFindFrame or astConvert. f AST_FINDFRAME or AST_CONVERT. * Thus, "corresponding axes" are not necessarily identical. For * instance, SkyFrame axes in two Frames will match even if they * describe different celestial coordinate systems *-- * Implementation Notes: * This function is simply a wrap-up for the protected astMatchAxesX * method which performs the required processing but swaps the order * of the first two arguments. This is a trick to allow the * astMatchAxes method to be over-ridden by derived classes on the * basis of the class of either of the first two arguments. * * In practice, each class that represents an encapsulated Frame (e.g. * FrameSet, Region, etc) should over-ride this method, extracting a * Frame from the supplied "frm1" pointer, and then invoking * astMatchAxesX. */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the "astMatchAxesX" method with the first two arguments swapped. */ astMatchAxesX( frm2, frm1, axes ); } static void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes, int *status ) { /* *+ * Name: * astMatchAxesX * Purpose: * Find any corresponding axes in two Frames. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astMatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes ) * Class Membership: * Frame method. * Description: * This function performs the processing for the public astMatchAxes * method and has exactly the same interface except that the order * of the first two arguments is swapped. This is a trick to allow * the astMatchAxes method to be over-ridden by derived classes on * the basis of the class of either of its first two arguments. * * See the astMatchAxes method for details of the interface. *- */ /* Local Variables: */ AstFrame *pfrm; AstFrame *resfrm; AstMapping *resmap; int *frm1_axes; int *pfrm_axes; int ifirst; int max_axes; int min_axes; int nax2; int pax; int preserve_axes; /* Check the global error status. */ if ( !astOK ) return; /* Temporarily ensure that the PreserveAxes attribute is non-zero in the second supplied Frame. This means thte result Frame returned by astMatch below will have the axis count and order of the target Frame (i.e. "pfrm"). */ if( astTestPreserveAxes( frm1 ) ) { preserve_axes = astGetPreserveAxes( frm1 ) ? 1 : 0; } else { preserve_axes = -1; } astSetPreserveAxes( frm1, 1 ); /* Temporarily ensure that the MaxAxes and MinAxes attributes in the second supplied Frame are set so the Frame can be used as a template in astMatch for matching any number of axes. */ if( astTestMaxAxes( frm1 ) ) { max_axes = astGetMaxAxes( frm1 ); } else { max_axes = -1; } astSetMaxAxes( frm1, 10000 ); if( astTestMinAxes( frm1 ) ) { min_axes = astGetMinAxes( frm1 ); } else { min_axes = -1; } astSetMinAxes( frm1, 1 ); /* Get the number of axes in the frm2 Frame. */ nax2 = astGetNaxes( frm2 ); /* Loop round the axes in the frm2 Frame. */ for( ifirst = 0; ifirst < nax2; ifirst++ ) { /* Identify the primary Frame defining the current axis in the frm2 Frame. */ astPrimaryFrame( frm2, ifirst, &pfrm, &pax ); /* Attempt to find a sub-frame within the frm1 Frame that corresponds to this primary Frame. */ if( astMatch( frm1, pfrm, 1, &frm1_axes, &pfrm_axes, &resmap, &resfrm ) ) { /* Store the one-based index within "frm1" of the corresponding axis. */ axes[ ifirst ] = frm1_axes[ pax ] + 1; /* Free resources */ frm1_axes = astFree( frm1_axes ); pfrm_axes = astFree( pfrm_axes ); resmap = astAnnul( resmap ); resfrm = astAnnul( resfrm ); /* If no corresponding axis was found store zero in the returned array. */ } else { axes[ ifirst ] = 0; } /* Free resouces. */ pfrm = astAnnul( pfrm ); } /* Re-instate the original attribute values in the frm1 Frame. */ if( preserve_axes == -1 ) { astClearPreserveAxes( frm1 ); } else { astSetPreserveAxes( frm1, preserve_axes ); } if( max_axes == -1 ) { astClearMaxAxes( frm1 ); } else { astSetMaxAxes( frm1, max_axes ); } if( min_axes == -1 ) { astClearMinAxes( frm1 ); } else { astSetMinAxes( frm1, min_axes ); } } static void NewUnit( AstAxis *ax, const char *old_units, const char *new_units, const char *method, const char *class, int *status ) { /* * Name: * NewUnit * Purpose: * Modify an Axis Label and Symbol to reflect a new Unit value. * Type: * Private function. * Synopsis: * #include "frame.h" * void NewUnit( AstAxis *ax, const char *old_units, const char *new_units, * const char *method, const char *class ) * Class Membership: * Frame method. * Description: * This function modifies the Label and Symbol attributes of an Axis * to reflect a new Unit value. This function should only be called if * the ActiveUnit flag of the parent Frame is non-zero (this is not * checked within this function). * * If the axis has a set label, then we may be able to modify it to * correctly describe the axis in the supplied new units. For instance, * if the original units were "Hz", the original label was "frequency", * and the new units are "log(Hz)", then the label is modified to become * "log( frequency )". * * The Axis Format attribute is cleared if the supplied units are * different to the old units (because any set format is probably not * going to be appropriate for a new system of units. * Parameters: * ax * Pointer to the Axis. * old_units * The original units value. * new_units * The new units value. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis selection. This method name is used * solely for constructing error messages. * class * Pointer to a constant null-terminated character string * containing the name of the class upon which this function * was invoked. This is used solely for constructing error messages. * Returned Value: * void. */ /* Local Variables: */ AstMapping *map; /* Pointer to units Mapping */ char *new_lab; /* Pointer to new axis label */ char *new_sym; /* Pointer to new axis symbol */ /* Check the global error status. */ if ( !astOK ) return; /* Check that the axis label is set. We relay on sub-classes to return appropriate default labels if the label is not set. */ if( astTestAxisLabel( ax ) ) { /* See if it is possible to map the old units into the new units. If it is, then a Mapping is returned together with an appropriately modified label. */ map = astUnitMapper( old_units, new_units, astGetAxisLabel( ax ), &new_lab ); /* If succesfull, annul the Mapping (which we do not need), and store the modified label in the Axis, finally freeing the memory used to hold the modified label. */ if( map ) { map = astAnnul( map ); if( new_lab ) { astSetAxisLabel( ax, new_lab ); new_lab = astFree( new_lab ); } } } /* Do the same for the axis symbol. */ if( astTestAxisSymbol( ax ) ) { map = astUnitMapper( old_units, new_units, astGetAxisSymbol( ax ), &new_sym ); if( map ) { map = astAnnul( map ); if( new_sym ) { astSetAxisSymbol( ax, new_sym ); new_sym = astFree( new_sym ); } } } /* If succesful, clear the axis format if the new and old units are different. */ if( astOK ) { if( strcmp( old_units, new_units ) ) astClearAxisFormat( ax ); } } static void Norm( AstFrame *this, double value[], int *status ) { /* *++ * Name: c astNorm f AST_NORM * Purpose: * Normalise a set of Frame coordinates. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astNorm( AstFrame *this, double value[] ) f CALL AST_NORM( THIS, VALUE, STATUS ) * Class Membership: * Frame method. * Description: c This function normalises a set of Frame coordinate values which f This routine normalises a set of Frame coordinate values which * might be unsuitable for display (e.g. may lie outside the * expected range) into a set of acceptable values suitable for * display. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c value f VALUE( * ) = DOUBLE PRECISION (Given and Returned) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * coordinate values representing a point in the space which the * Frame describes. If these values lie outside the expected * range for the Frame, they will be replaced with more * acceptable (normalised) values. Otherwise, they will be * returned unchanged. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - For some classes of Frame, whose coordinate values are not * constrained, this function will never modify the values * supplied. However, for Frames whose axes represent cyclic * quantities (such as angles or positions on the sky), coordinates * will typically be wrapped into an appropriate standard range, * such as zero to 2*pi. * - The NormMap class is a Mapping which can be used to normalise a * set of points using the c astNorm function f AST_NORM routine * of a specified Frame. * - It is intended to be possible to put any set of coordinates * into a form suitable for display by using this function to * normalise them, followed by appropriate formatting c (using astFormat). f (using AST_FORMAT). *-- */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ int axis; /* Loop counter for axes */ int naxes; /* Number of Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); /* Loop to process the coordinate for each axis in turn. */ for ( axis = 0; axis < naxes; axis++ ) { /* Obtain a pointer to the relevant Frame Axis. */ ax = astGetAxis( this, axis ); /* Normalise the coordinate for this axis. */ astAxisNorm( ax, value + axis ); /* Annul the pointer to the Axis. */ ax = astAnnul( ax ); /* Quit looping if an error occurs. */ if ( !astOK ) break; } } static void NormBox( AstFrame *this, double lbnd[], double ubnd[], AstMapping *reg, int *status ) { /* *+ * Name: * astNormBox * Purpose: * Extend a box to include effect of any singularities in the Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astNormBox( AstFrame *this, double lbnd[], double ubnd[], * AstMapping *reg ) * Class Membership: * Frame method. * Description: * This function modifies a supplied box to include the effect of any * singularities in the co-ordinate system represented by the Frame. * For a normal Cartesian coordinate system, the box will be returned * unchanged. Other classes of Frame may do other things. For instance, * a SkyFrame will check to see if the box contains either the north * or south pole and extend the box appropriately. * Parameters: * this * Pointer to the Frame. * lbnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * lower axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * ubnd * An array of double, with one element for each Frame axis * (Naxes attribute). Initially, this should contain a set of * upper axis bounds for the box. They will be modified on exit * to include the effect of any singularities within the box. * reg * A Mapping which should be used to test if any singular points are * inside or outside the box. The Mapping should leave an input * position unchanged if the point is inside the box, and should * set all bad if the point is outside the box. *- */ /* This base class returns the box limits unchanged. */ } static double Offset2( AstFrame *this, const double point1[2], double angle, double offset, double point2[2], int *status ){ /* *++ * Name: c astOffset2 f AST_OFFSET2 * Purpose: * Calculate an offset along a geodesic curve in a 2D Frame. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c double astOffset2( AstFrame *this, const double point1[2], double angle, c double offset, double point2[2] ); f RESULT = AST_OFFSET2( THIS, POINT1, ANGLE, OFFSET, POINT2, STATUS ) * Class Membership: * Frame method. * Description: c This function finds the Frame coordinate values of a point which f This routine finds the Frame coordinate values of a point which * is offset a specified distance along the geodesic curve at a * given angle from a specified starting point. It can only be * used with 2-dimensional Frames. * * For example, in a basic Frame, this offset will be along the * straight line joining two points. For a more specialised Frame * describing a sky coordinate system, however, it would be along * the great circle passing through two sky positions. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c point1 f POINT1( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of the * point marking the start of the geodesic curve. c angle f ANGLE = DOUBLE PRECISION (Given) * The angle (in radians) from the positive direction of the second * axis, to the direction of the required position, as seen from * the starting position. Positive rotation is in the sense of * rotation from the positive direction of axis 2 to the positive * direction of axis 1. c offset f OFFSET = DOUBLE PRECISION * The required offset from the first point along the geodesic * curve. If this is positive, it will be in the direction of the * given angle. If it is negative, it will be in the opposite * direction. c point2 f POINT2( * ) = DOUBLE PRECISION (Returned) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * in which the coordinates of the required point will be returned. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astOffset2 f AST_OFFSET2 = DOUBLE PRECISION * The direction of the geodesic curve at the end point. That is, the * angle (in radians) between the positive direction of the second * axis and the continuation of the geodesic curve at the requested * end point. Positive rotation is in the sense of rotation from * the positive direction of axis 2 to the positive direction of axis * 1. * Notes: c - The geodesic curve used by this function is the path of f - The geodesic curve used by this routine is the path of * shortest distance between two points, as defined by the c astDistance function. f AST_DISTANCE function. * - An error will be reported if the Frame is not 2-dimensional. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. *-- */ /* Local Variables: */ int naxes; /* Number of Frame axes */ double result; /* Returned value */ /* Check the global error status. */ result = AST__BAD; if ( !astOK ) return result; /* Initialize bad values. */ point2[ 0 ] = AST__BAD; point2[ 1 ] = AST__BAD; /* Determine the number of Frame axes. */ naxes = astGetNaxes( this ); /* Report an error if the Frame is not 2 dimensional. */ if( naxes != 2 && astOK ) { astError( AST__NAXIN, "astOffset2(%s): Invalid number of Frame axes (%d)." " astOffset2 can only be used with 2 dimensonal Frames.", status, astGetClass( this ), naxes ); } /* Check the supplied values. */ if ( astOK && point1[ 0 ] != AST__BAD && point1[ 1 ] != AST__BAD && angle != AST__BAD && offset != AST__BAD ) { /* Store the results. */ point2[ 0 ] = point1[ 0 ] + sin( angle )*offset; point2[ 1 ] = point1[ 1 ] + cos( angle )*offset; /* The position angle of the curve does not vary in cartesian coordinates */ result = angle; } /* Return the result. */ return result; } static void Offset( AstFrame *this, const double point1[], const double point2[], double offset, double point3[], int *status ) { /* *++ * Name: c astOffset f AST_OFFSET * Purpose: * Calculate an offset along a geodesic curve. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astOffset( AstFrame *this, c const double point1[], const double point2[], c double offset, double point3[] ) f CALL AST_OFFSET( THIS, POINT1, POINT2, OFFSET, POINT3, STATUS ) * Class Membership: * Frame method. * Description: c This function finds the Frame coordinate values of a point which f This routine finds the Frame coordinate values of a point which * is offset a specified distance along the geodesic curve between * two other points. * * For example, in a basic Frame, this offset will be along the * straight line joining two points. For a more specialised Frame * describing a sky coordinate system, however, it would be along * the great circle passing through two sky positions. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c point1 f POINT1( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This should contain the coordinates of the * point marking the start of the geodesic curve. c point2 f POINT2( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis. * This should contain the coordinates of the point marking the * end of the geodesic curve. c offset f OFFSET = DOUBLE PRECISION * The required offset from the first point along the geodesic * curve. If this is positive, it will be towards the second * point. If it is negative, it will be in the opposite * direction. This offset need not imply a position lying * between the two points given, as the curve will be * extrapolated if necessary. c point3 f POINT3( * ) = DOUBLE PRECISION (Returned) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * in which the coordinates of the required point will be returned. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - The geodesic curve used by this function is the path of f - The geodesic curve used by this routine is the path of * shortest distance between two points, as defined by the c astDistance function. f AST_DISTANCE function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value. * - "Bad" coordinate values will also be returned if the two * points supplied are coincident (or otherwise fail to uniquely * specify a geodesic curve) but the requested offset is non-zero. *-- */ /* Local Variables: */ double delta; /* Displacement along axis */ double dist; /* Distance between points */ double fract; /* Fraction of distance required */ int axis; /* Loop counter for axes */ int naxes; /* Number of Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Determine the number of Frame axes. */ naxes = astGetNaxes( this ); if ( astOK ) { /* Loop to determine the Cartesian distance between points 1 and 2. */ dist = 0.0; for ( axis = 0; axis < naxes; axis++ ) { /* If any of the coordinates supplied is bad, set the distance to be bad and quit looping. */ if ( ( point1[ axis ] == AST__BAD ) || ( point2[ axis ] == AST__BAD ) ) { dist = AST__BAD; break; /* Otherwise, accumulate the sum of squared displacements along each axis. */ } else { delta = point1[ axis ] - point2[ axis ]; dist += ( delta * delta ); } } /* Take the square root to find the distance (if valid). */ if ( dist != AST__BAD ) dist = sqrt( dist ); /* If the distance between the points cannot be found, or the distance is zero but the required offset is non-zero, then set the result coordinates to be bad. */ if ( ( dist == AST__BAD ) || ( ( dist == 0.0 ) && ( offset != 0.0 ) ) ) { for ( axis = 0; axis < naxes; axis++ ) { point3[ axis ] = AST__BAD; } /* Otherwise, calculate what fraction of the distance between the points we need to move, and apply this fraction of the displacement along each axis. */ } else { fract = ( dist == 0.0 ) ? 0.0 : offset / dist; for ( axis = 0; axis < naxes; axis++ ) { point3[ axis ] = point1[ axis ] + fract * ( point2[ axis ] - point1[ axis ] ); } } } } static void Overlay( AstFrame *template, const int *template_axes, AstFrame *result, int *status ) { /* *+ * Name: * astOverlay * Purpose: * Overlay the attributes of a template Frame on to another Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astOverlay( AstFrame *template, const int *template_axes, * AstFrame *result ) * Class Membership: * Frame method. * Description: * This function overlays attributes of one Frame (the "template") on to * another Frame, so as to over-ride selected attributes of that second * Frame. Normally only those attributes which have been specifically set * in the template will be transferred. This implements a form of * defaulting, in which a Frame acquires attributes from the template, but * retains its original attributes (as the default) if new values have not * previously been explicitly set in the template. * Parameters: * template * Pointer to the template Frame, for which values should have been * explicitly set for any attribute which is to be transferred. * template_axes * Pointer to an array of int, with one element for each axis of the * "result" Frame (see below). For each axis in the result frame, the * corresponding element of this array should contain the (zero-based) * index of the template axis to which it corresponds. This array is used * to establish from which template axis any axis-dependent attributes * should be obtained. * * If any axis in the result Frame is not associated with a template * axis, the corresponding element of this array should be set to -1. * * If a NULL pointer is supplied, the template and result axis * indicies are assumed to be identical. * result * Pointer to the Frame which is to receive the new attribute values. *- */ /* Local Variables: */ AstAxis *result_ax; /* Pointer to result Axis object */ AstAxis *template_ax; /* Pointer to template Axis object */ AstSystemType sys; /* System value */ int result_axis; /* Loop counter for result Frame axes */ int result_naxes; /* Number of result Frame axes */ int template_axis; /* Index of template Frame axis */ int template_naxes; /* Number of template Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Define a macro that tests whether an attribute is set in the template and, if so, transfers its value to the target. */ #define OVERLAY(attribute) \ if ( astTest##attribute( template ) ) { \ astSet##attribute( result, astGet##attribute( template ) ); \ } /* Use the macro to transfer each Frame attribute in turn. */ OVERLAY(Dut1); OVERLAY(Digits); OVERLAY(Domain); OVERLAY(Epoch); OVERLAY(Title); OVERLAY(ObsLat) OVERLAY(ObsLon) OVERLAY(ObsAlt) /* Transfer the ActiveUnit flag. */ astSetActiveUnit( result, astGetActiveUnit( template ) ); /* Only overlay the System and AlignSystem attribute if the values are valid for the result class. */ if( astTestSystem( template ) ) { sys = astGetSystem( template ); if( astValidateSystem( result, sys, "astOverlay" ) ) { astSetSystem( result, sys ); } } if( astTestAlignSystem( template ) ) { sys = astGetAlignSystem( template ); if( astValidateSystem( result, sys, "astOverlay" ) ) { astSetAlignSystem( result, sys ); } } /* Now transfer attributes associated with individual axes. Obtain the number of axes in the template and result Frames. */ template_naxes = astGetNaxes( template ); result_naxes = astGetNaxes( result ); if ( astOK ) { /* Loop through all the axes in the result Frame and determine to which template axis each one corresponds. Check that the resulting axis index is valid. If not, then the axis will not receive new attributes. */ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { template_axis = template_axes ? template_axes[ result_axis ] : result_axis; if ( ( template_axis >= 0 ) && ( template_axis < template_naxes ) ) { /* Obtain pointers to the relevant Axis objects of each Frame and use the astAxisOverlay method of the template Axis to overlay attributes on to the result Axis. Annul the Axis pointers afterwards. */ template_ax = astGetAxis( template, template_axis ); result_ax = astGetAxis( result, result_axis ); astAxisOverlay( template_ax, result_ax ); template_ax = astAnnul( template_ax ); result_ax = astAnnul( result_ax ); /* Quit looping if an error occurs. */ if ( !astOK ) break; } } } /* Undefine macros local to this function. */ #undef OVERLAY } static void PermAxes( AstFrame *this, const int perm[], int *status ) { /* *+ * Name: * astPermAxes * Purpose: * Permute the order of a Frame's axes. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astPermAxes( AstFrame *this, const int perm[] ) * Class Membership: * Frame method. * Description: * This function permutes the order in which a Frame's axes occur. * Parameters: * this * Pointer to the Frame. * perm * An array of int (with one element for each axis of the Frame) * which lists the axes in their new order. Each element of this * array should be a (zero-based) axis index identifying the * axes according to their old (un-permuted) order. * Notes: * - Only genuine permutations of the axis order are permitted, so * each axis must be referenced exactly once in the "perm" array. * - If more than one axis permutation is applied to a Frame, the * effects are cumulative. *- * Implementation Notes: * - This function implements the basic astPermAxes method which is * available via the protected interface to the Frame class. A * public interface to this method is provided by the * astPermAxesId_ function. */ /* Local Variables: */ int *old; /* Pointer to copy of old permutation array */ int axis; /* Loop counter for Frame axes */ int naxes; /* Number of Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Validate the permutation array, to check that it describes a genuine permutation. */ astCheckPerm( this, perm, "astPermAxes" ); /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); /* Allocate memory and use it to store a copy of the old permutation array for the Frame. */ old = astStore( NULL, this->perm, sizeof( int ) * (size_t) naxes ); /* Apply the new axis permutation cumulatively to the old one and store the result in the Frame. */ if ( astOK ) { for ( axis = 0; axis < naxes; axis++ ) { this->perm[ axis ] = old[ perm[ axis ] ]; } } /* Free the temporary copy of the old array. */ old = astFree( old ); } static AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[], AstMapping **map, int *status ) { /* *+ * Name: * astPickAxes * Purpose: * Create a new Frame by picking axes from an existing one. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[], * AstMapping **map ) * Class Membership: * Frame method. * Description: * This function creates a new Frame whose axes are copies of axes * picked from an existing Frame. Other Frame attributes are also * copied to the new Frame. Zero or more of the original axes may * be picked in any order, but each can be used only * once. Additional axes (with default characteristics) may be * included in the new Frame if required. * * Optionally, a Mapping that converts between the original Frame's * axes and those of the new Frame may also be returned. * Parameters: * this * Pointer to the original Frame. * naxes * The number of axes required in the new Frame. * axes * Pointer to an array of int with naxes elements. This should * contain (zero based) axis indices specifying the axes which * are to be included in the new Frame, in the order * required. Each axis index may occur only once. * * If additional (default) axes are also to be included, the * corresponding elements of this array should be set to -1. * map * Address of a location to receive a pointer to a new * Mapping. This will be a PermMap (or a UnitMap as a special * case) that describes the axis permutation that has taken * place between the original and new Frames. The forward * transformation will convert from the original Frame's axes to * the new one's, and vice versa. * * If this Mapping is not required, a NULL value may be supplied * for this parameter. * Returned Value: * Pointer to the new Frame. * Notes: * - The class of object returned may differ from that of the * original Frame, depending on which axes are selected. For * example, if a single axis is picked from a SkyFrame (which * always has two axes), the resulting Frame cannot be a valid * SkyFrame, so will revert to the parent class (Frame) instead. * - The new Frame contains a deep copy of all the data selected * from the original Frame. Modifying the new Frame will therefore * not affect the original one. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic astPickAxes method * available via the protected interface to the Frame class. The * public interface to this method is provided by the * astPickAxesId_ function. */ /* Local Variables: */ AstFrame *frame; /* Pointer to Frame to be returned */ AstMapping *mapping; /* Pointer to Mapping to be returned */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the returned pointers. */ frame = NULL; if ( map ) *map = NULL; /* Check that a valid set of axes is being selected . */ astValidateAxisSelection( this, naxes, axes, "astPickAxes" ); /* Create the required new Frame by selecting the axes. This also returns a Mapping which transforms between the original Frame and the new one. */ astSubFrame( this, NULL, naxes, axes, NULL, &mapping, &frame ); if ( astOK ) { /* Return the Mapping pointer if required. */ if ( map ) { *map = mapping; /* Otherwise annul the Mapping. If an error occurs, also annul the Frame. */ } else { mapping = astAnnul( mapping ); if ( !astOK ) frame = astAnnul( frame ); } } /* Return the pointer to the new Frame. */ return frame; } static void PrimaryFrame( AstFrame *this, int axis1, AstFrame **frame, int *axis2, int *status ) { /* *+ * Name: * astPrimaryFrame * Purpose: * Uniquely identify a primary Frame and one of its axes. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astPrimaryFrame( AstFrame *this, int axis1, AstFrame **frame, * int *axis2 ) * Class Membership: * Frame method. * Description: * This function returns information about the underlying (primary) Frame * corresponding to a specified axis, when given what may be a compound * Frame composed of more than one simpler one. * Parameters: * this * Pointer to the Frame. * axis1 * An axis index (zero-based) identifying the Frame axis for which * information is required. * frame * Address of a location to receive a pointer to the underlying (primary) * frame to which the requested axis belongs (i.e. this will not be a * compound Frame). * axis2 * Pointer to an int which is to receive the (zero-based) axis * index within "frame" which identifies the axis being referred * to, using the axis order that applied when the primary Frame * was originally constructed (i.e. this function undoes all * subsequent axis pemutations and the effects of combining * Frames, in order to reveal the original underlying axis * order). * Notes: * - This protected method is provided so that class implementations can * distinguish the axes of frames from one another (e.g. can distinguish * a longitude axis as being different from a latitide axis) even after * their order has been permuted and they have been combined with axes from * other Frames. * - The reference count of the primary Frame will be incremented by one to * reflect the new pointer returned. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise the returned values. */ *frame = NULL; *axis2 = 0; /* Validate and permute the axis index supplied. */ axis1 = astValidateAxis( this, axis1, 1, "astPrimaryFrame" ); /* Since "this" is a primary Frame (i.e. is not compound), simply clone a pointer to it. */ if ( astOK ) *frame = astClone( this ); /* Return the permuted axis index, which refers to the original axis order. */ if ( astOK ) *axis2 = axis1; } double astReadDateTime_( const char *value, int *status ) { /* *+ * Name: * astReadDateTime * Purpose: * Read a date/time string. * Type: * Private function. * Synopsis: * #include "frame.h" * double astReadDateTime( const char *value ) * Class Membership: * Frame member function. * Description: * This function reads a date/time string in a variety of formats and * returns the resulting time as a Modified Julian Date. If the string * cannot be interpreted as a date/time or contains invalid values, an * error is reported. * Parameters: * value * Pointer to a null terminated string containing the value to be read. * Returned Value: * The time as a Modified Julian date. * Date/Time Formats: * The date/time formats supported by this function are listed below. These * are interpreted in a case-insensitive manner and the function is * generally flexible about the presence of additional white space and the * use of alternative field delimiters. * * Besselian Epoch * Expressed in decimal years, with or without decimal places * ("B1950" or "B1976.13", for example). * Julian Epoch * Expressed in decimal years, with or without decimal places * ("J2000" or "J2100.9", for example). * Year * Decimal years, with or without decimal places ("1996.8" for example). * Such values are interpreted as a Besselian epoch (see above) if less * than 1984.0 and as a Julian epoch otherwise. * Julian Date * With or without decimal places ("JD 2454321.9" for example). * Modified Julian Date * With or without decimal places ("MJD 54321.4" for example). * Gregorian Calendar Date * With the month expressed as an integer or 3-character * abbreviation, and with optional decimal places to represent a * fraction of a day ("1996-10-2" or "1996-Oct-2.6" for * example). If no fractional part of a day is given, the time * refers to the start of the day (zero hours). * Gregorian Date and Time * Any calendar date (as above) but with a fraction of a day expressed * as hours, minutes and seconds ("1996-Oct-2 12:13:56.985" for example). * The date and time can be separated by a space or by a "T" (as used * by ISO8601). * Notes: * - The date/time value is interpreted as a calendar date and time, not * linked to any particular time system. Thus, interpretation of hours, * minutes and seconds is done in the obvious manner assuming 86400 seconds * in a day. No allowance for is made, for instance, for leap seconds or for * the varying length of a second in some time systems. * - A value of AST__BAD is returned if this function is invoked with the * global error status set or if it should fail for any reason. *- */ /* Local Vaiables: */ char cmonth[ 4 ]; /* Buffer for name of month */ char sep1[ 2 ]; /* Year/month separator string */ char sep2[ 2 ]; /* Month/day separator string */ char sep3[ 2 ]; /* Hour/minute separator string */ char sep4[ 2 ]; /* Minute/second separator string */ char *cc; /* Pointer to copy of remaining text */ const char *v; /* Pointer into value string */ const char *p; /* Pointer to date/time separator */ double day; /* Day number plus fraction of whole day */ double epoch; /* Epoch stored as decimal years */ double hms; /* Hours, min & sec as fraction of a day */ double jd; /* Julian Date */ double mjd; /* Modified Julian Date */ double result; /* Result to be returned */ double sec; /* Seconds and fractions of a second */ int hour; /* Number of hours */ int iday; /* Number of whole days */ int l; /* Length of string remaining */ int len; /* Length of string */ int match; /* Date/time string has correct form? */ int minute; /* Number of minutes */ int month; /* Number of months */ int nc; /* Number of characters read from string */ int stat; /* Status return from SLALIB functions */ int year; /* Number of years */ /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Initialise. */ result = AST__BAD; /* Obtain the length of the input string. */ len = (int) strlen( value ); /* Attempt to read the string using each recognised format in turn. */ /* Besselian epoch in decimal years (e.g. "B1950.0"). */ /* ================================================== */ if ( nc = 0, ( 1 == astSscanf( value, " %*1[Bb] %lf %n", &epoch, &nc ) ) && ( nc >= len ) ) { /* Convert to Modified Julian Date. */ result = palEpb2d( epoch ); /* Julian epoch in decimal years (e.g. "J2000.0"). */ /* =============================================== */ } else if ( nc = 0, ( 1 == astSscanf( value, " %*1[Jj] %lf %n", &epoch, &nc ) ) && ( nc >= len ) ) { /* Convert to Modified Julian Date. */ result = palEpj2d( epoch ); /* Decimal years (e.g. "1976.2"). */ /* ============================== */ } else if ( nc = 0, ( 1 == astSscanf( value, " %lf %n", &epoch, &nc ) ) && ( nc >= len ) ) { /* Convert to Modified Julian Date, treating the epoch as Julian or Besselian depending on whether it is 1984.0 or later. */ result = ( epoch < 1984.0 ) ? palEpb2d( epoch ) : palEpj2d( epoch ); /* Modified Julian Date (e.g. "MJD 54321.0"). */ /* ============================================ */ } else if ( nc = 0, ( 1 == astSscanf( value, " %*1[Mm] %*1[Jj] %*1[Dd] %lf %n", &mjd, &nc ) ) && ( nc >= len ) ) { /* Use the result directly. */ result = mjd; /* Julian Date (e.g. "JD 2454321.5"). */ /* ==================================== */ } else if ( nc = 0, ( 1 == astSscanf( value, " %*1[Jj] %*1[Dd] %lf %n", &jd, &nc ) ) && ( nc >= len ) ) { /* Convert to Modified Julian Date. */ result = jd - 2400000.5; /* Gregorian calendar date (e.g. "1996-10-2" or "1996-Oct-2"). */ /* =========================================================== */ /* This format also allows day fractions expressed as decimal days, e.g: "1996-Oct-2.5001" or as hours, minutes and seconds, e.g: "1996-Oct-2 12:14:30.52" Various alternative field delimiters are also allowed. */ } else { /* Note that the method used to parse this format relies heavily on conditional execution controlled by "&&" and "||" operators. Initialise the variables used. */ v = value; l = len; *cmonth = '\0'; year = month = iday = hour = minute = 0; day = sec = 0.0; /* Identify the year and month. */ /* ---------------------------- */ /* Try to match an initial " 1996 - 10 -" or " 1996 10 " or similar. */ match = ( nc = 0, ( 4 == astSscanf( v, " %d %1[:/-] %2d %1[:/-]%n", &year, sep1, &month, sep2, &nc ) ) ); match = match || ( nc = 0, ( 4 == astSscanf( v, " %d%1[ ] %2d%1[ ]%n", &year, sep1, &month, sep2, &nc ) ) ); /* If that failed, allow " 1996 - Oct -" or " 1996 Oct " or similar. */ match = match || ( nc = 0, ( 4 == astSscanf( v, " %d %1[:/-] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz] %1[:/-]%n", &year, sep1, cmonth, sep2, &nc ) ) ); match = match || ( nc = 0, ( 4 == astSscanf( v, " %d%1[ ] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz]%1[ ]%n", &year, sep1, cmonth, sep2, &nc ) ) ); /* Alternative field separators are permitted above, but ensure that they are both the same. */ match = match && ( *sep1 == *sep2 ); /* Identify the day and fraction of day. */ /*-------------------------------------- */ /* If the above matched correctly, modify the string pointer "v" to the next character to be interpreted and decrement the remaining string length. */ if ( match ) { v += nc; l -= nc; /* ISO8601 format uses the litter T as a delimiter between the date and time. If there is a T in the remaining string, take a copy and change the T to a space. */ p = strchr( v, 'T' ); if( p ) { cc = astStore( NULL, v, l + 1 ); cc[ p - v ] = ' '; v = cc; } else { cc = NULL; } /* We now try to match the following characters but without reading any values. This is done to ensure the string has the correct form (e.g. exclude "-" signs and exponents in numbers, which are otherwise hard to detect). */ /* Try to match " 12.3456 " or similar. */ match = ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789].%*[0123456789] %n", &nc ) ) && ( nc == l ) ); /* If that failed, then try to match " 12. " or similar. */ match = match || ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) ) && ( nc == l ) ); /* If that also failed, then try to match just " 12 " or similar. */ match = match || ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) ) && ( nc == l ) ); /* If any of the above patterns matched, now read the data (the day number) as a double value. */ if ( match ) { match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &day, &nc ) ) && ( nc == l ) ); /* If none of the above matched, then look to see if the day fraction has been given in hours, minutes and seconds by trying to match " 12 03 : 45 :" or " 12 13 45 " or similar. */ } else { match = ( nc = 0, ( 5 == astSscanf( v, " %2d%*1[ ] %2d %1[:/-] %2d %1[:/-]%n", &iday, &hour, sep3, &minute, sep4, &nc ) ) ); match = match || ( nc = 0, ( 5 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d%1[ ]%n", &iday, &hour, sep3, &minute, sep4, &nc ) ) ); /* Alternative field separators are permitted above, but ensure that they are both the same. */ match = match && ( *sep3 == *sep4 ); /* If the day number was read as an integer, convert it to double. */ if ( match ) day = (double) iday; /* If no match, see if we can get a match without a trailing seconds field. */ if( !match ) { match = ( nc = 0, ( 4 == astSscanf( v, " %2d%*1[ ] %2d %1[:/-] %2d %n", &iday, &hour, sep3, &minute, &nc ) && ( nc == l ) ) ); match = match || ( nc = 0, ( 4 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d %n", &iday, &hour, sep3, &minute, &nc ) && ( nc == l ) ) ); /* If the day number was read as an integer, convert it to double. */ if ( match ) day = (double) iday; /* Otherwise, identify the seconds field. */ /* -------------------------------------- */ /* If hours and minutes fields have been matched, now look for the final seconds (and fractions of seconds) field. This is similar to the day/fraction field (see earlier) in that we first check that it has the correct form before reading its value. */ /* Adjust the string pointer and remaining string length. */ } else { v += nc; l -= nc; /* Try to match " 12.3456 " or similar. */ match = ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789].%*[0123456789] %n", &nc ) ) && ( nc == l ) ); /* If that failed, then try to match " 12. " or similar. */ match = match || ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) ) && ( nc == l ) ); /* If that also failed, then try to match just " 12 " or similar. */ match = match || ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) ) && ( nc == l ) ); /* If any of the above patterns matched, now read the data (the number of seconds) as a double value. */ if ( match ) { match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &sec, &nc ) ) && ( nc == l ) ); } } } /* Free resources */ if( cc ) cc = astFree( cc ); } /* Interpret the values that were read. */ /* ------------------------------------ */ /* We execute this if all of the above text matching was successful, transferred the required number of data values, and consumed the entire input string. */ if ( match ) { /* See if the month was given as a character string (e.g. "Oct") instead of a number. If so, define local variables for use in converting it. */ if ( *cmonth ) { char lcmonth[ 4 ]; /* Lower case copy of month string */ const char *ptr; /* Pointer result from look up */ const char *table = /* Month look up table */ "jan feb mar apr may jun jul aug sep oct nov dec"; int i; /* Loop counter for characters */ /* Convert the month string to lower case. */ for ( i = 0; cmonth[ i ]; i++ ) { lcmonth[ i ] = tolower( cmonth[ i ] ); } lcmonth[ i ] = '\0'; /* Look the month up in the table of months and generate the required month number. */ if ( ( ptr = strstr( table, lcmonth ) ) ) { month = 1 + ( ptr - table ) / 4; /* If the lookup failed, report an error. */ } else { astError( AST__DTERR, "Month value \"%s\" is invalid.", status, cmonth ); } } /* If OK, extract the integral day number and convert years, months and days to a Modified Julian Date. */ if ( astOK ) { iday = (int) day; palCaldj( year, month, iday, &mjd, &stat ); /* Examine the return status from the conversion and report an appropriate error if necessary. */ switch ( stat ) { case 1: astError( AST__DTERR, "Year value (%d) is invalid.", status, year ); break; case 2: astError( AST__DTERR, "Month value (%d) is invalid.", status, month ); break; case 3: astError( AST__DTERR, "Day value (%.*g) is invalid.", status, DBL_DIG, day ); break; /* If conversion to MJD was successful, add any fractional part of a day to the result. */ default: mjd += ( day - (double) iday ); /* Convert hours, minutes and seconds to a fraction of a day (this will give zero if none of these quantities was supplied). */ palDtf2d( hour, minute, sec, &hms, &stat ); /* Examine the return status from the conversion and report an appropriate error if necessary. */ switch ( stat ) { case 1: astError( AST__DTERR, "Hour value (%d) is invalid.", status, hour ); break; case 2: astError( AST__DTERR, "Minute value (%d) is invalid.", status, minute ); break; case 3: astError( AST__DTERR, "Seconds value (%.*g) is invalid.", status, DBL_DIG, sec ); break; /* Add the fraction of a day derived from hours, minutes and seconds fields to the result. */ default: mjd += hms; break; } break; } /* Return the result, if no error occurred. */ if ( astOK ) result = mjd; } /* If none of the supported date/time formats matched, then report an error. */ } else { astError( AST__DTERR, "Date/time does not have the correct form." , status); } } /* Return the result. */ return result; } static void ReportPoints( AstMapping *this_mapping, int forward, AstPointSet *in_points, AstPointSet *out_points, int *status ) { /* * Name: * ReportPoints * Purpose: * Report the effect of transforming a set of points using a Frame. * Type: * Private function. * Synopsis: * #include "mapping.h" * void ReportPoints( AstMapping *this, int forward, * AstPointSet *in_points, AstPointSet *out_points, int *status ) * Class Membership: * Frame member function (over-rides the protected astReportPoints * method inherited from the Mapping class). * Description: * This function reports the coordinates of a set of points before * and after being transformed by a Frame, by writing them to * standard output. * Parameters: * this * Pointer to the Frame. * forward * A non-zero value indicates that the Frame's forward * coordinate transformation has been applied, while a zero * value indicates the inverse transformation. * in_points * Pointer to a PointSet which is associated with the * coordinates of a set of points before the Frame was applied. * out_points * Pointer to a PointSet which is associated with the * coordinates of the same set of points after the Frame has * been applied. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *this; /* Pointer to the Frame structure */ double **ptr_in; /* Pointer to array of input data pointers */ double **ptr_out; /* Pointer to array of output data pointers */ int coord; /* Loop counter for coordinates */ int ncoord_in; /* Number of input coordinates per point */ int ncoord_out; /* Number of output coordinates per point */ int npoint; /* Number of points to report */ int npoint_in; /* Number of input points */ int npoint_out; /* Number of output points */ int point; /* Loop counter for points */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_mapping; /* Obtain the numbers of points and coordinates associated with each PointSet. */ npoint_in = astGetNpoint( in_points ); npoint_out = astGetNpoint( out_points ); ncoord_in = astGetNcoord( in_points ); ncoord_out = astGetNcoord( out_points ); /* Obtain the pointers that give access to the coordinate data associated with each PointSet. */ ptr_in = astGetPoints( in_points ); ptr_out = astGetPoints( out_points ); /* In the event that both PointSets don't contain equal numbers of points (this shouldn't actually happen), simply use the minimum number. */ npoint = ( npoint_in < npoint_out ) ? npoint_in : npoint_out; /* Loop to report the effect of the transformation on each point in turn. */ for ( point = 0; point < npoint; point++ ) { /* Report the input coordinates (in parentheses and separated by commas). Format each value for display using the Frame's astFormat method. */ printf( "(" ); for ( coord = 0; coord < ncoord_in; coord++ ) { printf( "%s%s", coord ? ", " : "", astFormat( this, coord, ptr_in[ coord ][ point ] ) ); } /* Similarly report the output coordinates. */ printf( ") --> (" ); for ( coord = 0; coord < ncoord_out; coord++ ) { printf( "%s%s", coord ? ", " : "", astFormat( this, coord, ptr_out[ coord ][ point ] ) ); } printf( ")\n" ); } } static void Resolve( AstFrame *this, const double point1[], const double point2[], const double point3[], double point4[], double *d1, double *d2, int *status ){ /* *++ * Name: c astResolve f AST_RESOLVE * Purpose: * Resolve a vector into two orthogonal components * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astResolve( AstFrame *this, const double point1[], c const double point2[], const double point3[], c double point4[], double *d1, double *d2 ); f CALL AST_RESOLVE( THIS, POINT1, POINT2, POINT3, POINT4, D1, D2, f STATUS ) * Class Membership: * Frame method. * Description: c This function resolves a vector into two perpendicular components. f This routine resolves a vector into two perpendicular components. * The vector from point 1 to point 2 is used as the basis vector. * The vector from point 1 to point 3 is resolved into components * parallel and perpendicular to this basis vector. The lengths of the * two components are returned, together with the position of closest * aproach of the basis vector to point 3. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c point1 f POINT1( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vector to be resolved. c point2 f POINT2( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. c point3 f POINT3( * ) = DOUBLE PRECISION (Given) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * (Naxes attribute). This marks the end of the vector to be * resolved. c point4 f POINT4( * ) = DOUBLE PRECISION (Returned) c An array of double, with one element for each Frame axis f An array with one element for each Frame axis * in which the coordinates of the point of closest approach of the * basis vector to point 3 will be returned. c d1 f D1 = DOUBLE PRECISION (Returned) c The address of a location at which to return the distance from f The distance from * point 1 to point 4 (that is, the length of the component parallel * to the basis vector). Positive values are in the same sense as * movement from point 1 to point 2. c d2 f D2 = DOUBLE PRECISION (Returned) c The address of a location at which to return the distance from f The distance from * point 4 to point 3 (that is, the length of the component * perpendicular to the basis vector). The value is always positive. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - Each vector used in this function is the path of f - Each vector used in this routine is the path of * shortest distance between two points, as defined by the c astDistance function. f AST_DISTANCE function. * - This function will return "bad" coordinate values (AST__BAD) * if any of the input coordinates has this value, or if the required * output values are undefined. *-- */ /* Local Variables: */ double bv; /* Length of basis vector */ double c; /* Component length */ double dp; /* Dot product */ int axis; /* Loop counter for axes */ int naxes; /* Number of Frame axes */ int ok; /* OK to proceed? */ /* Check the global error status. */ *d1 = AST__BAD; *d2 = AST__BAD; if ( !astOK ) return; /* Determine the number of Frame axes. */ naxes = astGetNaxes( this ); /* Initialize bad values, and check if the supplied vectors are good. */ ok = 1; for( axis = 0; axis < naxes; axis++ ){ point4[ axis ] = AST__BAD; if( point1[ axis ] == AST__BAD || point2[ axis ] == AST__BAD || point3[ axis ] == AST__BAD ) ok = 0; } /* Check the supplied values. */ if ( ok ) { /* Find the dot product of the basis vector with the vector joining point 1 and point 3. At the same time form the squared length of the basis vector. */ dp = 0.0; bv = 0.0; for( axis = 0; axis < naxes; axis++ ){ c = point2[ axis ] - point1[ axis ]; dp += c * ( point3[ axis ] - point1[ axis ] ); bv += c * c; } /* Check the basis vector does not have zero length, and convert the squared length into a length. */ if( bv > 0.0 ) { bv = sqrt( bv ); /* The dot product is the required distance d1 multiplied by the length of the basis vector. Form the distance d1. */ *d1 = dp/bv; /* Offset away from point 1 towards point 2 by a distance of d1. */ for( axis = 0; axis < naxes; axis++ ){ point4[ axis ] = point1[ axis ] + (*d1/bv)*( point2[ axis ] - point1[ axis ] ); } /* Finally, form the required length d2. */ *d2 = 0.0; for( axis = 0; axis < naxes; axis++ ){ c = ( point3[ axis ] - point4[ axis ] ); *d2 += c*c; } *d2 = sqrt( *d2 ); } } return; } static AstPointSet *ResolvePoints( AstFrame *this, const double point1[], const double point2[], AstPointSet *in, AstPointSet *out, int *status ) { /* *+ * Name: * astResolvePoints * Purpose: * Resolve a set of vectors into orthogonal components * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstPointSet *astResolvePoints( AstFrame *this, const double point1[], * const double point2[], AstPointSet *in, * AstPointSet *out ) * Class Membership: * Frame method. * Description: * This function takes a Frame and a set of vectors encapsulated * in a PointSet, and resolves each one into two orthogonal components, * returning these two components in another PointSet. * * This is exactly the same as the public astResolve method, except * that this method allows many vectors to be processed in a single call, * thus reducing the computational cost of overheads of many * individual calls to astResolve. * Parameters: * this * Pointer to the Frame. * point1 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the start of the basis vector, * and of the vectors to be resolved. * point2 * An array of double, with one element for each Frame axis * (Naxes attribute). This marks the end of the basis vector. * in * Pointer to the PointSet holding the ends of the vectors to be * resolved. * out * Pointer to a PointSet which will hold the length of the two * resolved components. A NULL value may also be given, in which * case a new PointSet will be created by this function. * Returned Value: * Pointer to the output (possibly new) PointSet. The first axis will * hold the lengths of the vector components parallel to the basis vector. * These values will be signed (positive values are in the same sense as * movement from point 1 to point 2. The second axis will hold the lengths * of the vector components perpendicular to the basis vector. These * values will be signed only if the Frame is 2-dimensional, in which * case a positive value indicates that rotation from the basis vector * to the tested vector is in the same sense as rotation from the first * to the second axis of the Frame. * Notes: * - The number of coordinate values per point in the input * PointSet must match the number of axes in the supplied Frame. * - If an output PointSet is supplied, it must have space for * sufficient number of points and 2 coordinate values per point. * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * - We assume flat geometry throughout this function. Other classes, * (e.g. SkyFrame) will override this method using more appropriate * geometry. *- */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ double **ptr_in; /* Pointers to input axis values */ double **ptr_out; /* Pointers to returned axis values */ double *basisv; /* Pointer to array holding basis vector */ double *d1; /* Pointer to next parallel component value */ double *d2; /* Pointer to next perpendicular component value */ double *ip; /* Pointer to next input axis value */ double bv; /* Length of basis vector */ double c; /* Constant value */ double d; /* Component length */ double dp; /* Dot product */ double x1; /* First axis of basis vector */ double x2; /* First axis of test vector */ double y1; /* Second axis of basis vector */ double y2; /* Second axis of test vector */ int axis; /* Loop counter for axes */ int ipoint; /* Index of next point */ int nax; /* Number of Frame axes */ int ncoord_in; /* Number of input PointSet coordinates */ int ncoord_out; /* Number of coordinates in output PointSet */ int npoint; /* Number of points to transform */ int npoint_out; /* Number of points in output PointSet */ int ok; /* OK to proceed? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain the number of axes in the Frame. */ nax = astGetNaxes( this ); /* Obtain the number of input vectors to resolve and the number of coordinate values per vector. */ npoint = astGetNpoint( in ); ncoord_in = astGetNcoord( in ); /* If OK, check that the number of input coordinates matches the number required by the Frame. Report an error if these numbers do not match. */ if ( astOK && ( ncoord_in != nax ) ) { astError( AST__NCPIN, "astResolvePoints(%s): Bad number of coordinate " "values (%d) in input %s.", status, astGetClass( this ), ncoord_in, astGetClass( in ) ); astError( AST__NCPIN, "The %s given requires %d coordinate value(s) for " "each input point.", status, astGetClass( this ), nax ); } /* If still OK, and a non-NULL pointer has been given for the output PointSet, then obtain the number of points and number of coordinates per point for this PointSet. */ if ( astOK && out ) { npoint_out = astGetNpoint( out ); ncoord_out = astGetNcoord( out ); /* Check that the dimensions of this PointSet are adequate to accommodate the output coordinate values and report an error if they are not. */ if ( astOK ) { if ( npoint_out < npoint ) { astError( AST__NOPTS, "astResolvePoints(%s): Too few points (%d) in " "output %s.", status, astGetClass( this ), npoint_out, astGetClass( out ) ); astError( AST__NOPTS, "The %s needs space to hold %d transformed " "point(s).", status, astGetClass( this ), npoint ); } else if ( ncoord_out < 2 ) { astError( AST__NOCTS, "astResolvePoints(%s): Too few coordinate " "values per point (%d) in output %s.", status, astGetClass( this ), ncoord_out, astGetClass( out ) ); astError( AST__NOCTS, "The %s supplied needs space to store 2 " "coordinate value(s) per transformed point.", status, astGetClass( this ) ); } } } /* If all the validation stages are passed successfully, and a NULL output pointer was given, then create a new PointSet to encapsulate the output coordinate data. */ if ( astOK ) { if ( !out ) { result = astPointSet( npoint, 2, "", status ); /* Otherwise, use the PointSet supplied. */ } else { result = out; } } /* Get pointers to the input and output axis values */ ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Store points to the first two axis arrays in the returned PointSet. */ d1 = ptr_out[ 0 ]; d2 = ptr_out[ 1 ]; /* Allocate work space. */ basisv = astMalloc( sizeof( double )*(size_t) nax ); /* If the Frame has only one axis, then the supplied basic vector is irrelevant - the returned perpendicular distances are always zero and the returned parallel distances are just the distances from point1 to each input point. */ if( nax < 2 && basisv ) { ip = ptr_in[ 0 ]; for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++, ip++ ) { *d1 = astAxDistance( this, 1, point1[0], *ip ); *d2 = 0.0; } /* Now deal with Frames which have 2 or more axes */ } else if( basisv ){ /* Check if the supplied positions defining the basis vector are good. Store the basis vector, and get its squared length. */ ok = 1; bv = 0.0; for( axis = 0; axis < nax; axis++ ){ if( point1[ axis ] == AST__BAD || point2[ axis ] == AST__BAD ) { ok = 0; break; } else { basisv[ axis ] = point2[ axis ] - point1[ axis ]; bv += basisv[ axis ]*basisv[ axis ]; } } /* Check the basis vector does not have zero length, and convert the squared length into a length. */ if( ok && bv > 0.0 ) { bv = sqrt( bv ); } else { ok = 0; } /* Store points to the first two axis arrays in the returned PointSet. */ d1 = ptr_out[ 0 ]; d2 = ptr_out[ 1 ]; /* Check supplied values can be used */ if( ok ) { /* Loop round each supplied vector. */ for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) { /* Find the dot product of the basis vector with the vector joining point 1 and the end of the current vector. */ ok = 1; dp = 0.0; for( axis = 0; axis < nax; axis++ ){ d = ptr_in[ axis ][ ipoint ] - point1[ axis ]; if( d != AST__BAD ) { dp += basisv[ axis ] * d; } else { ok = 0; break; } } /* If this input position is good... */ if( ok ) { /* The dot product is the required parallel component length multiplied by the length of the basis vector. Form the distance d1. */ *d1 = dp/bv; /* Offset away from point 1 towards point 2 by a distance of d1, and form the required length d2. */ c = *d1/bv; if( nax > 2 ) { *d2 = 0.0; for( axis = 0; axis < nax; axis++ ){ d = ptr_in[ axis ][ ipoint ] - ( point1[ axis ] + c*basisv[ axis ] ); *d2 += d*d; } *d2 = sqrt( *d2 ); /* If the Frame is 2 dimensional, we can give a sign the the perpendicular component. */ } else { x1 = c*basisv[ 0 ]; y1 = c*basisv[ 1 ]; x2 = ptr_in[ 0 ][ ipoint ] - ( point1[ 0 ] + x1 ); y2 = ptr_in[ 1 ][ ipoint ] - ( point1[ 1 ] + y1 ); *d2 = sqrt( x2*x2 + y2*y2 ); if( x1*y2 - x2*y1 < 0.0 ) *d2 = -(*d2); } /* If this input vector is bad, put bad values in the output */ } else { *d1 = AST__BAD; *d2 = AST__BAD; } } /* If supplied values cannot be used, fill the returned PointSet with bad values */ } else { for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) { *d1 = AST__BAD; *d2 = AST__BAD; } } } /* Free resources */ basisv = astFree( basisv ); /* Annul the returned PointSet if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static void SetActiveUnit( AstFrame *this, int value, int *status ){ /* *++ * Name: c astSetActiveUnit f AST_SETACTIVEUNIT * Purpose: * Specify how the Unit attribute should be used. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astSetActiveUnit( AstFrame *this, int value ) f CALL AST_SETACTIVEUNIT( THIS, VALUE, STATUS ) * Class Membership: * Frame method. * Description: c This function f This routine * sets the current value of the ActiveUnit flag for a Frame, which * controls how the Frame behaves when it is used (by c astFindFrame or astConvert) f AST_FINDFRAME or AST_CONVERT) * to match another Frame. If the ActiveUnit flag is set in both * template and target Frames then the returned Mapping takes into account * any differences in axis units. The default value for simple Frames is * zero, which preserves the behaviour of versions of AST prior to * version 2.0. * * If the ActiveUnit flag of either Frame is c zero, f .FALSE., * then the Mapping will ignore any difference in the Unit attributes of * corresponding template and target axes. In this mode, the Unit * attributes are purely descriptive commentary for the benefit of * human readers and do not influence the Mappings between Frames. * This is the behaviour which all Frames had in older version of AST, * prior to the introduction of this attribute. * * If the ActiveUnit flag of both Frames is c non-zero, f .TRUE., * then the Mapping from template to target will take account of any * difference in the axis Unit attributes, where-ever possible. For * instance, if corresponding target and template axes have Unit strings of * "km" and "m", then the FrameSet class will use a ZoomMap to connect * them which introduces a scaling of 1000. If no Mapping can be found * between the corresponding units string, then an error is reported. * In this mode, it is assumed that values of the Unit attribute conform * to the syntax for units strings described in the FITS WCS Paper I * "Representations of world coordinates in FITS" (Greisen & Calabretta). * Particularly, any of the named unit symbols, functions, operators or * standard multiplier prefixes listed within that paper can be used within * a units string. A units string may contain symbols for unit which are * not listed in the FITS paper, but transformation to any other units * will then not be possible (except to units which depend only on the * same unknown units - thus "flops" can be transformed to "Mflops" * even though "flops" is not a standard FITS unit symbol). * * A range of common non-standard variations of unit names and multiplier * prefixes are also allowed, such as adding an "s" to the end of Angstrom, * using a lower case "a" at the start of "angstrom", "micron" instead of * "um", "sec" instead of "s", etc. * c If the ActiveUnit flag is non-zero, setting a new Unit value for an f If the ActiveUnit flag is .TRUE., setting a new Unit value for an * axis may also change its Label and Symbol attributes. For instance, if * an axis has Unit "Hz" and Label "frequency", then changing its Unit to * "log(Hz)" will change its Label to "log( frequency )". In addition, * the Axis Format attribute will be cleared when-ever a new value * is assigned to the Unit attribute. * c Note, if a non-zero value is set for the ActiveUnit flag, then changing a f Note, if a .TRUE. value is set for the ActiveUnit flag, then changing a * Unit value for the current Frame within a FrameSet will result in the * Frame being re-mapped (that is, the Mappings which define the * relationships between Frames within the FrameSet will be modified to * take into account the change in Units). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c value f VALUE = LOGICAL (Given) * The new value to use. f STATUS = INTEGER (Given and Returned) f The global status. * Applicability: * SkyFrame c The ActiveUnit flag for a SkyFrame is always 0 (any value c supplied using this function is ignored). f The ActiveUnit flag for a SkyFrame is always .FALSE. (any value f supplied using this routine is ignored). * SpecFrame c The ActiveUnit flag for a SpecFrame is always 1 (any value c supplied using this function is ignored). f The ActiveUnit flag for a SpecFrame is always .TRUE. (any value f supplied using this routine is ignored). * FluxFrame c The ActiveUnit flag for a FluxFrame is always 1 (any value c supplied using this function is ignored). f The ActiveUnit flag for a FluxFrame is always .TRUE. (any value f supplied using this routine is ignored). * CmpFrame c The default ActiveUnit flag for a CmpFrame is 1 if both of the c component Frames are using active units, and zero otherwise. When f The default ActiveUnit flag for a CmpFrame is .TRUE. if both of the f component Frames are using active units, and .FALSE. otherwise. When * a new value is set for the ActiveUnit flag, the flag value * is propagated to the component Frames. This change will be * reflected through all references to the component Frames, not * just those encapsulated within the CmpFrame. * Region: * Regions always use active units if possible. * Notes: * - The ActiveUnit flag resembles a Frame attribute, except that it * cannot be tested or cleared, and it cannot be accessed using the c generic astGet and astSet functions. f generic AST_GET and AST_SET routines. c - The astGetActiveUnit function can be used to retrieve the current f - The AST_GETACTIVEUNIT routine can be used to retrieve the current * value of the ActiveUnit flag. *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Store a value of 1 for the Frame component if the supplied value is non-zero. */ this->active_unit = ( value ) ? 1 : 0; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * Frame member function (over-rides the astSetAttrib method inherited * from the Mapping class). * Description: * This function assigns an attribute value for a Frame, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the Frame. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. */ /* Local Vaiables: */ AstAxis *ax; /* Pointer to Axis */ AstFrame *pfrm; /* Pointer to primary Frame containing axis */ AstFrame *this; /* Pointer to the Frame structure */ AstSystemType system_code; /* System code */ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */ char *pfrm_setting; /* Primary Frame attribute */ char *axis_setting; /* Pointer to axis attribute setting string */ const char *equals; /* Pointer to equals sign */ const char *old_setting; /* Pointer to supplied setting string */ const char *op; /* Pointer to opening parenthesis */ double dval; /* Double attibute value */ double mjd; /* Epoch as a Modified Julian Date */ int axis; /* Index for the Frame axis */ int axis_nc; /* No. characters in axis attribute name */ int axis_value; /* Offset of value to be assigned to axis */ int digits; /* Number of digits of precision */ int direction; /* Axis direction flag */ int domain; /* Offset of Domain string */ int epoch; /* Offset of Epoch string */ int format; /* Offset of axis Format string */ int free_axis_setting; /* Should axis_setting be freed? */ int has_axis; /* Does setting include an axis specifier? */ int ival; /* Integer attribute value */ int label; /* Offset of axis Label string */ int len; /* Length of setting string */ int match_end; /* Match final axes of target? */ int max_axes; /* Maximum number of axes matched */ int min_axes; /* Minimum number of axes matched */ int nc; /* Number of characters read by astSscanf */ int off2; /* Modified offset of attribute value */ int off; /* Offset of attribute value */ int oldrep; /* Original error reporting state */ int paxis; /* Axis index within primary frame */ int permute; /* Permute axes in order to match? */ int preserve_axes; /* Preserve matched target axes? */ int sign; /* Sign of longitude value */ int symbol; /* Offset of axis Symbol string */ int system; /* Offset of System string */ int title; /* Offset of Title string */ int unit; /* Offset of axis Unit string */ int used; /* Could the setting string be used? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Find the offset to the first equal sign in the setting string. */ equals = strchr( setting, '=' ); /* Set a flag indicating if the attribute name includes an axis specifier. */ op = strchr( setting, '(' ); has_axis = ( !op || op > equals ) ? 0 : 1; /* A flag indicating that we do not need to free the axis_setting memory. */ free_axis_setting = 0; /* Initialise things to avoid compiler warnings. */ axis_setting = NULL; old_setting = NULL; /* Jump back to here if we are trying the same attribute setting but with an explicit axis "(1)" added to the attribute name. */ L1: /* Obtain the length of the setting string. */ len = strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* Digits. */ /* ------- */ if ( nc = 0, ( 1 == astSscanf( setting, "digits= %d %n", &digits, &nc ) ) && ( nc >= len ) ) { astSetDigits( this, digits ); /* Digits(axis). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "digits(%d)= %d %n", &axis, &digits, &nc ) ) && ( nc >= len ) ) { /* There is no function to set the Digits attribute value for an axis directly, so obtain a pointer to the Axis and use this to set the attribute. */ (void) astValidateAxis( this, axis - 1, 1, "astSetDigits(axis)" ); ax = astGetAxis( this, axis - 1 ); astSetAxisDigits( ax, digits ); ax = astAnnul( ax ); /* Direction(axis). */ /* ---------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "direction(%d)= %d %n", &axis, &direction, &nc ) ) && ( nc >= len ) ) { astSetDirection( this, axis - 1, direction ); /* Epoch. */ /* ------ */ } else if ( nc = 0, ( 0 == astSscanf( setting, "epoch=%n%*[^\n]%n", &epoch, &nc ) ) && ( nc >= len ) ) { /* Convert the Epoch value to a Modified Julian Date before use. */ mjd = astReadDateTime( setting + epoch ); if ( astOK ) { astSetEpoch( this, mjd ); /* Report contextual information if the conversion failed. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid epoch value " "\"%s\" given for coordinate system.", status, astGetClass( this ), setting + epoch ); } /* Top(axis). */ /* ---------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "top(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetTop( this, axis - 1, dval ); /* Bottom(axis). */ /* ------------- */ } else if ( nc = 0, ( 2 == astSscanf( setting, "bottom(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetBottom( this, axis - 1, dval ); /* Domain. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "domain=%n%*[^\n]%n", &domain, &nc ) ) && ( nc >= len ) ) { astSetDomain( this, setting + domain ); /* Format(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "format(%d)=%n%*[^\n]%n", &axis, &format, &nc ) ) && ( nc >= len ) ) { astSetFormat( this, axis - 1, setting + format ); /* Label(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "label(%d)=%n%*[^\n]%n", &axis, &label, &nc ) ) && ( nc >= len ) ) { astSetLabel( this, axis - 1, setting + label ); /* MatchEnd. */ /* --------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "matchend= %d %n", &match_end, &nc ) ) && ( nc >= len ) ) { astSetMatchEnd( this, match_end ); /* MaxAxes. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "maxaxes= %d %n", &max_axes, &nc ) ) && ( nc >= len ) ) { astSetMaxAxes( this, max_axes ); /* MinAxes. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "minaxes= %d %n", &min_axes, &nc ) ) && ( nc >= len ) ) { astSetMinAxes( this, min_axes ); /* Permute. */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "permute= %d %n", &permute, &nc ) ) && ( nc >= len ) ) { astSetPermute( this, permute ); /* PreserveAxes. */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "preserveaxes= %d %n", &preserve_axes, &nc ) ) && ( nc >= len ) ) { astSetPreserveAxes( this, preserve_axes ); /* Symbol(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "symbol(%d)=%n%*[^\n]%n", &axis, &symbol, &nc ) ) && ( nc >= len ) ) { astSetSymbol( this, axis - 1, setting + symbol ); /* AlignSystem. */ /* ------------ */ } else if ( nc = 0, ( 0 == astSscanf( setting, "alignsystem= %n%*s %n", &system, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a System code before use. */ system_code = astSystemCode( this, system + setting ); if ( system_code != AST__BADSYSTEM ) { astSetAlignSystem( this, system_code ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid AlignSystem description \"%s\".", status, astGetClass( this ), system + setting ); } /* System. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "system= %n%*s %n", &system, &nc ) ) && ( nc >= len ) ) { /* Convert the string to a System code before use. */ system_code = astSystemCode( this, system + setting ); if ( system_code != AST__BADSYSTEM ) { astSetSystem( this, system_code ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid System description \"%s\".", status, astGetClass( this ), system + setting ); } /* Title. */ /* ------ */ } else if ( nc = 0, ( 0 == astSscanf( setting, "title=%n%*[^\n]%n", &title, &nc ) ) && ( nc >= len ) ) { astSetTitle( this, setting + title ); /* Unit(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "unit(%d)=%n%*[^\n]%n", &axis, &unit, &nc ) ) & ( nc >= len ) ) { astSetUnit( this, axis - 1, setting + unit ); /* ObsLat. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "obslat=%n%*s %n", &off, &nc ) ) && ( nc >= 7 ) ) { /* If the first character in the value string is "N" or "S", remember the sign of the value and skip over the sign character. Default is north (+ve). */ off2 = off; if( setting[ off ] == 'N' || setting[ off ] == 'n' ) { off2++; sign = +1; } else if( setting[ off ] == 'S' || setting[ off ] == 's' ) { off2++; sign = -1; } else { sign = +1; } /* If not already created, create an FK5 J2000 SkyFrame which will be used for formatting and unformatting ObsLon and ObsLat values. */ if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status ); astEndPM; } /* Convert the string to a radians value before use. */ ival = astUnformat( skyframe, 1, setting + off2, &dval ); if ( ival == astChrLen( setting ) - off2 ) { astSetObsLat( this, dval*sign ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for " "ObsLat (observers latitude) \"%s\".", status, astGetClass( this ), setting + off ); } /* ObsLon. */ /* ------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "obslon=%n%*s %n", &off, &nc ) ) && ( nc >= 7 ) ) { /* If the first character in the value string is "E" or "W", remember the sign of the value and skip over the sign character. Default is east (+ve). */ off2 = off; if( setting[ off ] == 'E' || setting[ off ] == 'e' ) { off2++; sign = +1; } else if( setting[ off ] == 'W' || setting[ off ] == 'w' ) { off2++; sign = -1; } else { sign = +1; } /* If not already created, create an FK5 J2000 SkyFrame which will be used for formatting and unformatting ObsLon and ObsLat values. */ if( !skyframe ) { astBeginPM; skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status ); astEndPM; } /* Convert the string to a radians value before use. */ ival = astUnformat( skyframe, 1, setting + off2, &dval ); if ( ival == astChrLen( setting ) - off2 ) { astSetObsLon( this, dval*sign ); /* Report an error if the string value wasn't recognised. */ } else { astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for " "ObsLon (observers longitude) \"%s\".", status, astGetClass( this ), setting + off ); } /* ObsAlt. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "obsalt= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetObsAlt( this, dval ); /* Dut1. */ /* ---- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "dut1= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetDut1( this, dval ); /* Read-only attributes. */ /* --------------------- */ /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* Use this macro to report an error if a read-only attribute has been specified. */ } else if ( MATCH( "naxes" ) || !strncmp( setting, "normunit", 8 ) ) { astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* Other axis attributes. */ /* ---------------------- */ /* If the attribute was not identified above, but appears to refer to a Frame axis, then it may refer to an Axis object of a derived type (which has additional attributes not recognised here). */ } else if ( !free_axis_setting && ( nc = 0, ( 1 == astSscanf( setting, "%*[^()]%n(%d)%n=%*[^\n]%n", &axis_nc, &axis, &axis_value, &nc ) ) && ( nc >= len ) ) ) { /* Validate the axis index and copy the attribute setting string. */ (void) astValidateAxis( this, axis - 1, 1, "astSet" ); axis_setting = astString( setting, len ); if ( astOK ) { /* Over-write the axis index in the copy with the value to be assigned. */ (void) strcpy( axis_setting + axis_nc, setting + axis_value ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis - 1 ); if( astOK ) { /* Assume that we will be able to use the setting. */ used = 1; /* Temporarily switch off error reporting so that if the following attempt to access the axis attribute fails, we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. Any errors reported in this context will simply be ignored, in particularly they are not deferred for later delivery. */ oldrep = astReporting( 0 ); /* Use the Axis astSetAttrib method to set the value. */ astSetAttrib( ax, axis_setting ); /* If the above call failed with a status of AST__BADAT, indicating that the attribute name was not recognised, clear the status so that we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. */ if( astStatus == AST__BADAT ) { astClearStatus; /* Find the primary Frame containing the specified axis. */ astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); /* Only attempt to use the primary Frame if it is not the same as "this" - otherwise we could end up in an infinite loop. */ if( pfrm != this ) { /* astPrimaryFrame returns the original - unpermuted - axis index within the primary Frame. So we need to take into account any axis permutation which has been applied to the primary Frame when forming the attribute name to use below. Find the permuted (external) axis index which corresponds to the internal (unpermuted) axis index "paxis". */ paxis = astValidateAxis( pfrm, paxis, 0, "astSet" ); /* Modify the attribute name to refer to the axis numbering of the primary frame. */ sprintf( pfrm_attrib, "%.*s(%d)", axis_nc, setting, paxis + 1 ); /* Create a setting string in which the attribute name refers to the axis numbering of the primary frame. */ pfrm_setting = NULL; nc = 0; pfrm_setting = astAppendString( pfrm_setting, &nc, pfrm_attrib ); pfrm_setting = astAppendString( pfrm_setting, &nc, setting + axis_value ); /* Attempt to set the attribute within the primary Frame. */ astSetAttrib( pfrm, pfrm_setting ); /* Free the memory. */ pfrm_setting = astFree( pfrm_setting ); /* If this failed, clear the status and indicate that we have not managed to use the attribute setting. */ if( !astOK ) { astClearStatus; used = 0; } } else { used = 0; } /* If not found attempt to set the attribute value in the Axis, omitting the axis index. */ if( ! used ) { astSetAttrib( pfrm, axis_setting ); if( !astOK ) { astClearStatus; } else { used = 1; } } /* Free the setting string, and annul the primary Frame pointer. */ pfrm = astAnnul( pfrm ); } /* Re-instate the original error reporting state. */ astReporting( oldrep ); /* If we could not use the setting, attempt to set the axis attribute again, this time retaining the error report. This is done to ensure the user gets an appropriate error message. */ if( !used ) astSetAttrib( ax, axis_setting ); } /* Annul the Axis pointer and free the memory holding the attribute setting. */ ax = astAnnul( ax ); } axis_setting = astFree( axis_setting ); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, and the Frame has only 1 axis, and the attribute name does not already include an axis specifier, try again after appending "(1)" to the end of the attribute name. */ } else if( !has_axis && astGetNaxes( this ) == 1 && equals ) { /* Take a copy of the supplied setting, allowing 3 extra characters for the axis specifier "(1)". */ axis_setting = astMalloc( len + 4 ); if( axis_setting ) memcpy( axis_setting, setting, len ); /* Indicate we should free the axis_setting memory. */ free_axis_setting = 1; /* Add in the axis specifier. */ strcpy( axis_setting + ( equals - setting ), "(1)" ); /* Add in the equals sign and attribute value. */ strcpy( axis_setting + ( equals - setting ) + 3, equals ); /* Use the new setting instead of the supplied setting. */ old_setting = setting; setting = axis_setting; /* Indicate the setting now has an axis specifier. */ has_axis = 1; /* Jump back to try interpreting the new setting string. */ goto L1; /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. First re-instate the original setting string if it was changed above. */ } else { if( free_axis_setting ) { setting = old_setting; axis_setting = astFree( axis_setting ); free_axis_setting = 0; } (*parent_setattrib)( this_object, setting, status ); } if( free_axis_setting ) axis_setting = astFree( axis_setting ); /* Undefine macros local to this function. */ #undef MATCH } static void SetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status ) { /* *+ * Name: * astSetAxis * Purpose: * Set a new Axis for a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astSetAxis( AstFrame *this, int axis, AstAxis *newaxis ) * Class Membership: * Frame method. * Description: * This function allows a new Axis object to be associated with one * of the axes of a Frame, replacing the previous one. Each Axis * object contains a description of the quantity represented along * one of the Frame's axes, so this function allows this * description to be exchanged for another one. * Parameters: * this * Pointer to the Frame. * axis * The index (zero-based) of the axis whose associated Axis object is to * be replaced. * newaxis * Pointer to the new Axis object. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Validate and permute the axis index supplied. */ axis = astValidateAxis( this, axis, 1, "astSetAxis" ); /* If OK, annul the Frame's pointer to the old Axis object and clone a pointer to the new one to replace it. */ if ( astOK ) { this->axis[ axis ] = astAnnul( this->axis[ axis ] ); this->axis[ axis ] = astClone( newaxis ); } } static void SetFrameFlags( AstFrame *this, int flags, int *status ){ /* *+ * Name: * astSetFrameFlags * Purpose: * Store a new bit mask of flags in a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * void astSetFrameFlags( astFrame *this, int flags ) * Class Membership: * Frame member function. * Description: * This function stores a new set of flags in a Frame. The flags can * be retrieved using astGetFrameFlags. * Parameters: * this * The Frame. * flags * A bit mask holding the flags. Currently, the following bits are * used: * * 0 - Used to indicate if the Frame is currently involved in an * attempt to restore the integrity of a FrameSet following * changes to the attribute values of the Frame. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Assign the new bit mask. */ this->flags = flags; } static void SetFrameVariants( AstFrame *this, AstFrameSet *variants, int *status ){ /* *+ * Name: * astSetFrameVariants * Purpose: * Store a FrameSet holding alternative Frame properties. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astSetVariants( AstFrame *this, AstFrameSet *variants ) * Class Membership: * Frame method. * Description: * This function adds sets of alternative Frame properties to a Frame. * Parameters: * this * Pointer to the Frame. * variants * Pointer to a FrameSet in which each Frame is of the same class * and dimensionality as "this" and all Frames have unique Domain * names. * Notes: * - A clone of the supplied FrameSet pointer is stored in the Frame. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Annul any variants FrameSet already stored in the Frame. */ if( this->variants ) this->variants = astAnnul( this->variants ); /* Store a clone of ht esupplied FrameSet pointer. */ if( variants ) this->variants = astClone( variants ); } static void SetUnit( AstFrame *this, int axis, const char *unit, int *status ) { /* * Name: * SetUnit * Purpose: * Set a value for the Unit attribute of a Frame. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void SetUnit( AstFrame *this, int axis, const char *unit, int *status ) * Class Membership: * Frame method. * Description: * This function sets the Unit value for a Frame. * Parameters: * this * Pointer to the Frame. * axis * The number of the axis (zero-based) for which the Unit value is to * be set. * unit * The new value to be set. * status * Pointer to the inherited status variable. * Returned Value: * void. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ char *c; /* Copy of supplied string */ const char *oldunit; /* Pointer to old units string */ int l; /* Used length of supplied string */ /* Check the global error status. */ if ( !astOK ) return; /* Get a copy of the supplied string which excludes trailing spaces. */ l = astChrLen( unit ); c = astStore( NULL, unit, (size_t) (l + 1) ); if( astOK ) { c[ l ] = 0; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astSetUnit" ); ax = astGetAxis( this, axis ); /* The new unit may require the Label and/or Symbol to be changed, but only if the Frames ActiveUnit flag is set. */ if( astGetActiveUnit( this ) ) { /* Get the existing Axis unit, using the astGetUnit method (rather than astGetAxisUnit) in order to get any default value in the case where the Unit attribute is not set. */ oldunit = astGetUnit( this, axis ); /* Assign the new Unit value. This modifies labels and/or Symbols if necessary. */ NewUnit( ax, oldunit, c, "astSetUnit", astGetClass( this ), status ); } /* Set the Axis Unit attribute value. */ astSetAxisUnit( ax, c ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); } /* Free the string copy */ c = astFree( c ); } static int SubFrame( AstFrame *target, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { /* *+ * Name: * astSubFrame * Purpose: * Select axes from a Frame and convert to the new coordinate system. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astSubFrame( AstFrame *target, AstFrame *template, * int result_naxes, const int *target_axes, * const int *template_axes, AstMapping **map, * AstFrame **result ) * Class Membership: * Frame method. * Description: * This function selects a requested sub-set (or super-set) of the axes from * a "target" Frame and creates a new Frame with copies of the selected * axes assembled in the requested order. It then optionally overlays the * attributes of a "template" Frame on to the result. It returns both the * resulting Frame and a Mapping that describes how to convert between the * coordinate systems described by the target and result Frames. If * necessary, this Mapping takes account of any differences in the Frames' * attributes due to the influence of the template. * Parameters: * target * Pointer to the target Frame, from which axes are to be selected. * template * Pointer to the template Frame, from which new attributes for the * result Frame are to be obtained. Optionally, this may be NULL, in * which case no overlaying of template attributes will be performed. * result_naxes * Number of axes to be selected from the target Frame. This number may * be greater than or less than the number of axes in this Frame (or * equal). * target_axes * Pointer to an array of int with result_naxes elements, giving a list * of the (zero-based) axis indices of the axes to be selected from the * target Frame. The order in which these are given determines the order * in which the axes appear in the result Frame. If any of the values in * this array is set to -1, the corresponding result axis will not be * derived from the target Frame, but will be assigned default attributes * instead. * template_axes * Pointer to an array of int with result_naxes elements. This should * contain a list of the template axes (given as zero-based axis indices) * with which the axes of the result Frame are to be associated. This * array determines which axes are used when overlaying axis-dependent * attributes of the template on to the result. If any element of this * array is set to -1, the corresponding result axis will not receive any * template attributes. * * If the template argument is given as NULL, this array is not used and * a NULL pointer may also be supplied here. * map * Address of a location to receive a pointer to the returned Mapping. * The forward transformation of this Mapping will describe how to * convert coordinates from the coordinate system described by the target * Frame to that described by the result Frame. The inverse * transformation will convert in the opposite direction. * result * Address of a location to receive a pointer to the result Frame. * Returned Value: * A non-zero value is returned if coordinate conversion is * possible between the target and the result Frame. Otherwise zero * is returned and *map and *result are returned as NULL (but this * will not in itself result in an error condition). In general, * coordinate conversion should always be possible if no template * Frame is supplied but may not always be possible otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * Implementation Deficiencies: * - Any axis selection is currently permitted. Probably this * should be restricted so that each axis can only be selected * once. The astValidateAxisSelection method will do this but * currently there are bugs in the CmpFrame class that cause axis * selections which will not pass this test. Install the validation * when these are fixed. *- * Implementation Notes: * - This implementation addresses the selection of axes from a * Frame class object. This simply results in another object of the * same class and a Mapping which describes an axis permutation (or * a unit Mapping as a special case). Changes of Frame attributes * have no significance for coordinate values in this class, so do * not affect the Mapping returned. */ /* Local Variables: */ AstAxis *newaxis; /* Pointer to new Axis object */ AstFrame *tempframe; /* Pointer to temporary Frame */ AstMapping *aumap; /* A units Mapping for a single axis */ AstMapping *numap; /* The new total units Mapping */ AstMapping *umap; /* The total units Mapping */ int *inperm; /* Pointer to permutation array */ int *outperm; /* Pointer to permutation array */ int match; /* Coordinate conversion possible? */ int result_axis; /* Result Frame axis index */ int target_axis; /* Target Frame axis index */ int target_naxes; /* Number of target Frame axes */ int unit; /* Unit Mapping appropriate? */ int uunit; /* Is the "umap" Mapping a UnitMap? */ /* Initialise the returned values. */ *map = NULL; *result = NULL; match = 0; /* Check the global error status. */ if ( !astOK ) return match; /* Obtain the number of target Frame axes. */ target_naxes = astGetNaxes( target ); /* Ensure we do not attempt to use a negative number of result axes. */ if ( result_naxes < 0 ) result_naxes = 0; /* Create a temporary new Frame with the required number of axes. This will have a default Axis object associated with each of its axes. We will replace these where necessary with copies of the actual Axis objects we require. */ tempframe = astFrame( result_naxes, "", status ); /* Allocate memory to store two permutation arrays. These will be used to construct the Mapping that relates the target and result Frames. */ inperm = astMalloc( sizeof( int ) * (size_t) target_naxes ); outperm = astMalloc( sizeof( int ) * (size_t) result_naxes ); if ( astOK ) { /* Initialise the array that associates each target axis with the corresponding result axis (filling it with the value -1 initially signifies no associations). */ for ( target_axis = 0; target_axis < target_naxes; target_axis++ ) { inperm[ target_axis ] = -1; } /* Loop through each axis in the result Frame and obtain the index of the axis in the target Frame from which it is to be derived. */ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { target_axis = target_axes[ result_axis ]; /* Check if the resulting axis index is valid. If not, this result axis is not to be derived from any target axis, and it will therefore be left with its default attributes. Make an entry in the appropriate permutation array to indicate that this result axis is unassociated. */ if ( ( target_axis < 0 ) || ( target_axis >= target_naxes ) ) { outperm[ result_axis ] = -1; /* Otherwise, obtain a pointer to the target Axis object and modify the temporary Frame so that its axis is associated with the same Axis object. Annul the Axis pointer afterwards. */ } else { newaxis = astGetAxis( target, target_axis ); astSetAxis( tempframe, result_axis, newaxis ); newaxis = astAnnul( newaxis ); /* Update both permutation arrays to record the association between the target and result axes. */ outperm[ result_axis ] = target_axis; inperm[ target_axis ] = result_axis; } /* Quit looping if an error occurs. */ if ( !astOK ) break; } /* So far, we have only modified pointers in the temporary Frame to refer to the target Frame's Axis objects. Since we will next modify these objects' attributes, we must make a deep copy of the entire temporary Frame so that we do not modify the target's axes. This copy now becomes our result Frame. Annul the temporary one. */ if ( astOK ) { *result = astCopy( tempframe ); tempframe = astAnnul( tempframe ); /* Invoke the target "astOverlay" method to overlay any remaining attributes from the target Frame which are not associated with individual axes (e.g. the Frame's Title and Domain). */ astOverlay( target, target_axes, *result ); /* If a template Frame was supplied, also invoke its astOverlay method to overlay its attributes on the result Frame. (Note that in this particular case this has no effect other than transferring attributes. In general, however, i.e. in derived classes, this process is vital to determining the mapping below, whose main purpose is to convert between the target and result Frames. These will have different attributes as a result of the influence that the template has here.) */ if ( template ) astOverlay( template, template_axes, *result ); /* We will next generate the Mapping that relates the target and result Frames. If appropriate this should be a unit Mapping (UnitMap), so test if the number of axes in both Frames is equal. */ unit = ( target_naxes == result_naxes ); /* If so, check the contents of one of the permutation arrays to see if all result axes are associated with the corresponding target axis (the converse then also follows). If not, note this fact and quit checking. */ if ( unit ) { for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { if ( outperm[ result_axis ] != result_axis ) { unit = 0; break; } } } /* If a unit Mapping is appropriate, then construct it. */ if ( unit ) { *map = (AstMapping *) astUnitMap( result_naxes, "", status ); /* Otherwise, construct a Mapping describing the axis permutation we have produced. */ } else { *map = (AstMapping *) astPermMap( target_naxes, inperm, result_naxes, outperm, NULL, "", status ); } /* Note that coordinate conversion is possible. */ match = 1; /* If the ActiveUnit flag in both template and result Frame is non-zero, we now modify the Mapping to take account of any differences in the Units attributes of the target and results Frames. */ if( template && astGetActiveUnit( template ) && astGetActiveUnit( *result ) ) { /* Loop round the axes of the results Frame, accumulating a parallel CmpMap ("umap") in which each Mapping is the 1-D Mapping which transforms the Units of the corresponding target axis into the Units of the results axis. */ umap = NULL; uunit = 1; for( result_axis = 0; result_axis < result_naxes; result_axis++ ) { /* Find the index of the corresponding target axis. */ if( unit ) { target_axis = result_axis; } else { target_axis = outperm[ result_axis ]; } /* Get the Unit string for both axes, and attempt to find a Mapping which transforms values in the target units into the corresponding value in the results units. If this results axis does not have a corresponding target axis, then indicate that no units mapping can be found. */ if( target_axis > -1 ) { aumap = astUnitMapper( astGetUnit( target, target_axis ), astGetUnit( *result, result_axis ), NULL, NULL ); } else { aumap = NULL; } /* If no Mapping could be found, annull the Mapping and leave the loop. Otherwise, see if the Mapping is a UnitMap. If not, set a flag to indicate that we have at least one non-unit map. */ if( !aumap ) { if( umap ) umap = astAnnul( umap ); match = 0; break; } else { if( !astIsAUnitMap( aumap ) ) uunit = 0; } /* Add this Mapping into the parallel CmpMap. */ if( umap ) { numap = (AstMapping *) astCmpMap( umap, aumap, 0, "", status ); umap = astAnnul( umap ); aumap = astAnnul( aumap ); umap = numap; } else { umap = aumap; } } /* If the resulting CmpMap is not just a UnitMap, add it in series with the current results mapping, and then simplify it. */ if( !uunit && umap ) { numap = (AstMapping *) astCmpMap( *map, umap, 1, "", status ); (void) astAnnul( *map ); *map = numap; } /* Annul the CmpMap containing the units Mappings. */ if( umap ) umap = astAnnul( umap ); /* If the units could not bve matched annul the returned mapping. */ if( !match && *map ) *map = astAnnul( *map ); } } } /* Free the memory used for the permutation arrays. */ inperm = astFree( inperm ); outperm = astFree( outperm ); /* If an error occurred, annul the returned objects and reset the returned value. */ if ( !astOK ) { *map = astAnnul( *map ); *result = astAnnul( *result ); match = 0; } /* Return the result. */ return match; } static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) { /* *+ * Name: * astSystemCode * Purpose: * Convert a string into a coordinate system type code. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * AstSystemType SystemCode( AstFrame *this, const char *system ) * Class Membership: * Frame method. * Description: * This function converts a string used for the external description of * a coordinate system into a Frame coordinate system type code (System * attribute value). It is the inverse of the astSystemString function. * Parameters: * this * Pointer to the Frame. * system * Pointer to a constant null-terminated string containing the * external description of the coordinate system. * Returned Value: * The System type code. * Notes: * - A value of AST__BADSYSTEM is returned if the coordinate system * description was not recognised. This does not produce an error. * - A value of AST__BADSYSTEM is also returned if this function * is invoked with the global error status set or if it should fail * for any reason. *- */ /* Local Variables: */ AstSystemType result; /* Result value to return */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" string against each possibility and assign the result. The basic Frame class only supports a single system "Cartesian". */ if ( astChrMatch( "Cartesian", system ) ) { result = AST__CART; } /* Return the result. */ return result; } static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) { /* *+ * Name: * astSystemString * Purpose: * Convert a coordinate system type code into a string. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * const char *astSystemString( AstFrame *this, AstSystemType system ) * Class Membership: * Frame method. * Description: * This function converts a Frame coordinate system type code * (System attribute value) into a string suitable for use as an * external representation of the coordinate system type. * Parameters: * this * Pointer to the Frame. * system * The coordinate system type code. * Returned Value: * Pointer to a constant null-terminated string containing the * textual equivalent of the type code supplied. * Notes: * - A NULL pointer value is returned if the coordinate system * code was not recognised. This does not produce an error. * - A NULL pointer value is also returned if this function is * invoked with the global error status set or if it should fail * for any reason. *- */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Match the "system" value against each possibility and convert to a string pointer. (Where possible, return the same string as would be used in the FITS WCS representation of the coordinate system). A basic Frame only allows a single System value, "Cartesian". */ switch ( system ) { case AST__CART: result = "Cartesian"; break; } /* Return the result pointer. */ return result; } static int TestActiveUnit( AstFrame *this, int *status ){ /* *+ * Name: * astTestActiveUnit * Purpose: * Determines if the ActiveUnit flag is set. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astTestActiveUnit( AstFrame *this ) * Class Membership: * Frame method. * Description: * This function tests the current value of the ActiveUnit flag for a * Frame. See the description of the astSetActiveUnit function for a * description of the ActiveUnit flag. * Parameters: * this * Pointer to the Frame. * Returned Value: * Non-zero if the flag has been set. Zero otherwise. * Notes: * - A zero value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. *-- */ /* Local Variables: */ int result; /* The returned value */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Return the result. */ return ( this->active_unit != -INT_MAX ); } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a Frame. * Type: * Private function. * Synopsis: * #include "frame.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * Frame member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a Frame's attributes. * Parameters: * this * Pointer to the Frame. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - This function uses one-based axis numbering so that it is * suitable for external (public) use. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis */ AstFrame *pfrm; /* Pointer to primary Frame containing axis */ AstFrame *this; /* Pointer to the Frame structure */ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */ char *axis_attrib; /* Pointer to axis attribute name */ const char *old_attrib; /* Pointer to supplied attribute name string */ int axis; /* Frame axis number */ int axis_nc; /* No. characters in axis attribute name */ int free_axis_attrib; /* Should axis_attrib be freed? */ int has_axis; /* Does attrib name include axis specifier? */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ int oldrep; /* Original error reporting state */ int paxis; /* Axis index within primary frame */ int result; /* Result value to return */ int used; /* Could the setting string be used? */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Set a flag indicating if the attribute name includes an axis specifier. */ has_axis = ( strchr( attrib, '(' ) != NULL ); /* A flag indicating that we do not need to free the axis_attrib memory. */ free_axis_attrib = 0; /* Initialise things to avoid compiler warnings. */ axis_attrib = NULL; old_attrib = NULL; /* Jump back to here if we are trying the same attribute but with an explicit axis "(1)" added to the end of the name. */ L1: /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* Digits. */ /* ------- */ if ( !strcmp( attrib, "digits" ) ) { result = astTestDigits( this ); /* Digits(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { /* There is no function to test the Digits attribute for an axis directly, so obtain a pointer to the Axis and use this to test the attribute. */ (void) astValidateAxis( this, axis - 1, 1, "astTestDigits(axis)" ); ax = astGetAxis( this, axis - 1 ); result = astTestAxisDigits( ax ); ax = astAnnul( ax ); /* Direction(axis). */ /* ---------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestDirection( this, axis - 1 ); /* Epoch. */ /* ------ */ } else if ( !strcmp( attrib, "epoch" ) ) { result = astTestEpoch( this ); /* Bottom(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestBottom( this, axis - 1 ); /* Top(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestTop( this, axis - 1 ); /* Domain. */ /* ------- */ } else if ( !strcmp( attrib, "domain" ) ) { result = astTestDomain( this ); /* Format(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestFormat( this, axis - 1 ); /* Label(axis). */ /* ------------ */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestLabel( this, axis - 1 ); /* MatchEnd. */ /* --------- */ } else if ( !strcmp( attrib, "matchend" ) ) { result = astTestMatchEnd( this ); /* MaxAxes. */ /* -------- */ } else if ( !strcmp( attrib, "maxaxes" ) ) { result = astTestMaxAxes( this ); /* MinAxes. */ /* -------- */ } else if ( !strcmp( attrib, "minaxes" ) ) { result = astTestMinAxes( this ); /* Permute. */ /* -------- */ } else if ( !strcmp( attrib, "permute" ) ) { result = astTestPermute( this ); /* PreserveAxes. */ /* ------------- */ } else if ( !strcmp( attrib, "preserveaxes" ) ) { result = astTestPreserveAxes( this ); /* Symbol(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestSymbol( this, axis - 1 ); /* AlignSystem. */ /* ------------ */ } else if ( !strcmp( attrib, "alignsystem" ) ) { result = astTestAlignSystem( this ); /* System. */ /* ------- */ } else if ( !strcmp( attrib, "system" ) ) { result = astTestSystem( this ); /* Title. */ /* ------ */ } else if ( !strcmp( attrib, "title" ) ) { result = astTestTitle( this ); /* Unit(axis). */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestUnit( this, axis - 1 ); /* ObsLat. */ /* ------- */ } else if ( !strcmp( attrib, "obslat" ) ) { result = astTestObsLat( this ); /* ObsLon. */ /* ------- */ } else if ( !strcmp( attrib, "obslon" ) ) { result = astTestObsLon( this ); /* ObsAlt. */ /* ------- */ } else if ( !strcmp( attrib, "obsalt" ) ) { result = astTestObsAlt( this ); /* Dut1. */ /* ---- */ } else if ( !strcmp( attrib, "dut1" ) ) { result = astTestDut1( this ); /* Read-only attributes. */ /* --------------------- */ /* Test if the attribute name matches any of the read-only attributes of this class. If it does, then return zero. */ } else if ( !strcmp( attrib, "naxes" ) || !strncmp( attrib, "normunit", 8 ) ) { result = 0; /* Other axis attributes. */ /* ---------------------- */ /* If the attribute was not identified above, but appears to refer to a Frame axis, then it may refer to an Axis object of a derived type (which has additional attributes not recognised here). */ } else if ( !free_axis_attrib && ( nc = 0, ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n", &axis_nc, &axis, &nc ) ) && ( nc >= len ) ) ) { /* Validate the axis index and extract the attribute name. */ (void) astValidateAxis( this, axis - 1, 1, "astTest" ); axis_attrib = astString( attrib, axis_nc ); /* Obtain a pointer to the Axis object. */ ax = astGetAxis( this, axis - 1 ); if( astOK ) { /* Assume that we will be able to use the attribute name. */ used = 1; /* Temporarily switch off error reporting so that if the following attempt to access the axis attribute fails, we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. Any errors reported in this context will simply be ignored, in particularly they are not deferred for later delivery. */ oldrep = astReporting( 0 ); /* Use the Axis astTestAttrib method to test the attribute value. */ result = astTestAttrib( ax, axis_attrib ); /* If the above call failed with a status of AST__BADAT, indicating that the attribute name was not recognised, clear the status so that we can try to interpret the attribute name as an attribute of the primary Frame containing the specified axis. */ if( astStatus == AST__BADAT ) { astClearStatus; /* Find the primary Frame containing the specified axis. */ astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); /* Only attempt to use the primary Frame if it is not the same as "this" - otherwise we could end up in an infinite loop. */ if( pfrm != this ) { /* astPrimaryFrame returns the original - unpermuted - axis index within the primary Frame. So we need to take into account any axis permutation which has been applied to the primary Frame when forming the attribute name to use below. Find the permuted (external) axis index which corresponds to the internal (unpermuted) axis index "paxis". */ paxis = astValidateAxis( pfrm, paxis, 0, "astTest" ); /* Modify the attribute name to refer to the axis numbering of the primary frame. */ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 ); /* Attempt to test the attribute as an attribute of the primary Frame. */ result = astTestAttrib( pfrm, pfrm_attrib ); /* If this failed, clear the status and indicate that we have not managed to use the attribute name. */ if( !astOK ) { astClearStatus; used = 0; } } else { used = 0; } /* If not found attempt to test the attribute value in the Axis, omitting the axis index. */ if( ! used ) { result = astTestAttrib( pfrm, axis_attrib ); if( !astOK ) { astClearStatus; } else { used = 1; } } /* Annul the primary Frame pointer. */ pfrm = astAnnul( pfrm ); } /* Re-instate the original error reporting state. */ astReporting( oldrep ); /* If we could not use the attribute name, attempt to test the axis attribute again, this time retaining the error report. This is done to ensure the user gets an appropriate error message. */ if( !used ) result = astTestAttrib( ax, axis_attrib ); } /* Annul the Axis pointer and free the memory holding the attribute name. */ ax = astAnnul( ax ); axis_attrib = astFree( axis_attrib ); /* Not recognised. */ /* --------------- */ /* If the attribute is still not recognised, and the Frame has only 1 axis, and the attribute name does not already include an axis specifier, try again after appending "(1)" to the end of the attribute name. */ } else if( !has_axis && astGetNaxes( this ) == 1 ) { /* Take a copy of the supplied name, allowing 3 extra characters for the axis specifier "(1)". */ axis_attrib = astMalloc( len + 4 ); if( axis_attrib ) memcpy( axis_attrib, attrib, len ); /* Indicate we should free the axis_attrib memory. */ free_axis_attrib = 1; /* Add in the axis specifier. */ strcpy( axis_attrib + len, "(1)" ); /* Use the new attribute name instead of the supplied name. */ old_attrib = attrib; attrib = axis_attrib; /* Indicate the attribute name now has an axis specifier. */ has_axis = 1; /* Jump back to try interpreting the new attribute name. */ goto L1; /* Not recognised. */ /* --------------- */ /* If the attribute name is still not recognised, pass it on to the parent method for further interpretation. First re-instate the original attrib name string if it was changed above. */ } else { if( free_axis_attrib ) { attrib = old_attrib; axis_attrib = astFree( axis_attrib ); } result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Use a Frame to transform a set of points. * Type: * Private function. * Synopsis: * #include "frame.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * Frame member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a Frame and a set of points encapsulated in a * PointSet and transforms the points so as to perform the identity * transformation (i.e. simply copies the coordinate values). * Parameters: * this * Pointer to the Frame. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. In this case, both transformations are equivalent. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the Frame being applied. This number * will be equal to the number of Frame axes. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstFrame *this; /* Pointer to the Frame structure */ AstPointSet *result; /* Pointer value to be returned */ AstUnitMap *unitmap; /* Pointer to temporary UnitMap */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_mapping; /* Create a unit Mapping with one coordinate for each Frame axis. */ unitmap = astUnitMap( astGetNaxes( this ), "", status ); /* Use the Mapping to transform (i.e. copy) the coordinate values. */ result = astTransform( unitmap, in, forward, out ); /* Annul the Mapping. */ unitmap = astAnnul( unitmap ); /* If an error occurred and a new PointSet may have been created, then annul the result. In any case, ensure that a NULL pointer is returned. */ if ( !astOK ) { if ( !out ) result = astAnnul( result ); result = NULL; } /* Return the result pointer. */ return result; } static int Unformat( AstFrame *this, int axis, const char *string, double *value, int *status ) { /* *+ * Name: * astUnformat * Purpose: * Read a formatted coordinate value for a Frame axis. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astUnformat( AstFrame *this, int axis, const char *string, * double *value ) * Class Membership: * Frame method. * Description: * This function reads a formatted coordinate value for a Frame * axis (supplied as a string) and returns the equivalent numerical * value as a double. It also returns the number of characters read * from the string. * Parameters: * this * Pointer to the Frame. * axis * The number of the Frame axis for which the coordinate value * is to be read (axis numbering starts at zero for the first * axis). * string * Pointer to a constant null-terminated string containing the * formatted coordinate value. * value * Pointer to a double in which the coordinate value read will be * returned. * Returned Value: * The number of characters read from the string to obtain the * coordinate value. * Notes: * - Any white space at the beginning of the string will be * skipped, as also will any trailing white space following the * coordinate value read. The function's return value will reflect * this. * - A function value of zero (and no coordinate value) will be * returned, without error, if the string supplied does not contain * a suitably formatted value. * - The string "" is recognised as a special case and will * generate the value AST__BAD, without error. The test for this * string is case-insensitive and permits embedded white space. * - A function result of zero will be returned and no coordinate * value will be returned via the "value" pointer if this function * is invoked with the global error status set, or if it should * fail for any reason. *- * Implementation Notes: * - This function implements the basic astUnformat method * available via the protected interface to the Frame class. The * public interface to this method is provided by the * astUnformatId_ function. */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis object */ const char *label; /* Pointer to axis label string */ double coord; /* Coordinate value read */ int digits_set; /* Axis Digits attribute set? */ int nc; /* Number of characters read */ int status_value; /* AST error status */ /* Initialise. */ nc = 0; /* Check the global error status. */ if ( !astOK ) return nc; /* Validate the axis index and obtain a pointer to the required Axis. */ (void) astValidateAxis( this, axis, 1, "astUnformat" ); ax = astGetAxis( this, axis ); /* Test if any Axis attributes which may affect the result are undefined (i.e. have not been explicitly set). If so, we over-ride them, giving them temporary values dictated by the Frame. Only the Digits attribute is potentially relevant here. */ digits_set = astTestAxisDigits( ax ); if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) ); /* Read the coordinate value. */ if ( astOK ) { nc = astAxisUnformat( ax, string, &coord ); /* If an error occurred, save and temporarily clear the global error status while the axis Label string is obtained. Then restore the original error status value afterwards. */ if ( !astOK ) { status_value = astStatus; astClearStatus; label = astGetLabel( this, axis ); astSetStatus( status_value ); /* Report a contextual error message containing the axis label. */ astError( status_value, "%s(%s): Unable to read \"%s\" value.", status, "astUnformat", astGetClass( this ), label ); } } /* Clear any Axis attributes that were temporarily over-ridden. */ if ( !digits_set ) astClearAxisDigits( ax ); /* Annul the Axis pointer. */ ax = astAnnul( ax ); /* If an error occurred, clear the count of characters read. */ if ( !astOK ) { nc = 0; /* Otherwise, if characters were read, return the coordinate value. */ } else if ( nc ) { *value = coord; } /* Return the number of characters read. */ return nc; } static int ValidateAxis( AstFrame *this, int axis, int fwd, const char *method, int *status ) { /* *+ * Name: * astValidateAxis * Purpose: * Validate and permute a Frame's axis index. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astValidateAxis( AstFrame *this, int axis, int fwd, * const char *method ) * Class Membership: * Frame method. * Description: * This function checks the validity of an index (zero-based) which * is to be used to address one of the coordinate axes of a * Frame. If the index is valid, it is permuted using the axis * permutation array associated with the Frame and the (zero-based) * permuted axis index is returned. This gives the location of the * required axis information within the Frame's internal arrays. If * the axis index supplied is not valid, an error is reported and * the global error status is set. * Parameters: * this * Pointer to the Frame. * axis * The axis index (zero-based) to be checked. To be valid, it * must lie between zero and (naxes-1) inclusive, where "naxes" * is the number of coordinate axes associated with the Frame. * fwd * If non-zero, the suppplied axis index is assumed to be an * "external" axis index, and the corresponding "internal" axis index * is returned as the function value. Otherwise, the suppplied axis * index is assumed to be an "internal" axis index, and the * corresponding "external" axis index is returned as the function * value. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * Returned Value: * The permuted axis index - either "internal" or "external" as * specified by "fwd". * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. * - Error messages issued by this function refer to the public * numbering system used for axes which is one-based (zero-based axis * indices are used internally). *- */ /* Local Variables: */ const int *perm; /* Pointer to axis permutation array */ int naxes; /* Number of Frame axes */ int result; /* Permuted axis index */ /* Initialise. */ result = 0; /* Determine the number of Frame axes. */ naxes = astGetNaxes( this ); if ( astOK ) { /* If the Frame has no axes, report an error (note we convert to one-based axis numbering in the error message). */ if ( naxes == 0 ) { astError( AST__AXIIN, "%s(%s): Invalid attempt to use an axis index " "(%d) for a %s which has no axes.", status, method, astGetClass( this ), axis + 1, astGetClass( this ) ); /* Otherwise, check the axis index for validity and report an error if it is not valid (again, use one-based axis numbering). */ } else if ( ( axis < 0 ) || ( axis >= naxes ) ) { astError( AST__AXIIN, "%s(%s): Axis index (%d) invalid - it should " "be in the range 1 to %d.", status, method, astGetClass( this ), axis + 1, naxes ); /* If the axis index was valid, obtain the axis permutation array and use this to generate the permuted axis value. */ } else { perm = astGetPerm( this ); if( perm ) { /* External to internal is a simple look-up. */ if( fwd ) { result = perm[ axis ]; /* Internal to external requires a search through the permutation array. */ } else { for( result = 0; result < naxes; result++ ) { if( perm[ result ] == axis ) break; } } } } } /* Return the result. */ return result; } static void ValidateAxisSelection( AstFrame *this, int naxes, const int *axes, const char *method, int *status ) { /* *+ * Name: * astValidateAxisSelection * Purpose: * Check that a set of axes selected from a Frame is valid. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * void astValidateAxisSelection( AstFrame *this, int naxes, * const int *axes, const char *method ) * Class Membership: * Frame method. * Description: * This function checks the validity of an array of (zero-based) * axis indices that specify a set of axes to be selected from a * Frame. To be valid, no axis should be selected more than * once. In assessing this, any axis indices that do not refer to * valid Frame axes (e.g. are set to -1) are ignored. * * If the axis selection is valid, this function returns without further * action. Otherwise, an error is reported and the global error status is * set. * Parameters: * this * Pointer to the Frame. * naxes * The number of axes to be selected (may be zero). * axes * Pointer to an array of int with naxes elements that contains the * (zero based) axis indices to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis selection. This method name is used * solely for constructing error messages. *- */ /* Local Variables: */ int *count; /* Pointer to temporary array of counts */ int axis; /* Loop counter for selected axes */ int frame_axis; /* Loop counter for Frame axes */ int frame_naxes; /* Number of Frame axes */ int valid; /* Axis selection valid? */ /* Check the global error status. */ if ( !astOK ) return; /* Check to see if no axes have been selected. If so, there is nothing to do. */ if ( naxes ) { /* Initialise. */ valid = 1; /* Obtain the number of Frame axes and allocate an array of int with one element for each Frame axis. This will store a count of the number of times each axis is selected. */ frame_naxes = astGetNaxes( this ); count = astMalloc( sizeof( int ) * (size_t) frame_naxes ); if ( astOK ) { /* Initialise the array of counts to zero. */ for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) { count[ frame_axis ] = 0; } /* Loop through each selected axis. */ for ( axis = 0; axis < naxes; axis++ ) { frame_axis = axes[ axis ]; /* Check if the selected axis index is valid for the Frame. If so, increment the selection count for that Frame axis. */ if ( ( frame_axis >= 0 ) && ( frame_axis < frame_naxes ) ) { count[ frame_axis ]++; } } /* Loop through the count array and check that no Frame axis was selected more than once. If it was, clear the "valid" flag and quit checking. */ for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) { if ( count[ frame_axis ] > 1 ) { valid = 0; break; } } } /* Free the temporary count array. */ count = astFree( count ); /* If no error has occurred, but the axis selection is not valid, then report an error. */ if ( astOK && !valid ) { astError( AST__SELIN, "%s(%s): Invalid axis selection - each axis " "may be selected only once.", status, method, astGetClass( this ) ); } } } static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) { /* *+ * Name: * astValidateSystem * Purpose: * Validate a value for a Frame's System attribute. * Type: * Protected virtual function. * Synopsis: * #include "frame.h" * int astValidateSystem( AstFrame *this, AstSystemType system, * const char *method ) * Class Membership: * Frame method. * Description: * This function checks the validity of the supplied system value. * If the value is valid, it is returned unchanged. Otherwise, an * error is reported and a value of AST__BADSYSTEM is returned. * Parameters: * this * Pointer to the Frame. * system * The system value to be checked. * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function * to validate an axis index. This method name is used solely * for constructing error messages. * Returned Value: * The validated system value. * Notes: * - A value of AST_BADSYSTEM will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstSystemType result; /* Validated system value */ /* Initialise. */ result = AST__BADSYSTEM; /* Check the global error status. */ if ( !astOK ) return result; /* If the value is out of bounds, report an error. */ if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) { astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System " "or AlignSystem attribute of a %s.", status, method, astGetClass( this ), (int) system, astGetClass( this ) ); /* Otherwise, return the supplied value. */ } else { result = system; } /* Return the result. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with the axes of a Frame using the private macros defined for this purpose at the start of this file. */ /* *att++ * Name: * Naxes * Purpose: * Number of Frame axes. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This is a read-only attribute giving the number of axes in a * Frame (i.e. the number of dimensions of the coordinate space * which the Frame describes). This value is determined when the * Frame is created. * Applicability: * Frame * All Frames have this attribute. * FrameSet * The Naxes attribute of a FrameSet is the same as that of its * current Frame (as specified by the Current attribute). * CmpFrame * The Naxes attribute of a CmpFrame is equal to the sum of the * Naxes values of its two component Frames. *att-- */ /* *att++ * Name: * Direction(axis) * Purpose: * Display axis in conventional direction? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which suggests how the axes of * a Frame should be displayed (e.g.) in graphical output. By * default, it has the value one, indicating that they should be * shown in the conventional sense (increasing left to right for an * abscissa, and bottom to top for an ordinate). If set to zero, * this attribute indicates that the direction should be reversed, * as would often be done for an astronomical magnitude or a right * ascension axis. * Applicability: * Frame * The default Direction value supplied by the Frame class is 1, * indicating that all axes should be displayed in the * conventional direction. * SkyFrame * The SkyFrame class re-defines the default Direction value to * suggest that certain axes (e.g. right ascension) should be * plotted in reverse when appropriate. * FrameSet * The Direction attribute of a FrameSet axis is the same as * that of its current Frame (as specified by the Current * attribute). * Plot * The Direction attribute of the base Frame in a Plot is set to * indicate the sense of the two graphics axes, as implied by the * graphics bounding box supplied when the Plot was created. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. * - The Direction attribute does not directly affect the behaviour * of the AST library. Instead, it serves as a hint to applications * programs about the orientation in which they may wish to display * any data associated with the Frame. Applications are free to * ignore this hint if they wish. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Direction flag. */ MAKE_CLEAR(Direction) MAKE_GET(Direction,int,0,0,0) MAKE_SET(Direction,int) MAKE_TEST(Direction) /* *att++ * Name: * Dut1 * Purpose: * The UT1-UTC correction. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute is used when calculating the Local Apparent Sidereal * Time corresponding to SkyFrame's Epoch value (used when converting * positions to or from the "AzEl" system). It should be set to the * difference, in seconds, between the UT1 and UTC timescales at the * moment in time represented by the SkyFrame's Epoch attribute. The * value to use is unpredictable and depends on changes in the earth's * rotation speed. Values for UT1-UTC can be obtained from the * International Earth Rotation and Reference Systems Service * (IERS) at http://www.iers.org/. * * Currently, the correction is always less than 1 second. This is * ensured by the occasional introduction of leap seconds into the UTC * timescale. Therefore no great error will usually result if no value * is assigned to this attribute (in which case a default value of * zero is used). However, it is possible that a decision may be taken * at some time in the future to abandon the introduction of leap * seconds, in which case the DUT correction could grow to significant * sizes. * Applicability: * Frame * All Frames have this attribute. *att-- */ /* The UT1-UTC correction, in seconds. Has a value of AST__BAD when not set yielding a default value of 0.0. */ astMAKE_CLEAR(Frame,Dut1,dut1,AST__BAD) astMAKE_GET(Frame,Dut1,double,0.0,(this->dut1 == AST__BAD ? 0.0 : this->dut1)) astMAKE_SET(Frame,Dut1,double,dut1,value) astMAKE_TEST(Frame,Dut1,( this->dut1 != AST__BAD )) /* *att++ * Name: * Epoch * Purpose: * Epoch of observation. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute is used to qualify the coordinate systems described by * a Frame, by giving the moment in time when the coordinates are known * to be correct. Often, this will be the date of observation, and is * important in cases where coordinates systems move with respect to each * other over the course of time. * * The Epoch attribute is stored as a Modified Julian Date, but * when setting its value it may be given in a variety of * formats. See the "Input Formats" section (below) for details. * Strictly, the Epoch value should be supplied in the TDB timescale, * but for some purposes (for instance, for converting sky positions * between different types of equatorial system) the timescale is not * significant, and UTC may be used. * Input Formats: * The formats accepted when setting an Epoch value are listed * below. They are all case-insensitive and are generally tolerant * of extra white space and alternative field delimiters: * * - Besselian Epoch: Expressed in decimal years, with or without * decimal places ("B1950" or "B1976.13" for example). * * - Julian Epoch: Expressed in decimal years, with or without * decimal places ("J2000" or "J2100.9" for example). * * - Year: Decimal years, with or without decimal places ("1996.8" * for example). Such values are interpreted as a Besselian epoch * (see above) if less than 1984.0 and as a Julian epoch otherwise. * * - Julian Date: With or without decimal places ("JD 2454321.9" for * example). * * - Modified Julian Date: With or without decimal places * ("MJD 54321.4" for example). * * - Gregorian Calendar Date: With the month expressed either as an * integer or a 3-character abbreviation, and with optional decimal * places to represent a fraction of a day ("1996-10-2" or * "1996-Oct-2.6" for example). If no fractional part of a day is * given, the time refers to the start of the day (zero hours). * * - Gregorian Date and Time: Any calendar date (as above) but with * a fraction of a day expressed as hours, minutes and seconds * ("1996-Oct-2 12:13:56.985" for example). The date and time can be * separated by a space or by a "T" (as used by ISO8601 format). * Output Format: * When enquiring Epoch values, the format used is the "Year" * format described under "Input Formats". This is a value in * decimal years which will be a Besselian epoch if less than * 1984.0 and a Julian epoch otherwise. By omitting any character * prefix, this format allows the Epoch value to be obtained as * either a character string or a floating point value. * Applicability: * Frame * All Frames have this attribute. The basic Frame class provides * a default of J2000.0 (Julian) but makes no use of the Epoch value. * This is because the Frame class does not distinguish between * different Cartesian coordinate systems (see the System attribute). * CmpFrame * The default Epoch value for a CmpFrame is selected as follows; * if the Epoch attribute has been set in the first component Frame * then the Epoch value from the first component Frame is used as * the default for the CmpFrame. Otherwise, if the Epoch attribute has * been set in the second component Frame then the Epoch value from the * second component Frame is used as the default for the CmpFrame. * Otherwise, the default Epoch value from the first component * Frame is used as the default for the CmpFrame. When the Epoch * attribute of a CmpFrame is set or cleared, it is also set or * cleared in the two component Frames. * FrameSet * The Epoch attribute of a FrameSet is the same as that of its current * Frame (as specified by the Current attribute). * SkyFrame * The coordinates of sources within a SkyFrame can changed with time * for various reasons, including: (i) changing aberration of light * caused by the observer's velocity (e.g. due to the Earth's motion * around the Sun), (ii) changing gravitational deflection by the Sun * due to changes in the observer's position with time, (iii) fictitious * motion due to rotation of non-inertial coordinate systems (e.g. the * old FK4 system), and (iv) proper motion of the source itself (although * this last effect is not handled by the SkyFrame class because it * affects individual sources rather than the coordinate system as * a whole). * * The default Epoch value in a SkyFrame is B1950.0 (Besselian) for the * old FK4-based coordinate systems (see the System attribute) and * J2000.0 (Julian) for all others. * * Care must be taken to distinguish the Epoch value, which relates to * motion (or apparent motion) of the source, from the superficially * similar Equinox value. The latter is used to qualify a coordinate * system which is itself in motion in a (notionally) predictable way * as a result of being referred to a slowly moving reference plane * (e.g. the equator). * * See the description of the System attribute for details of which * qualifying attributes apply to each celestial coordinate system. * TimeFrame * A TimeFrame describes a general time axis and so cannot be completely * characterised by a single Epoch value. For this reason the TimeFrame * class makes no use of the Epoch attribute. However, user code can * still make use of the attribute if necessary to represent a "typical" * time spanned by the TimeFrame. The default Epoch value for a TimeFrame * will be the TDB equivalent of the current value of the TimeFrame's * TimeOrigin attribute. If no value has been set for TimeOrigin, * then the default Epoch value is J2000.0. The coordinates of sources within a SkyFrame can changed with time *att-- */ /* Clear the Epoch value by setting it to AST__BAD. */ astMAKE_CLEAR(Frame,Epoch,epoch,AST__BAD) /* Provide a default value of J2000.0 setting. */ astMAKE_GET(Frame,Epoch,double,AST__BAD,( ( this->epoch != AST__BAD ) ? this->epoch : palEpj2d( 2000.0 ))) /* Allow any Epoch value to be set. */ astMAKE_SET(Frame,Epoch,double,epoch,value) /* An Epoch value is set if it is not equal to AST__BAD. */ astMAKE_TEST(Frame,Epoch,( this->epoch != AST__BAD )) /* *att++ * Name: * Top(axis) * Purpose: * Highest axis value to display * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute gives the highest axis value to be displayed (for c instance, by the astGrid method). f instance, by the AST_GRID method). * Applicability: * Frame * The default supplied by the Frame class is to display all axis * values, without any limit. * SkyFrame * The SkyFrame class re-defines the default Top value to +90 degrees * for latitude axes, and 180 degrees for co-latitude axes. The * default for longitude axes is to display all axis values. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Top value. */ MAKE_CLEAR(Top) MAKE_GET(Top,double,DBL_MAX,0,DBL_MAX) MAKE_SET(Top,double) MAKE_TEST(Top) /* *att++ * Name: * Bottom(axis) * Purpose: * Lowest axis value to display * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute gives the lowest axis value to be displayed (for c instance, by the astGrid method). f instance, by the AST_GRID method). * Applicability: * Frame * The default supplied by the Frame class is to display all axis * values, without any limit. * SkyFrame * The SkyFrame class re-defines the default Bottom value to -90 degrees * for latitude axes, and 0 degrees for co-latitude axes. The * default for longitude axes is to display all axis values. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Bottom value. */ MAKE_CLEAR(Bottom) MAKE_GET(Bottom,double,-DBL_MAX,0,-DBL_MAX) MAKE_SET(Bottom,double) MAKE_TEST(Bottom) /* *att++ * Name: * Format(axis) * Purpose: * Format specification for axis values. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the format to be used when displaying * coordinate values associated with a particular Frame axis * (i.e. to convert values from binary to character form). It is c interpreted by the astFormat function and determines the f interpreted by the AST_FORMAT function and determines the * formatting which it applies. * * If no Format value is set for a Frame axis, a default value is * supplied instead. This is based on the value of the Digits, or * Digits(axis), attribute and is chosen so that it displays the * requested number of digits of precision. * Applicability: * Frame * The Frame class interprets this attribute as a format * specification string to be passed to the C "printf" function * (e.g. "%1.7G") in order to format a single coordinate value * (supplied as a double precision number). c c When supplying a value for this attribute, beware that the c "%" character may be interpreted directly as a format c specification by some printf-like functions (such as c astSet). You may need to double it (i.e. use "%%") to avoid c this. * SkyFrame * The SkyFrame class re-defines the syntax and default value of * the Format string to allow the formatting of sexagesimal * values as appropriate for the particular celestial coordinate * system being represented. The syntax of SkyFrame Format * strings is described (below) in the "SkyFrame Formats" * section. * FrameSet * The Format attribute of a FrameSet axis is the same as that * of its current Frame (as specified by the Current * attribute). Note that the syntax of the Format string is also * determined by the current Frame. * TimeFrame * The TimeFrame class extends the syntax of the Format string to * allow the formatting of TimeFrame axis values as Gregorian calendar * dates and times. The syntax of TimeFrame Format strings is described * (below) in the "TimeFrame Formats" section. * SkyFrame Formats: * The Format string supplied for a SkyFrame should contain zero or * more of the following characters. These may occur in any order, * but the following is recommended for clarity: * * - "+": Indicates that a plus sign should be prefixed to positive * values. By default, no plus sign is used. * * - "z": Indicates that leading zeros should be prefixed to the * value so that the first field is of constant width, as would be * required in a fixed-width table (leading zeros are always * prefixed to any fields that follow). By default, no leading * zeros are added. * * - "i": Use the standard ISO field separator (a colon) between * fields. This is the default behaviour. * * - "b": Use a blank to separate fields. * * - "l": Use a letter ("h"/"d", "m" or "s" as appropriate) to * separate fields. * * - "g": Use a letter and symbols to separate fields ("h"/"d", "m" or "s", * etc, as appropriate), but include escape sequences in the formatted * value so that the Plot class will draw the separators as small * super-scripts. c The default escape sequences are optimised for the pgplot graphics c package, but new escape sequences may be specified using function c astSetSkyDelim. * * - "d": Include a degrees field. Expressing the angle purely in * degrees is also the default if none of "h", "m", "s" or "t" are * given. * * - "h": Express the angle as a time and include an hours field * (where 24 hours correspond to 360 degrees). Expressing the angle * purely in hours is also the default if "t" is given without * either "m" or "s". * * - "m": Include a minutes field. By default this is not included. * * - "s": Include a seconds field. By default this is not included. * This request is ignored if "d" or "h" is given, unless a minutes * field is also included. * * - "t": Express the angle as a time (where 24 hours correspond to * 360 degrees). This option is ignored if either "d" or "h" is * given and is intended for use where the value is to be expressed * purely in minutes and/or seconds of time (with no hours * field). If "t" is given without "d", "h", "m" or "s" being * present, then it is equivalent to "h". * * - ".": Indicates that decimal places are to be given for the * final field in the formatted string (whichever field this * is). The "." should be followed immediately by an unsigned * integer which gives the number of decimal places required, or by an * asterisk. If an asterisk is supplied, a default number of decimal * places is used which is based on the value of the Digits * attribute. * * All of the above format specifiers are case-insensitive. If * several characters make conflicting requests (e.g. if both "i" * and "b" appear), then the character occurring last takes * precedence, except that "d" and "h" always override "t". * * If the format string starts with a percentage sign (%), then the * whole format string is assumed to conform to the syntax defined by * the Frame class, and the axis values is formated as a decimal * radians value. * TimeFrame Formats: * The Format string supplied for a TimeFrame should either use the * syntax defined by the base Frame class (i.e. a C "printf" format * string), or the extended "iso" syntax described below (the default * value is inherited from the Frame class): * * - C "printf" syntax: If the Format string is a C "printf" format * description such as "%1.7G", the TimeFrame axis value will be * formatted without change as a floating point value using this format. * The formatted string will thus represent an offset from the zero point * specified by the TimeFrame's TimeOrigin attribute, measured in * units given by the TimeFrame's Unit attribute. * * - "iso" syntax: This is used to format a TimeFrame axis value as a * Gregorian date followed by an optional time of day. If the Format * value commences with the string "iso" then the TimeFrame axis value * will be converted to an absolute MJD, including the addition of the * current TimeOrigin value, and then formatted as a Gregorian date * using the format "yyyy-mm-dd". Optionally, the Format value may * include an integer precision following the "iso" specification (e.g. * "iso.2"), in which case the time of day will be appended to the * formatted date (if no time of day is included, the date field is * rounded to the nearest day). The integer value in the Format string * indicates the number of decimal places to use in the seconds field. For * instance, a Format value of "iso.0" produces a time of day of the form * "hh:mm:ss", and a Format value of "iso.2" produces a time of day of the * form "hh:mm:ss.ss". The date and time fields will be separated by a * space unless 'T' is appended to the end of string, in which case * the letter T (upper case) will be used as the separator. The value of * the Digits attribute is ignored when using this "iso" format. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Format string. */ MAKE_CLEAR(Format) MAKE_GET(Format,const char *,NULL,0,0) MAKE_SET(Format,const char *) MAKE_TEST(Format) /* *att++ * Name: * Label(axis) * Purpose: * Axis label. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies a label to be attached to each axis of * a Frame when it is represented (e.g.) in graphical output. * * If a Label value has not been set for a Frame axis, then a * suitable default is supplied. * Applicability: * Frame * The default supplied by the Frame class is the string "Axis * ", where is 1, 2, etc. for each successive axis. * SkyFrame * The SkyFrame class re-defines the default Label value * (e.g. to "Right ascension" or "Galactic latitude") as * appropriate for the particular celestial coordinate system * being represented. * TimeFrame * The TimeFrame class re-defines the default Label value as * appropriate for the particular time system being represented. * FrameSet * The Label attribute of a FrameSet axis is the same as that of * its current Frame (as specified by the Current attribute). * Notes: * - Axis labels are intended purely for interpretation by human * readers and not by software. * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This provides an interface to the Axis methods for accessing the Label string, but provides an alternative default Label based on the axis number. This default string is written to the static "label_buff" buffer and a pointer to this is returned if required. */ MAKE_CLEAR(Label) MAKE_GET(Label,const char *,NULL,1,GetDefaultLabel( axis, status )) MAKE_SET(Label,const char *) MAKE_TEST(Label) /* *att++ * Name: * Symbol(axis) * Purpose: * Axis symbol. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies a short-form symbol to be used to * represent coordinate values for a particular axis of a * Frame. This might be used (e.g.) in algebraic expressions where * a full description of the axis would be inappropriate. Examples * include "RA" and "Dec" (for Right Ascension and Declination). * * If a Symbol value has not been set for a Frame axis, then a * suitable default is supplied. * Applicability: * Frame * The default Symbol value supplied by the Frame class is the * string "", where is 1, 2, etc. for successive * axes, and is the value of the Frame's Domain * attribute (truncated if necessary so that the final string * does not exceed 15 characters). If no Domain value has been * set, "x" is used as the value in constructing this * default string. * SkyFrame * The SkyFrame class re-defines the default Symbol value * (e.g. to "RA" or "Dec") as appropriate for the particular * celestial coordinate system being represented. * TimeFrame * The TimeFrame class re-defines the default Symbol value as * appropriate for the particular time system being represented. * FrameSet * The Symbol attribute of a FrameSet axis is the same as that * of its current Frame (as specified by the Current attribute). * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This provides an interface to the Axis methods for accessing the Symbol string, but provides an alternative default Symbol based on the axis number and the Frame's Domain (if defined, otherwise "x" is used). This default string is written to the static "symbol_buff" buffer and a pointer to this is returned if required. */ MAKE_CLEAR(Symbol) MAKE_GET(Symbol,const char *,NULL,1,GetDefaultSymbol( this, axis, status ) ) MAKE_SET(Symbol,const char *) MAKE_TEST(Symbol) /* *att++ * Name: * Unit(axis) * Purpose: * Axis physical units. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute contains a textual representation of the physical * units used to represent coordinate values on a particular axis c of a Frame. The astSetActiveUnit function controls how the Unit values f of a Frame. The AST_SETACTIVEUNIT routine controls how the Unit values * are used. * Applicability: * Frame * The default supplied by the Frame class is an empty string. * SkyFrame * The SkyFrame class re-defines the default Unit value (e.g. to * "hh:mm:ss.sss") to describe the character string returned by c the astFormat function when formatting coordinate values. f the AST_FORMAT function when formatting coordinate values. * SpecFrame * The SpecFrame class re-defines the default Unit value so that it * is appropriate for the current System value. See the System * attribute for details. An error will be reported if an attempt * is made to use an inappropriate Unit. * TimeFrame * The TimeFrame class re-defines the default Unit value so that it * is appropriate for the current System value. See the System * attribute for details. An error will be reported if an attempt * is made to use an inappropriate Unit (e.g. "km"). * FrameSet * The Unit attribute of a FrameSet axis is the same as that of * its current Frame (as specified by the Current attribute). * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Unit string. */ MAKE_GET(Unit,const char *,NULL,0,0) MAKE_TEST(Unit) /* *att++ * Name: * NormUnit(axis) * Purpose: * Normalised Axis physical units. * Type: * Public attribute. * Synopsis: * String, read-only. * Description: * The value of this read-only attribute is derived from the current * value of the Unit attribute. It will represent an equivalent system * of units to the Unit attribute, but will potentially be simplified. * For instance, if Unit is set to "s*(m/s)", the NormUnit value will * be "m". If no simplification can be performed, the value of the * NormUnit attribute will equal that of the Unit attribute. * Applicability: * Frame * All Frames have this attribute. * Notes: * - When specifying this attribute by name, it should be * subscripted with the number of the Frame axis to which it * applies. *att-- */ /* This simply provides an interface to the Axis methods for accessing the Unit string. */ MAKE_GET(NormUnit,const char *,NULL,0,0) /* Implement member functions to access the attributes associated with the Frame as a whole using the macros defined for this purpose in the "object.h" file. */ /* *att++ * Name: * Digits/Digits(axis) * Purpose: * Number of digits of precision. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute specifies how many digits of precision are * required by default when a coordinate value is formatted for a c Frame axis (e.g. using astFormat). Its value may be set either f Frame axis (e.g. using AST_FORMAT). Its value may be set either * for a Frame as a whole, or (by subscripting the attribute name * with the number of an axis) for each axis individually. Any * value set for an individual axis will over-ride the value for * the Frame as a whole. * * Note that the Digits value acts only as a means of determining a * default Format string. Its effects are over-ridden if a Format * string is set explicitly for an axis. However, if the Format * attribute specifies the precision using the string ".*", then * the Digits attribute is used to determine the number of decimal * places to produce. * Applicability: * Frame * The default Digits value supplied by the Frame class is 7. If * a value less than 1 is supplied, then 1 is used instead. * FrameSet * The Digits attribute of a FrameSet (or one of its axes) is * the same as that of its current Frame (as specified by the * Current attribute). * Plot * The default Digits value used by the Plot class when drawing * annotated axis labels is the smallest value which results in all * adjacent labels being distinct. * TimeFrame * The Digits attribute is ignored when a TimeFrame formats a value * as a date and time string (see the Format attribute). *att-- */ /* Clear the Digits value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,Digits,digits,-INT_MAX) /* Supply a default of 7 digits if no value has been set. */ astMAKE_GET(Frame,Digits,int,0,( ( this->digits != -INT_MAX ) ? this->digits : 7 )) /* Constrain the Digits value being set to be at least 1. */ astMAKE_SET(Frame,Digits,int,digits,( value > 1 ? value : 1 )) /* The Digits value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,Digits,( this->digits != -INT_MAX )) /* *att++ * Name: * MatchEnd * Purpose: * Match trailing axes? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which controls how a Frame c behaves when it is used (by astFindFrame) as a template to match f behaves when it is used (by AST_FINDFRAME) as a template to match * another (target) Frame. It applies only in the case where a * match occurs between template and target Frames with different * numbers of axes. * * If the MatchEnd value of the template Frame is zero, then the * axes which occur first in the target Frame will be matched and * any trailing axes (in either the target or template) will be * disregarded. If it is non-zero, the final axes in each Frame * will be matched and any un-matched leading axes will be * disregarded instead. * Applicability: * Frame * The default MatchEnd value for a Frame is zero, so that * trailing axes are disregarded. * FrameSet * The MatchEnd attribute of a FrameSet is the same as that of * its current Frame (as specified by the Current attribute). *att-- */ /* Clear the MatchEnd value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,MatchEnd,match_end,-INT_MAX) /* Supply a default of 0 if no MatchEnd value has been set. */ astMAKE_GET(Frame,MatchEnd,int,0,( ( this->match_end != -INT_MAX ) ? this->match_end : 0 )) /* Set a MatchEnd value of 1 if any non-zero value is supplied. */ astMAKE_SET(Frame,MatchEnd,int,match_end,( value != 0 )) /* The MatchEnd value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,MatchEnd,( this->match_end != -INT_MAX )) /* *att++ * Name: * MaxAxes * Purpose: * Maximum number of Frame axes to match. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute controls how a Frame behaves when it is used (by c astFindFrame) as a template to match another (target) Frame. It f AST_FINDFRAME) as a template to match another (target) Frame. It * specifies the maximum number of axes that the target Frame may * have in order to match the template. * * Normally, this value will equal the number of Frame axes, so * that a template Frame will only match another Frame with the * same number of axes as itself. By setting a different value, * however, the matching process may be used to identify Frames * with specified numbers of axes. * Applicability: * Frame * The default MaxAxes value for a Frame is equal to the number * of Frame axes (Naxes attribute). * CmpFrame * The MaxAxes attribute of a CmpFrame defaults to a large number * (1000000) which is much larger than any likely number of axes in * a Frame. Combined with the MinAxes default of zero (for a * CmpFrame), this means that the default behaviour for a CmpFrame * is to match any target Frame that consists of a subset of the * axes in the template CmpFrame. To change this so that a CmpFrame * will only match Frames that have the same number of axes, you * should set the CmpFrame MaxAxes and MinAxes attributes to the * number of axes in the CmpFrame. * FrameSet * The MaxAxes attribute of a FrameSet is the same as that of * its current Frame (as specified by the Current attribute). * Notes: * - When setting a MaxAxes value, the value of the MinAxes * attribute may also be silently changed so that it remains * consistent with (i.e. does not exceed) the new value. The * default MaxAxes value may also be reduced to remain consistent * with the MinAxes value. * - If a template Frame is used to match a target with a different * number of axes, the MatchEnd attribute of the template is used * to determine how the individual axes of each Frame should match. *att-- */ /* Clear the MaxAxes value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,MaxAxes,max_axes,-INT_MAX) /* Use the DefaultMaxAxes and ConsistentMaxAxes functions (defined earlier) for the Get and Set operations to ensure that MinAxes and MaxAxes values remain consistent. */ astMAKE_GET(Frame,MaxAxes,int,0,DefaultMaxAxes( this, status )) astMAKE_SET(Frame,MaxAxes,int,max_axes,ConsistentMaxAxes( this, value, status )) /* The MaxAxes value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,MaxAxes,( this->max_axes != -INT_MAX )) /* *att++ * Name: * MinAxes * Purpose: * Minimum number of Frame axes to match. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute controls how a Frame behaves when it is used (by c astFindFrame) as a template to match another (target) Frame. It f AST_FINDFRAME) as a template to match another (target) Frame. It * specifies the minimum number of axes that the target Frame may * have in order to match the template. * * Normally, this value will equal the number of Frame axes, so * that a template Frame will only match another Frame with the * same number of axes as itself. By setting a different value, * however, the matching process may be used to identify Frames * with specified numbers of axes. * Applicability: * Frame * The default MinAxes value for a Frame is equal to the number * of Frame axes (Naxes attribute). * CmpFrame * The MinAxes attribute of a CmpFrame defaults to zero. Combined * with the MaxAxes default of 1000000 (for a CmpFrame), this means * that the default behaviour for a CmpFrame is to match any target * Frame that consists of a subset of the axes in the template * CmpFrame. To change this so that a CmpFrame will only match Frames * that have the same number of axes, you should set the CmpFrame * MinAxes and MaxAxes attributes to the number of axes in the CmpFrame. * FrameSet * The MinAxes attribute of a FrameSet is the same as that of * its current Frame (as specified by the Current attribute). * Notes: * - When setting a MinAxes value, the value of the MaxAxes * attribute may also be silently changed so that it remains * consistent with (i.e. is not less than) the new value. The * default MinAxes value may also be reduced to remain consistent * with the MaxAxes value. * - If a template Frame is used to match a target with a different * number of axes, the MatchEnd attribute of the template is used * to determine how the individual axes of each Frame should match. *att-- */ /* Clear the MinAxes value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,MinAxes,min_axes,-INT_MAX) /* Use the DefaultMinAxes and ConsistentMinAxes functions (defined earlier) for the Get and Set operations to ensure that MinAxes and MaxAxes values remain consistent. */ astMAKE_GET(Frame,MinAxes,int,0,DefaultMinAxes( this, status )) astMAKE_SET(Frame,MinAxes,int,min_axes,ConsistentMinAxes( this, value, status )) /* The MinAxes value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,MinAxes,( this->min_axes != -INT_MAX )) /* *att++ * Name: * Domain * Purpose: * Coordinate system domain. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute contains a string which identifies the physical * domain of the coordinate system that a Frame describes. * * The Domain attribute also controls how a Frame behaves when it is c used (by astFindFrame) as a template to match another (target) f used (by AST_FINDFRAME) as a template to match another (target) * Frame. It does this by specifying the Domain that the target * Frame should have in order to match the template. If the Domain * value in the template Frame is set, then only targets with the * same Domain value will be matched. If the template's Domain * value is not set, however, then the target's Domain will be * ignored. * Applicability: * Frame * The default Domain value supplied by the Frame class is an * empty string. * SkyFrame * The SkyFrame class re-defines the default Domain value to be * "SKY". * CmpFrame * The CmpFrame class re-defines the default Domain value to be * of the form "-", where and are the * Domains of the two component Frames. If both these Domains are * blank, then the string "CMP" is used as the default Domain name. * FrameSet * The Domain attribute of a FrameSet is the same as that of its * current Frame (as specified by the Current attribute). * SpecFrame * The SpecFrame class re-defines the default Domain value to be * "SPECTRUM". * DSBSpecFrame * The DSBSpecFrame class re-defines the default Domain value to be * "DSBSPECTRUM". * FluxFrame * The FluxFrame class re-defines the default Domain value to be * "FLUX". * SpecFluxFrame * The FluxFrame class re-defines the default Domain value to be * "SPECTRUM-FLUX". * TimeFrame * The TimeFrame class re-defines the default Domain value to be * "TIME". * Notes: * - All Domain values are converted to upper case and white space * is removed before use. *att-- */ /* Clear the Domain value by freeing the allocated memory and assigning a NULL pointer. */ astMAKE_CLEAR(Frame,Domain,domain,astFree( this->domain )) /* If the Domain value is not set, supply a default in the form of a pointer to the constant string "". */ astMAKE_GET(Frame,Domain,const char *,NULL,( this->domain ? this->domain : "" )) /* Set a Domain value by freeing any previously allocated memory, allocating new memory, storing the string, removing white space, converting to upper case and saving the pointer to the cleaned copy. */ astMAKE_SET(Frame,Domain,const char *,domain,CleanDomain( astStore( this->domain, value, strlen( value ) + (size_t) 1 ), status )) /* The Domain value is set if the pointer to it is not NULL. */ astMAKE_TEST(Frame,Domain,( this->domain != NULL )) /* *att++ * Name: * Permute * Purpose: * Permute axis order? * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute is a boolean value which controls how a Frame c behaves when it is used (by astFindFrame) as a template to match f behaves when it is used (by AST_FINDFRAME) as a template to match * another (target) Frame. It specifies whether the axis order of * the target Frame may be permuted in order to obtain a match. * * If the template's Permute value is zero, it will match a target * only if it can do so without changing the order of its * axes. Otherwise, it will attempt to permute the target's axes as * necessary. * * The default value is 1, so that axis permutation will be attempted. * Applicability: * Frame * All Frames have this attribute. However, the Frame class * effectively ignores this attribute and behaves as if it has * the value 1. This is because the axes of a basic Frame are * not distinguishable and will always match any other Frame * whatever their order. * SkyFrame * Unlike a basic Frame, the SkyFrame class makes use of this * attribute. * FrameSet * The Permute attribute of a FrameSet is the same as that of * its current Frame (as specified by the Current attribute). *att-- */ /* Clear the Permute value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,Permute,permute,-INT_MAX) /* Supply a default of 1 if no Permute value has been set. */ astMAKE_GET(Frame,Permute,int,0,( ( this->permute != -INT_MAX ) ? this->permute : 1 )) /* Set a Permute value of 1 if any non-zero value is supplied. */ astMAKE_SET(Frame,Permute,int,permute,( value != 0 )) /* The Permute value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,Permute,( this->permute != -INT_MAX )) /* *att++ * Name: * PreserveAxes * Purpose: * Preserve axes? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute controls how a Frame behaves when it is used (by c astFindFrame) as a template to match another (target) Frame. It f AST_FINDFRAME) as a template to match another (target) Frame. It * determines which axes appear (and in what order) in the "result" * Frame produced. * * If PreserveAxes is zero in the template Frame, then the result * Frame will have the same number (and order) of axes as the * template. If it is non-zero, however, the axes of the target * Frame will be preserved, so that the result Frame will have the * same number (and order) of axes as the target. * * The default value is zero, so that target axes are not preserved * and the result Frame resembles the template. * Applicability: * Frame * All Frames have this attribute. * FrameSet * The PreserveAxes attribute of a FrameSet is the same as that * of its current Frame (as specified by the Current attribute). *att-- */ /* Clear the PreserveAxes value by setting it to -INT_MAX. */ astMAKE_CLEAR(Frame,PreserveAxes,preserve_axes,-INT_MAX) /* Supply a default of 0 if no PreserveAxes value has been set. */ astMAKE_GET(Frame,PreserveAxes,int,0,( ( this->preserve_axes != -INT_MAX ) ? this->preserve_axes : 0 )) /* Set a PreserveAxes value of 1 if any non-zero value is supplied. */ astMAKE_SET(Frame,PreserveAxes,int,preserve_axes,( value != 0 )) /* The PreserveAxes value is set if it is not -INT_MAX. */ astMAKE_TEST(Frame,PreserveAxes,( this->preserve_axes != -INT_MAX )) /* *att++ * Name: * AlignSystem * Purpose: * Coordinate system in which to align the Frame. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute controls how a Frame behaves when it is used (by c astFindFrame or astConvert) as a template to match another (target) f AST_FINDFRAME or AST_CONVERT) as a template to match another (target) * Frame. It identifies the coordinate system in which the two Frames * will be aligned by the match. * * The values which may be assigned to this attribute, and its default * value, depend on the class of Frame and are described in the * "Applicability" section below. In general, the AlignSystem attribute * will accept any of the values which may be assigned to the System * attribute. * c The Mapping returned by AST_FINDFRAME or AST_CONVERT will use the f The Mapping returned by astFindFrame or astConvert will use the * coordinate system specified by the AlignSystem attribute as an * intermediate coordinate system. The total returned Mapping will first * map positions from the first Frame into this intermediate coordinate * system, using the attributes of the first Frame. It will then map * these positions from the intermediate coordinate system into the * second Frame, using the attributes of the second Frame. * Applicability: * Frame * The AlignSystem attribute for a basic Frame always equals "Cartesian", * and may not be altered. * CmpFrame * The AlignSystem attribute for a CmpFrame always equals "Compound", * and may not be altered. * FrameSet * The AlignSystem attribute of a FrameSet is the same as that of its * current Frame (as specified by the Current attribute). * SkyFrame * The default AlignSystem attribute for a SkyFrame is "ICRS". * SpecFrame * The default AlignSystem attribute for a SpecFrame is "Wave" * (wavelength). * TimeFrame * The default AlignSystem attribute for a TimeFrame is "MJD". *att-- */ /* Clear the AlignSystem value by setting it to AST__BADSYSTEM. */ astMAKE_CLEAR(Frame,AlignSystem,alignsystem,AST__BADSYSTEM) /* Provide a default AlignSystem of AST__CART. */ astMAKE_GET(Frame,AlignSystem,AstSystemType,AST__BADSYSTEM,( ( this->alignsystem == AST__BADSYSTEM ) ? AST__CART : this->alignsystem ) ) /* Validate the AlignSystem value being set and retain the original if the supplied value is not recognized. */ astMAKE_SET(Frame,AlignSystem,AstSystemType,alignsystem,( (astValidateSystem( this, value, "astSetAlignSystem" ) != AST__BADSYSTEM) ? value : this->alignsystem )) /* The AlignSystem value is set if it is not AST__BADSYSTEM. */ astMAKE_TEST(Frame,AlignSystem,( this->alignsystem != AST__BADSYSTEM )) /* *att++ * Name: * System * Purpose: * Coordinate system used to describe positions within the domain * Type: * Public attribute. * Synopsis: * String. * Description: * In general it is possible for positions within a given physical * domain to be described using one of several different coordinate * systems. For instance, the SkyFrame class can use galactic * coordinates, equatorial coordinates, etc, to describe positions on * the sky. As another example, the SpecFrame class can use frequency, * wavelength, velocity, etc, to describe a position within an * electromagnetic spectrum. The System attribute identifies the particular * coordinate system represented by a Frame. Each class of Frame * defines a set of acceptable values for this attribute, as listed * below (all are case insensitive). Where more than one alternative * System value is shown, the first of will be returned when an * enquiry is made. * Applicability: * Frame * The System attribute for a basic Frame always equals "Cartesian", * and may not be altered. * CmpFrame * The System attribute for a CmpFrame always equals "Compound", * and may not be altered. In addition, the CmpFrame class allows * the System attribute to be referenced for a component Frame by * including the index of an axis within the required component * Frame. For instance, "System(3)" refers to the System attribute * of the component Frame which includes axis 3 of the CmpFrame. * FrameSet * The System attribute of a FrameSet is the same as that of its * current Frame (as specified by the Current attribute). * SkyFrame * The SkyFrame class supports the following System values and * associated celestial coordinate systems: * * - "AZEL": Horizon coordinates. The longitude axis is azimuth * such that geographic north has an azimuth of zero and geographic * east has an azimuth of +PI/2 radians. The zenith has elevation * +PI/2. When converting to and from other celestial coordinate * systems, no corrections are applied for atmospheric refraction * or polar motion (however, a correction for diurnal aberattion is * applied). Note, unlike most other * celestial coordinate systems, this system is right handed. Also, * unlike other SkyFrame systems, the AzEl system is sensitive to * the timescale in which the Epoch value is supplied. This is * because of the gross diurnal rotation which this system undergoes, * causing a small change in time to translate to a large rotation. * When converting to or from an AzEl system, the Epoch value for * both source and destination SkyFrames should be supplied in the * TDB timescale. The difference between TDB and TT is between 1 * and 2 milliseconds, and so a TT value can usually be supplied in * place of a TDB value. The TT timescale is related to TAI via * TT = TAI + 32.184 seconds. * * - "ECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the * ecliptic and mean equinox specified by the qualifying Equinox * value. * * - "FK4": The old FK4 (barycentric) equatorial coordinate system, * which should be qualified by an Equinox value. The underlying * model on which this is based is non-inertial and rotates slowly * with time, so for accurate work FK4 coordinate systems should * also be qualified by an Epoch value. * * - "FK4-NO-E" or "FK4_NO_E": The old FK4 (barycentric) equatorial * system but without the "E-terms of aberration" (e.g. some radio * catalogues). This coordinate system should also be qualified by * both an Equinox and an Epoch value. * * - "FK5" or "EQUATORIAL": The modern FK5 (barycentric) equatorial * coordinate system. This should be qualified by an Equinox value. * * - "GALACTIC": Galactic coordinates (IAU 1958). * * - "GAPPT", "GEOCENTRIC" or "APPARENT": The geocentric apparent * equatorial coordinate system, which gives the apparent positions * of sources relative to the true plane of the Earth's equator and * the equinox (the coordinate origin) at a time specified by the * qualifying Epoch value. (Note that no Equinox is needed to * qualify this coordinate system because no model "mean equinox" * is involved.) These coordinates give the apparent right * ascension and declination of a source for a specified date of * observation, and therefore form an approximate basis for * pointing a telescope. Note, however, that they are applicable to * a fictitious observer at the Earth's centre, and therefore * ignore such effects as atmospheric refraction and the (normally * much smaller) aberration of light due to the rotational velocity * of the Earth's surface. Geocentric apparent coordinates are * derived from the standard FK5 (J2000.0) barycentric coordinates * by taking account of the gravitational deflection of light by * the Sun (usually small), the aberration of light caused by the * motion of the Earth's centre with respect to the barycentre * (larger), and the precession and nutation of the Earth's spin * axis (normally larger still). * * - "HELIOECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the * ecliptic and mean equinox of J2000.0, in which an offset is added to * the longitude value which results in the centre of the sun being at * zero longitude at the date given by the Epoch attribute. Attempts to * set a value for the Equinox attribute will be ignored, since this * system is always referred to J2000.0. * * - "ICRS": The Internation Celestial Reference System, realised * through the Hipparcos catalogue. Whilst not an equatorial system * by definition, the ICRS is very close to the FK5 (J2000) system * and is usually treated as an equatorial system. The distinction * between ICRS and FK5 (J2000) only becomes important when accuracies * of 50 milli-arcseconds or better are required. ICRS need not be * qualified by an Equinox value. * * - "J2000": An equatorial coordinate system based on the mean * dynamical equator and equinox of the J2000 epoch. The dynamical * equator and equinox differ slightly from those used by the FK5 * model, and so a "J2000" SkyFrame will differ slightly from an * "FK5(Equinox=J2000)" SkyFrame. The J2000 System need not be * qualified by an Equinox value * * - "SUPERGALACTIC": De Vaucouleurs Supergalactic coordinates. * * - "UNKNOWN": Any other general spherical coordinate system. No * Mapping can be created between a pair of SkyFrames if either of the * SkyFrames has System set to "Unknown". * * Currently, the default System value is "ICRS". However, this * default may change in future as new astrometric standards * evolve. The intention is to track the most modern appropriate * standard. For this reason, you should use the default only if * this is what you intend (and can tolerate any associated slight * change in future). If you intend to use the ICRS system * indefinitely, then you should specify it explicitly. * SpecFrame * The SpecFrame class supports the following System values and * associated spectral coordinate systems (the default is "WAVE" - * wavelength). They are all defined in FITS-WCS paper III: * * - "FREQ": Frequency (GHz) * - "ENER" or "ENERGY": Energy (J) * - "WAVN" or "WAVENUM": Wave-number (1/m) * - "WAVE" or "WAVELEN": Vacuum wave-length (Angstrom) * - "AWAV" or "AIRWAVE": Wave-length in air (Angstrom) * - "VRAD" or "VRADIO": Radio velocity (km/s) * - "VOPT" or "VOPTICAL": Optical velocity (km/s) * - "ZOPT" or "REDSHIFT": Redshift (dimensionless) * - "BETA": Beta factor (dimensionless) * - "VELO" or "VREL": Apparent radial ("relativistic") velocity (km/s) * * The default value for the Unit attribute for each system is shown * in parentheses. Note that the default value for the ActiveUnit flag c is non-zero f is .TRUE. * for a SpecFrame, meaning that changes to the Unit attribute for * a SpecFrame will result in the SpecFrame being re-mapped within * its enclosing FrameSet in order to reflect the change in units c (see astSetActiveUnit function for further information). f (see AST_SETACTIVEUNIT routine for further information). * TimeFrame * The TimeFrame class supports the following System values and * associated coordinate systems (the default is "MJD"): * * - "MJD": Modified Julian Date (d) * - "JD": Julian Date (d) * - "JEPOCH": Julian epoch (yr) * - "BEPOCH": Besselian (yr) * * The default value for the Unit attribute for each system is shown * in parentheses. Strictly, these systems should not allow changes * to be made to the units. For instance, the usual definition of * "MJD" and "JD" include the statement that the values will be in * units of days. However, AST does allow the use of other units * with all the above supported systems (except BEPOCH), on the * understanding that conversion to the "correct" units involves * nothing more than a simple scaling (1 yr = 365.25 d, 1 d = 24 h, * 1 h = 60 min, 1 min = 60 s). Besselian epoch values are defined * in terms of tropical years of 365.2422 days, rather than the * usual Julian year of 365.25 days. Therefore, to avoid any * confusion, the Unit attribute is automatically cleared to "yr" when * a System value of BEPOCH System is selected, and an error is * reported if any attempt is subsequently made to change the Unit * attribute. * * Note that the default value for the ActiveUnit flag c is non-zero f is .TRUE. * for a TimeFrame, meaning that changes to the Unit attribute for * a TimeFrame will result in the TimeFrame being re-mapped within * its enclosing FrameSet in order to reflect the change in units c (see astSetActiveUnit function for further information). f (see AST_SETACTIVEUNIT routine for further information). * FluxFrame * The FluxFrame class supports the following System values and * associated systems for measuring observed value: * * - "FLXDN": Flux per unit frequency (W/m^2/Hz) * - "FLXDNW": Flux per unit wavelength (W/m^2/Angstrom) * - "SFCBR": Surface brightness in frequency units (W/m^2/Hz/arcmin**2) * - "SFCBRW": Surface brightness in wavelength units (W/m^2/Angstrom/arcmin**2) * * The above lists specified the default units for each System. If an * explicit value is set for the Unit attribute but no value is set * for System, then the default System value is determined by the Unit * string (if the units are not appropriate for describing any of the * supported Systems then an error will be reported when an attempt is * made to access the System value). If no value has been specified for * either Unit or System, then System=FLXDN and Unit=W/m^2/Hz are * used. *att-- */ /* Clear the System value by setting it to AST__BADSYSTEM. */ astMAKE_CLEAR(Frame,System,system,AST__BADSYSTEM) /* Provide a default coordinate system of AST__CART. */ astMAKE_GET(Frame,System,AstSystemType,AST__BADSYSTEM,( ( this->system == AST__BADSYSTEM ) ? AST__CART : this->system ) ) /* Validate the System value being set and retain the original if the supplied value is not recognized. */ astMAKE_SET(Frame,System,AstSystemType,system,( (astValidateSystem( this, value, "astSetSystem" ) != AST__BADSYSTEM) ? value : this->system )) /* The System value is set if it is not AST__BADSYSTEM. */ astMAKE_TEST(Frame,System,( this->system != AST__BADSYSTEM )) /* *att++ * Name: * Title * Purpose: * Frame title. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute holds a string which is used as a title in (e.g.) * graphical output to describe the coordinate system which a Frame * represents. Examples might be "Detector Coordinates" or * "Galactic Coordinates". * * If a Title value has not been set for a Frame, then a suitable * default is supplied, depending on the class of the Frame. * Applicability: * Frame * The default supplied by the Frame class is "-d coordinate * system", where is the number of Frame axes (Naxes * attribute). * CmpFrame * The CmpFrame class re-defines the default Title value to be * "-d compound coordinate system", where is the number * of CmpFrame axes (Naxes attribute). * FrameSet * The Title attribute of a FrameSet is the same as that of its * current Frame (as specified by the Current attribute). * Notes: * - A Frame's Title is intended purely for interpretation by human * readers and not by software. *att-- */ /* Clear the Title value by freeing the allocated memory and assigning a NULL pointer. */ astMAKE_CLEAR(Frame,Title,title,astFree( this->title )) /* If the Title value is not set, write a default based on the number of Frame axes into the static "title_buff" buffer, and return a pointer to this buffer. */ astMAKE_GET(Frame,Title,const char *,NULL,( this->title ? this->title : GetDefaultTitle( this, status ) )) /* Set a Title value by freeing any previously allocated memory, allocating new memory, storing the string and saving the pointer to the copy. */ astMAKE_SET(Frame,Title,const char *,title,astStore( this->title, value, strlen( value ) + (size_t) 1 )) /* The Title value is set if the pointer to it is not NULL. */ astMAKE_TEST(Frame,Title,( this->title != NULL )) /* *att++ * Name: * ObsLat * Purpose: * The geodetic latitude of the observer * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the geodetic latitude of the observer, in * degrees, relative to the IAU 1976 reference ellipsoid. The basic Frame * class makes no use of this attribute, but specialised subclasses of * Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame * classes use it. The default value is zero. * * The value is stored internally in radians, but is converted to and * from a degrees string for access. Some example input formats are: * "22:19:23.2", "22 19 23.2", "22:19.387", "22.32311", "N22.32311", * "-45.6", "S45.6". As indicated, the sign of the latitude can * optionally be indicated using characters "N" and "S" in place of the * usual "+" and "-". When converting the stored value to a string, the * format "[s]dd:mm:ss.ss" is used, when "[s]" is "N" or "S". * Applicability: * Frame * All Frames have this attribute. * SpecFrame * Together with the ObsLon, Epoch, RefRA and RefDec attributes, * it defines the Doppler shift introduced by the observers diurnal * motion around the earths axis, which is needed when converting to * or from the topocentric standard of rest. The maximum velocity * error which can be caused by an incorrect value is 0.5 km/s. The * default value for the attribute is zero. * TimeFrame * Together with the ObsLon attribute, it is used when converting * between certain time scales (TDB, TCB, LMST, LAST) *att-- */ /* The geodetic latitude of the observer (radians). Clear the ObsLat value by setting it to AST__BAD, returning zero as the default value. Any value is acceptable. */ astMAKE_CLEAR(Frame,ObsLat,obslat,AST__BAD) astMAKE_GET(Frame,ObsLat,double,0.0,((this->obslat!=AST__BAD)?this->obslat:0.0)) astMAKE_SET(Frame,ObsLat,double,obslat,value) astMAKE_TEST(Frame,ObsLat,(this->obslat!=AST__BAD)) /* *att++ * Name: * ObsAlt * Purpose: * The geodetic altitude of the observer * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the geodetic altitude of the observer, in * metres, relative to the IAU 1976 reference ellipsoid. The basic Frame * class makes no use of this attribute, but specialised subclasses of * Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame * classes use it. The default value is zero. * Applicability: * Frame * All Frames have this attribute. * SpecFrame * Together with the ObsLon, Epoch, RefRA and RefDec attributes, * it defines the Doppler shift introduced by the observers diurnal * motion around the earths axis, which is needed when converting to * or from the topocentric standard of rest. The maximum velocity * error which can be caused by an incorrect value is 0.5 km/s. The * default value for the attribute is zero. * TimeFrame * Together with the ObsLon attribute, it is used when converting * between certain time scales (TDB, TCB, LMST, LAST) *att-- */ /* The geodetic altitude of the observer (metres). Clear the ObsAlt value by setting it to AST__BAD, returning zero as the default value. Any value is acceptable. */ astMAKE_CLEAR(Frame,ObsAlt,obsalt,AST__BAD) astMAKE_GET(Frame,ObsAlt,double,0.0,((this->obsalt!=AST__BAD)?this->obsalt:0.0)) astMAKE_SET(Frame,ObsAlt,double,obsalt,value) astMAKE_TEST(Frame,ObsAlt,(this->obsalt!=AST__BAD)) /* *att++ * Name: * ObsLon * Purpose: * The geodetic longitude of the observer * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the geodetic (or equivalently, geocentric) * longitude of the observer, in degrees, measured positive eastwards. * See also attribute ObsLat. The basic Frame class makes no use of this * attribute, but specialised subclasses of Frame may use it. For instance, * the SpecFrame, SkyFrame and TimeFrame classes use it. The default value * is zero. * * The value is stored internally in radians, but is converted to and * from a degrees string for access. Some example input formats are: * "155:19:23.2", "155 19 23.2", "155:19.387", "155.32311", "E155.32311", * "-204.67689", "W204.67689". As indicated, the sign of the longitude can * optionally be indicated using characters "E" and "W" in place of the * usual "+" and "-". When converting the stored value to a string, the * format "[s]ddd:mm:ss.ss" is used, when "[s]" is "E" or "W" and the * numerical value is chosen to be less than 180 degrees. * Applicability: * Frame * All Frames have this attribute. * SpecFrame * Together with the ObsLon, Epoch, RefRA and RefDec attributes, * it defines the Doppler shift introduced by the observers diurnal * motion around the earths axis, which is needed when converting to * or from the topocentric standard of rest. The maximum velocity * error which can be caused by an incorrect value is 0.5 km/s. The * default value for the attribute is zero. * TimeFrame * Together with the ObsLon attribute, it is used when converting * between certain time scales (TDB, TCB, LMST, LAST) *att-- */ /* The geodetic longitude of the observer (radians). Clear the ObsLon value by setting it to AST__BAD, returning zero as the default value. Any value is acceptable. */ astMAKE_CLEAR(Frame,ObsLon,obslon,AST__BAD) astMAKE_GET(Frame,ObsLon,double,0.0,((this->obslon!=AST__BAD)?this->obslon:0.0)) astMAKE_SET(Frame,ObsLon,double,obslon,value) astMAKE_TEST(Frame,ObsLon,(this->obslon!=AST__BAD)) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for Frame objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for Frame objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstFrame *in; /* Pointer to input Frame */ AstFrame *out; /* Pointer to output Frame */ int axis; /* Loop counter for axes */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output Frames. */ in = (AstFrame *) objin; out = (AstFrame *) objout; /* For safety, first clear any references to the input memory from the output Frame. */ out->axis = NULL; out->domain = NULL; out->perm = NULL; out->title = NULL; out->variants = NULL; /* If necessary, allocate memory in the output Frame and store a copy of the input Title and Domain strings. */ if ( in->title ) out->title = astStore( NULL, in->title, strlen( in->title ) + (size_t) 1 ); if ( in->domain ) out->domain = astStore( NULL, in->domain, strlen( in->domain ) + (size_t) 1 ); /* Allocate memory to hold the output Frame's Axis object pointers and its axis permutation array. */ out->axis = astMalloc( sizeof( AstAxis * ) * (size_t) in->naxes ); out->perm = astMalloc( sizeof( int ) * (size_t) in->naxes ); /* Make a copy of each of the input Frame's Axis objects, storing the pointer to each new Axis in the memory just allocated. Also copy the axis permutation array. */ if ( astOK ) { for ( axis = 0; axis < in->naxes; axis++ ) { out->axis[ axis ] = astCopy( in->axis[ axis ] ); out->perm[ axis ] = in->perm[ axis ]; } /* If an error occurred while copying the Axis objects, then loop through the resulting array of pointers and make sure that all of them are properly annulled. */ if ( !astOK ) { for ( axis = 0; axis < in->naxes; axis++ ) { out->axis[ axis ] = astAnnul( out->axis[ axis ] ); } } } /* Other remaining objects */ if( in->variants ) out->variants = astCopy( in->variants ); /* If an error occurred, free any allocated memory. */ if ( !astOK ) { out->axis = astFree( out->axis ); out->domain = astFree( out->domain ); out->perm = astFree( out->perm ); out->title = astFree( out->title ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for Frame objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for Frame objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstFrame *this; /* Pointer to Frame */ int axis; /* Loop counter for Frame axes */ /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) obj; /* Free the memory used for the Title and Domain strings if necessary. */ this->title = astFree( this->title ); this->domain = astFree( this->domain ); /* If memory has been allocated to store pointers to the Frame's Axis objects, annul each of these pointers and then free the memory. */ if ( this->axis ) { for ( axis = 0; axis < this->naxes; axis++ ) { this->axis[ axis ] = astAnnul( this->axis[ axis ] ); } this->axis = astFree( this->axis ); } /* Free memory used for the axis permutation array if necessary. */ this->perm = astFree( this->perm ); /* Other objects. */ if( this->variants ) this->variants = astAnnul( this->variants ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for Frame objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the Frame class to an output Channel. * Parameters: * this * Pointer to the Frame whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define COMMENT_LEN 150 /* Maximum length of a comment string */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstAxis *ax; /* Pointer to Axis */ AstFrame *cfrm; /* Pointer to FrameSet's current Frame */ AstFrame *this; /* Pointer to the Frame structure */ AstSystemType system; /* System code */ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */ char key[ KEY_LEN + 1 ]; /* Buffer for keywords */ const char *sval; /* Pointer to string value */ const char *lab; /* Pointer to unit label */ const int *perm; /* Pointer to axis permutation array */ double dval; /* Double attibute value */ int *invperm; /* Pointer to inverse permutation array */ int axis; /* Loop counter for Frame axes */ int bessyr; /* Format as Besselian years (else Julian) */ int digits_set; /* Digits set explicitly for any axis? */ int full; /* Full attribute value */ int full_set; /* Full attribute set? */ int helpful; /* Helpful to show value even if not set? */ int isFrame; /* Is this a simple Frame? */ int ival; /* Integer value */ int naxes; /* Number of Frame axes */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the Frame structure. */ this = (AstFrame *) this_object; /* Determine the number of Frame axes and a pointer to the Frame's axis permutation array (using methods, to allow for any over-ride by a derived class). */ naxes = astGetNaxes( this ); perm = astGetPerm( this ); /* Some default attribute values are not helpful for a simple Frame. Note if this is a simple Frame, or if it is a FrameSet with a simple Frame as its current Frame., or if it is a CmpFrame. */ if( !strcmp( astGetClass( this ), "Frame" ) ) { isFrame = 1; } else if( astIsAFrameSet( this ) ) { cfrm = astGetFrame( (AstFrameSet *) this, AST__CURRENT ); isFrame = !strcmp( astGetClass( cfrm ), "Frame" ); cfrm = astAnnul( cfrm ); } else if( astIsACmpFrame( this ) ) { isFrame = 1; } else { isFrame = 0; } /* Allocate memory to hold an inverse axis permutation array and generate this array from the forward permutation values. This will be used to determine which axis should be enquired about (using possibly over-ridden methods) to obtain data to correspond with a particular internal value (i.e. instance variable) relating to an axis. This step is needed so that the effect of any axis permutation can be un-done before values are written out, as output values are written by this function in un-permuted order. */ invperm = astMalloc( sizeof( int ) * (size_t) naxes ); if ( astOK ) { for ( axis = 0; axis < naxes; axis++ ) invperm[ perm[ axis ] ] = axis; /* Write out values representing the instance variables for the Frame class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Title. */ /* ------ */ set = TestTitle( this, status ); sval = set ? GetTitle( this, status ) : astGetTitle( this ); astWriteString( channel, "Title", set, 1, sval, "Title of coordinate system" ); /* Naxes. */ /* ------ */ set = ( this->naxes != 0 ); ival = set ? this->naxes : naxes; astWriteInt( channel, "Naxes", set, 1, ival, "Number of coordinate axes" ); /* Domain. */ /* ------- */ set = TestDomain( this, status ); sval = set ? GetDomain( this, status ) : astGetDomain( this ); /* Don't show an un-set Domain value if it is blank. */ helpful = ( sval && *sval ); astWriteString( channel, "Domain", set, helpful, sval, "Coordinate system domain" ); /* Epoch. */ /* ------ */ set = TestEpoch( this, status ); dval = set ? GetEpoch( this, status ) : astGetEpoch( this ); /* Convert MJD to Besselian or Julian years, depending on the value. */ bessyr = ( dval < palEpj2d( 1984.0 ) ); dval = bessyr ? palEpb( dval ) : palEpj( dval ); astWriteDouble( channel, "Epoch", set, !isFrame, dval, bessyr ? "Besselian epoch of observation" : "Julian epoch of observation" ); /* Label. */ /* ------ */ /* This, and some other, attributes are stored internally by the Frame's Axis objects, but are "re-packaged" by the Frame class to appear as Frame attributes. We treat them here like Frame attributes that are "un-set". There is a Label value for each Frame axis. */ for ( axis = 0; axis < naxes; axis++ ) { /* The inverse axis permutation array is used to obtain the axis index for astGetLabel. This reverses the effect of the Frame's axis permutation array and yields a default value appropriate to the axis with internal index "axis". */ sval = astGetLabel( this, invperm[ axis ] ); /* Create keyword and comment strings appropriate to each axis (converting to 1-based axis numbering) and write out the Label values. */ (void) sprintf( key, "Lbl%d", axis + 1 ); (void) sprintf( comment, "Label for axis %d", axis + 1 ); astWriteString( channel, key, 0, 1, sval, comment ); } /* Symbol. */ /* ------- */ /* There is a Symbol value for each Frame axis. These are handled in the same way as the Label values. */ for ( axis = 0; axis < naxes; axis++ ) { sval = astGetSymbol( this, invperm[ axis ] ); (void) sprintf( key, "Sym%d", axis + 1 ); (void) sprintf( comment, "Symbol for axis %d", axis + 1 ); astWriteString( channel, key, 0, 0, sval, comment ); } /* System. */ /* ------- */ set = TestSystem( this, status ); system = set ? GetSystem( this, status ) : astGetSystem( this ); /* If set, convert explicitly to a string for the external representation. */ if ( set ) { if ( astOK ) { sval = astSystemString( this, system ); /* Report an error if the System value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "astWrite(%s): Corrupt %s contains invalid " "System identification code (%d).", status, astGetClass( channel ), astGetClass( this ), (int) system ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "system" ); } /* Write out the value. */ astWriteString( channel, "System", set, !isFrame, sval, "Coordinate system type" ); /* AlignSystem. */ /* ------------ */ set = TestAlignSystem( this, status ); system = set ? GetAlignSystem( this, status ) : astGetAlignSystem( this ); /* If set, convert explicitly to a string for the external representation. */ if ( set ) { if ( astOK ) { sval = astSystemString( this, system ); /* Report an error if the AlignSystem value was not recognised. */ if ( !sval ) { astError( AST__SCSIN, "astWrite(%s): Corrupt %s contains invalid " "AlignSystem identification code (%d).", status, astGetClass( channel ), astGetClass( this ), (int) system ); } } /* If not set, use astGetAttrib which returns a string value using (possibly over-ridden) methods. */ } else { sval = astGetAttrib( this_object, "alignsystem" ); } /* Write out the value. */ astWriteString( channel, "AlSys", set, 0, sval, "Alignment coordinate system" ); /* Unit. */ /* ----- */ /* There is a Unit value for each axis. */ for ( axis = 0; axis < naxes; axis++ ) { sval = astGetUnit( this, invperm[ axis ] ); /* Get any label associated with the unit string. */ lab = astUnitLabel( sval ); /* Construct a comment including the above label (but only if it is not the same as the unit string) . */ if( lab && strcmp( lab, sval ) ) { (void) sprintf( comment, "Units for axis %d (%s)", axis + 1, lab ); } else { (void) sprintf( comment, "Units for axis %d", axis + 1 ); } /* Show the Unit value if it is not blank. */ helpful = ( sval && *sval ); (void) sprintf( key, "Uni%d", axis + 1 ); astWriteString( channel, key, 0, helpful, sval, comment ); } /* Digits. */ /* ------- */ /* There is a Digits value for each axis... */ digits_set = 0; for ( axis = 0; axis < naxes; axis++ ) { /* Obtain the axis Digits value, using the Frame's Digits value as a default. */ ax = astGetAxis( this, invperm[ axis ] ); set = astTestAxisDigits( ax ); ival = set ? astGetAxisDigits( ax ) : astGetDigits( this ); ax = astAnnul( ax ); /* Show the value if it is set for the axis (i.e. if it differs from the default for the whole Frame) and note if any such value is set. */ helpful = set; if ( set ) digits_set = 1; (void) sprintf( key, "Dig%d", axis + 1 ); (void) sprintf( comment, "Individual precision for axis %d", axis + 1 ); astWriteInt( channel, key, 0, helpful, ival, comment ); } /* There is also a Digits value for the Frame as a whole... */ set = TestDigits( this, status ); /* Show the value (even if not set) if an explicit Digits value has been set for any axis (above). */ helpful = digits_set; ival = set ? GetDigits( this, status ) : astGetDigits( this ); astWriteInt( channel, "Digits", set, helpful, ival, "Default formatting precision" ); /* Format. */ /* ------- */ /* There is a Format value for each axis. */ for ( axis = 0; axis < naxes; axis++ ) { sval = astGetFormat( this, invperm[ axis ] ); /* Show the Format value if the Digits value is set for an individual axis. */ ax = astGetAxis( this, invperm[ axis ] ); helpful = astTestAxisDigits( ax ); ax = astAnnul( ax ); (void) sprintf( key, "Fmt%d", axis + 1 ); (void) sprintf( comment, "Format specifier for axis %d", axis + 1 ); astWriteString( channel, key, 0, helpful, sval, comment ); } /* Direction. */ /* ---------- */ /* There is a Direction value for each axis. */ for ( axis = 0; axis < naxes; axis++ ) { ival = astGetDirection( this, invperm[ axis ] ); /* Show the value if it is zero. */ helpful = ( ival == 0 ); (void) sprintf( key, "Dir%d", axis + 1 ); (void) sprintf( comment, ival ? "Plot axis %d in conventional direction" : "Plot axis %d in reverse direction", axis + 1 ); astWriteInt( channel, key, 0, helpful, ival, comment ); } /* Bottom. */ /* ------- */ /* There is a Bottom value for each axis. */ for ( axis = 0; axis < naxes; axis++ ) { dval = astGetBottom( this, invperm[ axis ] ); /* Show the value if it is zero. */ helpful = ( dval != -DBL_MAX ); (void) sprintf( key, "Bot%d", axis + 1 ); astWriteDouble( channel, key, 0, helpful, dval, "Lowest legal axis value"); } /* Top. */ /* ------- */ /* There is a Top value for each axis. */ for ( axis = 0; axis < naxes; axis++ ) { dval = astGetTop( this, invperm[ axis ] ); /* Show the value if it is zero. */ helpful = ( dval != DBL_MAX ); (void) sprintf( key, "Top%d", axis + 1 ); astWriteDouble( channel, key, 0, helpful, dval, "Highest legal axis value"); } /* PreserveAxes. */ /* ------------- */ set = TestPreserveAxes( this, status ); ival = set ? GetPreserveAxes( this, status ) : astGetPreserveAxes( this ); astWriteInt( channel, "Presrv", set, 0, ival, ival ? "Preserve target axes" : "Don't preserve target axes" ); /* Permute. */ /* -------- */ set = TestPermute( this, status ); ival = set ? GetPermute( this, status ) : astGetPermute( this ); astWriteInt( channel, "Permut", set, 0, ival, ival ? "Axes may be permuted to match" : "Axes may not be permuted match" ); /* MinAxes. */ /* -------- */ set = TestMinAxes( this, status ); ival = set ? GetMinAxes( this, status ) : astGetMinAxes( this ); astWriteInt( channel, "MinAx", set, 0, ival, "Minimum number of axes to match" ); /* MaxAxes. */ /* -------- */ set = TestMaxAxes( this, status ); ival = set ? GetMaxAxes( this, status ) : astGetMaxAxes( this ); astWriteInt( channel, "MaxAx", set, 0, ival, "Maximum number of axes to match" ); /* MatchEnd. */ /* --------- */ set = TestMatchEnd( this, status ); ival = set ? GetMatchEnd( this, status ) : astGetMatchEnd( this ); astWriteInt( channel, "MchEnd", set, 0, ival, ival ? "Match final target axes" : "Match initial target axes" ); /* ObsLat. */ /* ------- */ set = TestObsLat( this, status ); dval = set ? GetObsLat( this, status ) : astGetObsLat( this ); astWriteDouble( channel, "ObsLat", set, 0, dval, "Observers geodetic latitude (rads)" ); /* ObsLon. */ /* ------- */ set = TestObsLon( this, status ); dval = set ? GetObsLon( this, status ) : astGetObsLon( this ); astWriteDouble( channel, "ObsLon", set, 0, dval, "Observers geodetic longitude (rads)" ); /* ObsAlt. */ /* ------- */ set = TestObsAlt( this, status ); dval = set ? GetObsAlt( this, status ) : astGetObsAlt( this ); astWriteDouble( channel, "ObsAlt", set, 0, dval, "Observers geodetic altitude (metres)" ); /* Dut1*/ /* ---- */ set = TestDut1( this, status ); dval = set ? GetDut1( this, status ) : astGetDut1( this ); astWriteDouble( channel, "Dut1", set, 0, dval, "UT1-UTC in seconds" ); /* ActiveUnit. */ /* ----------- */ if( astTestActiveUnit( this ) ) { ival = astGetActiveUnit( this ); astWriteInt( channel, "ActUnt", 1, 0, ival, ival ? "Unit strings affects alignment" : "Unit strings do not affect alignment" ); } /* Axis permutation array. */ /* ----------------------- */ /* Write out the axis permutation array value for each axis, converting to 1-based axis numbering. */ for ( axis = 0; axis < this->naxes; axis++ ) { set = ( this->perm[ axis ] != axis ); ival = this->perm[ axis ] + 1; /* Create a keyword and comment appropriate to the axis. */ (void) sprintf( key, "Prm%d", axis + 1 ); if ( set ) { (void) sprintf( comment, "Axis %d permuted to use internal axis %d", axis + 1, ival ); } else { (void) sprintf( comment, "Axis %d not permuted", axis + 1 ); } astWriteInt( channel, key, set, 0, ival, comment ); } /* Axis Objects. */ /* ------------- */ /* Temporarily set the Channel's Full attribute to -1 (unless it is +1 to start with), remembering the original setting. This prevents any unnecessary "un-set" Axis values being output that would otherwise simply duplicate the Frame's attributes which have already been written. "Set" Axis values are still written, however (and all values are written if Full is set to 1). */ full_set = astTestFull( channel ); full = astGetFull( channel ); if ( full <= 0 ) astSetFull( channel, -1 ); /* Handle each axis in turn. */ for ( axis = 0; axis < this->naxes; axis++ ) { /* Create a keyword and comment appropriate to the axis (converting to 1-based axis numbering). */ (void) sprintf( key, "Ax%d", axis + 1 ); (void) sprintf( comment, "Axis number %d", axis + 1 ); /* Write out the axis Object description. */ astWriteObject( channel, key, 1, 0, this->axis[ axis ], comment ); } /* Restore the Channel's original Full attribute setting. */ if ( full_set ) { astSetFull( channel, full ); } else { astClearFull( channel ); } /* Free the inverse axis permutation array. */ invperm = astFree( invperm ); /* Variants */ /* ------- */ if( this->variants ) astWriteObject( channel, "Vrnts", 1, 0, this->variants, "Variant Frames" ); } /* Undefine macros local to this function. */ #undef COMMENT_LEN #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAFrame and astCheckFrame functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(Frame,Mapping) astMAKE_CHECK(Frame) AstFrame *astFrame_( int naxes, const char *options, int *status, ...) { /* *+ * Name: * astFrame * Purpose: * Create a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * AstFrame *astFrame( int naxes, const char *options, int *status, ... ) * Class Membership: * Frame constructor. * Description: * This function creates a new Frame and optionally initialises its * attributes. * Parameters: * naxes * The number of Frame axes. * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new Frame. The syntax used is the same as * for the astSet method and may include "printf" format * specifiers identified by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then * an optional list of arguments may follow it in order to * supply values to be substituted for these specifiers. The * rules for supplying these are identical to those for the * astSet method (and for the C "printf" function). * Returned Value: * A pointer to the new Frame. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic Frame constructor which is * available via the protected interface to the Frame class. A * public interface is provided by the astFrameId_ function. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *new; /* Pointer to new Frame */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the Frame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab, "Frame", naxes ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Frame's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new Frame. */ return new; } AstFrame *astInitFrame_( void *mem, size_t size, int init, AstFrameVtab *vtab, const char *name, int naxes, int *status ) { /* *+ * Name: * astInitFrame * Purpose: * Initialise a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * AstFrame *astInitFrame( void *mem, size_t size, int init, * AstFrameVtab *vtab, const char *name, * int naxes ) * Class Membership: * Frame initialiser. * Description: * This function is provided for use by class implementations to initialise * a new Frame object. It allocates memory (if necessary) to accommodate * the Frame plus any additional data associated with the derived class. * It then initialises a Frame structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a Frame at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the Frame is to be created. This * must be of sufficient size to accommodate the Frame data * (sizeof(Frame)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the Frame (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the Frame * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the Frame's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new Frame. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * naxes * The number of Frame axes. * Returned Value: * A pointer to the new Frame. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstFrame *new; /* Pointer to new Frame */ int axis; /* Loop counter for Frame axes */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitFrameVtab( vtab, name ); /* Initialise. */ new = NULL; /* Check the number of axes for validity, reporting an error if necessary. */ if ( naxes < 0 ) { astError( AST__NAXIN, "astInitFrame(%s): Number of axes (%d) is " "invalid - this number should not be negative.", status, name, naxes ); /* Initialise a Mapping structure (the parent class) as the first component within the Frame structure, allocating memory if necessary. Set the number of input/output coordinates to zero (the astGetNin and astGetNout methods are over-ridden by the Frame class to provide values for these that are equal to the number of Frame axes). */ } else { new = (AstFrame *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, 0, 0, 1, 1 ); if ( astOK ) { /* Initialise the Frame data. */ /* ----------------------------- */ /* Set the number of Frame axes. */ new->naxes = naxes; /* Initialise all attributes to their "undefined" values. */ new->digits = -INT_MAX; new->domain = NULL; new->epoch = AST__BAD; new->match_end = -INT_MAX; new->max_axes = -INT_MAX; new->min_axes = -INT_MAX; new->permute = -INT_MAX; new->preserve_axes = -INT_MAX; new->title = NULL; new->system = AST__BADSYSTEM; new->alignsystem = AST__BADSYSTEM; new->active_unit = -INT_MAX; new->obsalt = AST__BAD; new->obslat = AST__BAD; new->obslon = AST__BAD; new->dut1 = AST__BAD; new->flags = 0; new->variants = NULL; /* Allocate memory to store pointers to the Frame's Axis objects and to store its axis permutation array. */ new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) naxes ); new->perm = astMalloc( sizeof( int ) * (size_t) naxes ); /* Create a new Axis object to describe each axis of the Frame and store the resulting pointers in the memory allocated above. Also initialise the axis permutation array so that the axes appear in their natural order. */ if ( astOK ) { for ( axis = 0; axis < naxes; axis++ ) { new->axis[ axis ] = astAxis( "", status ); new->perm[ axis ] = axis; } /* If an error occurred while creating the Axis objects, scan through the array of pointers to them again to ensure that they are all correctly annulled. */ if ( !astOK ) { for ( axis = 0; axis < naxes; axis++ ) { new->axis[ axis ] = astAnnul( new->axis[ axis ] ); } } } /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new object. */ return new; } AstFrame *astLoadFrame_( void *mem, size_t size, AstFrameVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadFrame * Purpose: * Load a Frame. * Type: * Protected function. * Synopsis: * #include "frame.h" * AstFrame *astLoadFrame( void *mem, size_t size, * AstFrameVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * Frame loader. * Description: * This function is provided to load a new Frame using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * Frame structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a Frame at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the Frame is to be loaded. * This must be of sufficient size to accommodate the Frame data * (sizeof(Frame)) plus any data used by derived classes. If a * value of NULL is given, this function will allocate the * memory itself using the "size" parameter to determine its * size. * size * The amount of memory used by the Frame (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the Frame structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstFrame) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new Frame. If this is NULL, a pointer to * the (static) virtual function table for the Frame class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "Frame" is used instead. * Returned Value: * A pointer to the new Frame. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstFrame *new; /* Pointer to the new Frame */ char *sval; /* Pointer to string value */ char key[ KEY_LEN + 1 ]; /* Buffer for keywords */ double dval; /* DOuble attribute value */ int axis; /* Loop counter for axes */ int ival; /* Integer value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this Frame. In this case the Frame belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstFrame ); vtab = &class_vtab; name = "Frame"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitFrameVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built Frame. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Assign values for transient components that are not included in the Frame dump */ new->flags = 0; /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "Frame" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Naxes. */ /* ------ */ /* Obtain the number of Frame axes and allocate memory for the arrays which hold axis information. */ new->naxes = astReadInt( channel, "naxes", 0 ); if ( new->naxes < 0 ) new->naxes = 0; new->perm = astMalloc( sizeof( int ) * (size_t) new->naxes ); new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) new->naxes ); /* If an error occurred, ensure that any allocated memory is freed. */ if ( !astOK ) { new->perm = astFree( new->perm ); new->axis = astFree( new->axis ); /* Otherwise, initialise the array of Axis pointers. */ } else { for ( axis = 0; axis < new->naxes; axis++ ) new->axis[ axis ] = NULL; /* Now obtain those input values which are required for each axis... */ for ( axis = 0; axis < new->naxes; axis++ ) { /* Axis object. */ /* ------------ */ /* This must be read first, so that it can hold the other axis values obtained below. */ /* Create a keyword appropriate to this axis. */ (void) sprintf( key, "ax%d", axis + 1 ); /* Read the Axis object. If none was read, provide a default Axis instead. */ new->axis[ axis ] = astReadObject( channel, key, NULL ); if ( !new->axis[ axis ] ) new->axis[ axis ] = astAxis( "", status ); /* Label. */ /* ------ */ /* Read the Label string for each axis. If a value is obtained, use it to set the Label attribute for the axis. Free the memory holding the string when no longer needed. */ (void) sprintf( key, "lbl%d", axis + 1 ); sval = astReadString( channel, key, NULL ); if ( sval ) { astSetAxisLabel( new->axis[ axis ], sval ); sval = astFree( sval ); } /* Symbol. */ /* ------- */ (void) sprintf( key, "sym%d", axis + 1 ); sval = astReadString( channel, key, NULL ); if ( sval ) { astSetAxisSymbol( new->axis[ axis ], sval ); sval = astFree( sval ); } /* Format. */ /* ------- */ (void) sprintf( key, "fmt%d", axis + 1 ); sval = astReadString( channel, key, NULL ); if ( sval ) { astSetAxisFormat( new->axis[ axis ], sval ); sval = astFree( sval ); } /* Unit. */ /* ----- */ (void) sprintf( key, "uni%d", axis + 1 ); sval = astReadString( channel, key, NULL ); if ( sval ) { astSetAxisUnit( new->axis[ axis ], sval ); sval = astFree( sval ); } /* Direction. */ /* ---------- */ (void) sprintf( key, "dir%d", axis + 1 ); ival = astReadInt( channel, key, -INT_MAX ); if ( ival != -INT_MAX ) { astSetAxisDirection( new->axis[ axis ], ival ); } /* Top. */ /*----- */ (void) sprintf( key, "top%d", axis + 1 ); dval = astReadDouble( channel, key, AST__BAD ); if ( dval != AST__BAD ) { astSetAxisTop( new->axis[ axis ], dval ); } /* Bottom. */ /*----- -- */ (void) sprintf( key, "bot%d", axis + 1 ); dval = astReadDouble( channel, key, AST__BAD ); if ( dval != AST__BAD ) { astSetAxisBottom( new->axis[ axis ], dval ); } /* Digits. */ /* ------- */ (void) sprintf( key, "dig%d", axis + 1 ); ival = astReadInt( channel, key, -INT_MAX ); if ( ival != -INT_MAX ) { astSetAxisDigits( new->axis[ axis ], ival ); } /* Axis permutation array. */ /* ----------------------- */ /* Convert from 1-based to zero-based axis numbering at this point. The default is the "un-permuted" value. */ sprintf( key, "prm%d", axis + 1 ); new->perm[ axis ] = astReadInt( channel, key, axis + 1 ) - 1; /* Quit looping if an error occurs. */ if ( !astOK ) break; } /* The remaining values are not associated with particular axes... */ /* Title. */ /* ------ */ new->title = astReadString( channel, "title", NULL ); /* Domain. */ /* ------- */ new->domain = astReadString( channel, "domain", NULL ); /* Epoch. */ /* ------ */ /* Interpret this as Besselian or Julian depending on its value. */ new->epoch = astReadDouble( channel, "epoch", AST__BAD ); if ( TestEpoch( new, status ) ) { SetEpoch( new, ( new->epoch < 1984.0 ) ? palEpb2d( new->epoch ) : palEpj2d( new->epoch ), status ); } /* Digits. */ /* ------- */ /* This is the value that applies to the Frame as a whole. */ new->digits = astReadInt( channel, "digits", -INT_MAX ); if ( TestDigits( new, status ) ) SetDigits( new, new->digits, status ); /* PreserveAxes. */ /* ------------- */ new->preserve_axes = astReadInt( channel, "presrv", -INT_MAX ); if ( TestPreserveAxes( new, status ) ) { SetPreserveAxes( new, new->preserve_axes, status ); } /* Permute. */ /* -------- */ new->permute = astReadInt( channel, "permut", -INT_MAX ); if ( TestPermute( new, status ) ) SetPermute( new, new->permute, status ); /* MinAxes. */ /* -------- */ new->min_axes = astReadInt( channel, "minax", -INT_MAX ); if ( TestMinAxes( new, status ) ) SetMinAxes( new, new->min_axes, status ); /* MaxAxes. */ /* -------- */ new->max_axes = astReadInt( channel, "maxax", -INT_MAX ); if ( TestMaxAxes( new, status ) ) SetMaxAxes( new, new->max_axes, status ); /* MatchEnd. */ /* --------- */ new->match_end = astReadInt( channel, "mchend", -INT_MAX ); if ( TestMatchEnd( new, status ) ) SetMatchEnd( new, new->match_end, status ); /* ObsLat. */ /* ------- */ new->obslat = astReadDouble( channel, "obslat", AST__BAD ); if ( TestObsLat( new, status ) ) SetObsLat( new, new->obslat, status ); /* ObsLon. */ /* ------- */ new->obslon = astReadDouble( channel, "obslon", AST__BAD ); if ( TestObsLon( new, status ) ) SetObsLon( new, new->obslon, status ); /* ObsAlt. */ /* ------- */ new->obsalt = astReadDouble( channel, "obsalt", AST__BAD ); if ( TestObsAlt( new, status ) ) SetObsAlt( new, new->obsalt, status ); /* Dut1. */ /* ---- */ new->dut1 = astReadDouble( channel, "dut1", AST__BAD ); if ( TestDut1( new, status ) ) SetDut1( new, new->dut1, status ); /* ActiveUnit. */ /* ----------- */ new->active_unit = astReadInt( channel, "actunt", -INT_MAX ); if ( TestActiveUnit( new, status ) ) SetActiveUnit( new, new->active_unit, status ); /* System. */ /* ------- */ /* Set the default and read the external representation as a string. */ new->system = AST__BADSYSTEM; sval = astReadString( channel, "system", NULL ); /* If a value was read, convert from a string to a System code. */ if ( sval ) { if ( astOK ) { new->system = astSystemCode( new, sval ); /* Report an error if the value wasn't recognised. */ if ( new->system == AST__BADSYSTEM ) { astError( AST__ATTIN, "astRead(%s): Invalid System description " "\"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* AlignSystem. */ /* ------------ */ /* Set the default and read the external representation as a string. */ new->alignsystem = AST__BADSYSTEM; sval = astReadString( channel, "alsys", NULL ); /* If a value was read, convert from a string to a System code. */ if ( sval ) { if ( astOK ) { new->alignsystem = astSystemCode( new, sval ); /* Report an error if the value wasn't recognised. */ if ( new->alignsystem == AST__BADSYSTEM ) { astError( AST__ATTIN, "astRead(%s): Invalid AlignSystem description " "\"%s\".", status, astGetClass( channel ), sval ); } } /* Free the string value. */ sval = astFree( sval ); } /* Variants. */ /* -------- */ new->variants = astReadObject( channel, "vrnts", NULL ); } /* If an error occurred, clean up by deleting the new Frame. */ if ( !astOK ) new = astDelete( new ); } /* Return the new Frame pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ const char *astAbbrev_( AstFrame *this, int axis, const char *fmt, const char *str1, const char *str2, int *status ) { if ( !astOK ) return str2; return (**astMEMBER(this,Frame,Abbrev))( this, axis, fmt, str1, str2, status ); } int astFields_( AstFrame *this, int axis, const char *fmt, const char *str, int maxfld, char **fields, int *nc, double *val, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,Fields))( this, axis, fmt, str, maxfld, fields, nc, val, status ); } void astCheckPerm_( AstFrame *this, const int *perm, const char *method, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,CheckPerm))( this, perm, method, status ); } AstPointSet *astResolvePoints_( AstFrame *this, const double point1[], const double point2[], AstPointSet *in, AstPointSet *out, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,ResolvePoints))( this, point1, point2, in, out, status ); } AstLineDef *astLineDef_( AstFrame *this, const double start[2], const double end[2], int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,LineDef))( this, start, end, status ); } int astLineCrossing_( AstFrame *this, AstLineDef *l1, AstLineDef *l2, double **cross, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,LineCrossing))( this, l1, l2, cross, status ); } void astLineOffset_( AstFrame *this, AstLineDef *line, double par, double prp, double point[2], int *status ){ if ( !astOK ) return; (**astMEMBER(this,Frame,LineOffset))( this, line, par, prp, point, status ); } int astLineContains_( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,LineContains))( this, l, def, point, status ); } AstFrameSet *astConvert_( AstFrame *from, AstFrame *to, const char *domainlist, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(from,Frame,Convert))( from, to, domainlist, status ); } AstFrameSet *astConvertX_( AstFrame *to, AstFrame *from, const char *domainlist, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(to,Frame,ConvertX))( to, from, domainlist, status ); } double astAngle_( AstFrame *this, const double a[], const double b[], const double c[], int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,Angle))( this, a, b, c, status ); } int astGetActiveUnit_( AstFrame *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,GetActiveUnit))( this, status ); } int astTestActiveUnit_( AstFrame *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,TestActiveUnit))( this, status ); } void astSetActiveUnit_( AstFrame *this, int value, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,SetActiveUnit))( this, value, status ); } double astDistance_( AstFrame *this, const double point1[], const double point2[], int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,Distance))( this, point1, point2, status ); } AstFrameSet *astFindFrame_( AstFrame *target, AstFrame *template, const char *domainlist, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(target,Frame,FindFrame))( target, template, domainlist, status ); } void astMatchAxes_( AstFrame *frm1, AstFrame *frm2, int *axes, int *status ) { if ( !astOK ) return; (**astMEMBER(frm1,Frame,MatchAxes))( frm1, frm2, axes, status ); } void astMatchAxesX_( AstFrame *frm2, AstFrame *frm1, int *axes, int *status ) { if ( !astOK ) return; (**astMEMBER(frm2,Frame,MatchAxesX))( frm2, frm1, axes, status ); } const char *astFormat_( AstFrame *this, int axis, double value, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,Format))( this, axis, value, status ); } double astGap_( AstFrame *this, int axis, double gap, int *ntick, int *status ) { if ( !astOK ) return 0.0; return (**astMEMBER(this,Frame,Gap))( this, axis, gap, ntick, status ); } AstAxis *astGetAxis_( AstFrame *this, int axis, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,GetAxis))( this, axis, status ); } int astGetNaxes_( AstFrame *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,GetNaxes))( this, status ); } const int *astGetPerm_( AstFrame *this, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,GetPerm))( this, status ); } AstFrameSet *astGetFrameVariants_( AstFrame *this, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,GetFrameVariants))( this, status ); } void astSetFrameVariants_( AstFrame *this, AstFrameSet *variants, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,SetFrameVariants))( this, variants, status ); } int astMatch_( AstFrame *this, AstFrame *target, int matchsub, int **template_axes, int **target_axes, AstMapping **map, AstFrame **result, int *status ) { AstFrame *super_this; const char *dom; int match; if ( !astOK ) return 0; match = (**astMEMBER(this,Frame,Match))( this, target, matchsub, template_axes, target_axes, map, result, status ); /* If the template ("this") could not be used to probe the target, it may be because the template class is a more specialised form of the target class. E.g. a SkyFrame cannot directly be used to probe a Frame, but a Frame *can* be used to probe a SkyFrame. This means (for instance), that a basic Frame with Domain FRED cannot be aligned (using astConvert) with a CmpFrame with Domain FRED. This sort of alignment is often useful, so we try now to use the supplied template to probe a modified form of the target that has been cast into the same class as the template. This is only possible if the template class is a sub-class of the target class. Attempt to do the cast. */ if( ! match && matchsub ) { super_this = (AstFrame *) astCast( this, target ); /* If the cast was possible, fix the template Domain since the parent class may provide a different default Domain, and then invoke the Match method appropriate to the new template class (i.e. the target class). */ if( super_this ) { if( astTestDomain( target ) ) { dom = astGetDomain( this ); if( astChrLen( dom ) > 0 ) astSetDomain( super_this, dom ); } match = (**astMEMBER(super_this,Frame,Match))( super_this, target, matchsub, template_axes, target_axes, map, result, status ); super_this = astAnnul( super_this ); } } return match; } int astIsUnitFrame_( AstFrame *this, int *status ){ if ( !astOK ) return 0; return (**astMEMBER(this,Frame,IsUnitFrame))( this, status ); } void astNorm_( AstFrame *this, double value[], int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,Norm))( this, value, status ); } void astNormBox_( AstFrame *this, double lbnd[], double ubnd[], AstMapping *reg, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,NormBox))( this, lbnd, ubnd, reg, status ); } double astAxDistance_( AstFrame *this, int axis, double v1, double v2, int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,AxDistance))( this, axis, v1, v2, status ); } double astAxOffset_( AstFrame *this, int axis, double v1, double dist, int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,AxOffset))( this, axis, v1, dist, status ); } AstPointSet *astFrameGrid_( AstFrame *this, int size, const double *lbnd, const double *ubnd, int *status ){ if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,FrameGrid))( this, size, lbnd, ubnd, status ); } void astOffset_( AstFrame *this, const double point1[], const double point2[], double offset, double point3[], int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,Offset))( this, point1, point2, offset, point3, status ); } double astAxAngle_( AstFrame *this, const double a[2], const double b[2], int axis, int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,AxAngle))( this, a, b, axis, status ); } double astOffset2_( AstFrame *this, const double point1[2], double angle, double offset, double point2[2], int *status ) { if ( !astOK ) return AST__BAD; return (**astMEMBER(this,Frame,Offset2))( this, point1, angle, offset, point2, status ); } void astIntersect_( AstFrame *this, const double a1[2], const double a2[2], const double b1[2], const double b2[2], double cross[2], int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,Intersect))( this, a1, a2, b1, b2, cross, status ); } void astOverlay_( AstFrame *template, const int *template_axes, AstFrame *result, int *status ) { if ( !astOK ) return; (**astMEMBER(template,Frame,Overlay))( template, template_axes, result, status ); } void astPermAxes_( AstFrame *this, const int perm[], int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,PermAxes))( this, perm, status ); } AstFrame *astPickAxes_( AstFrame *this, int naxes, const int axes[], AstMapping **map, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,PickAxes))( this, naxes, axes, map, status ); } void astPrimaryFrame_( AstFrame *this, int axis1, AstFrame **frame, int *axis2, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,PrimaryFrame))( this, axis1, frame, axis2, status ); } void astResolve_( AstFrame *this, const double point1[], const double point2[], const double point3[], double point4[], double *d1, double *d2, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,Resolve))( this, point1, point2, point3, point4, d1, d2, status ); } void astSetAxis_( AstFrame *this, int axis, AstAxis *newaxis, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,SetAxis))( this, axis, newaxis, status ); } void astSetUnit_( AstFrame *this, int axis, const char *value, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,SetUnit))( this, axis, value, status ); } void astClearUnit_( AstFrame *this, int axis, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,ClearUnit))( this, axis, status ); } int astSubFrame_( AstFrame *target, AstFrame *template, int result_naxes, const int *target_axes, const int *template_axes, AstMapping **map, AstFrame **result, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(target,Frame,SubFrame))( target, template, result_naxes, target_axes, template_axes, map, result, status ); } int astUnformat_( AstFrame *this, int axis, const char *string, double *value, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,Unformat))( this, axis, string, value, status ); } int astValidateAxis_( AstFrame *this, int axis, int fwd, const char *method, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,ValidateAxis))( this, axis, fwd, method, status ); } void astValidateAxisSelection_( AstFrame *this, int naxes, const int *axes, const char *method, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,ValidateAxisSelection))( this, naxes, axes, method, status ); } AstSystemType astValidateSystem_( AstFrame *this, AstSystemType system, const char *method, int *status ) { if ( !astOK ) return AST__BADSYSTEM; return (**astMEMBER(this,Frame,ValidateSystem))( this, system, method, status ); } AstSystemType astSystemCode_( AstFrame *this, const char *system, int *status ) { if ( !astOK ) return AST__BADSYSTEM; return (**astMEMBER(this,Frame,SystemCode))( this, system, status ); } const char *astSystemString_( AstFrame *this, AstSystemType system, int *status ) { if ( !astOK ) return NULL; return (**astMEMBER(this,Frame,SystemString))( this, system, status ); } int astAxIn_( AstFrame *this, int axis, double lo, double hi, double val, int closed, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,AxIn))( this, axis, lo, hi, val, closed, status ); } int astGetFrameFlags_( AstFrame *this, int *status ) { if ( !astOK ) return 0; return (**astMEMBER(this,Frame,GetFrameFlags))( this, status ); } void astSetFrameFlags_( AstFrame *this, int value, int *status ) { if ( !astOK ) return; (**astMEMBER(this,Frame,SetFrameFlags))( this, value, status ); } /* Special public interface functions. */ /* =================================== */ /* These provide the public interface to certain special functions whose public interface cannot be handled using macros (such as astINVOKE) alone. In general, they are named after the corresponding protected version of the function, but with "Id" appended to the name. */ /* Public Interface Function Prototypes. */ /* ------------------------------------- */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstFrame *PickAxesId_( AstFrame *, int, const int[], AstMapping **, int * ); AstFrame *astFrameId_( int, const char *, ... ); const char *astFormatId_( AstFrame *, int, double, int * ); int astUnformatId_( AstFrame *, int, const char *, double *, int * ); void astPermAxesId_( AstFrame *, const int[], int * ); /* Special interface function implementations. */ /* ------------------------------------------- */ const char *astFormatId_( AstFrame *this, int axis, double value, int *status ) { /* *++ * Name: c astFormat f AST_FORMAT * Purpose: * Format a coordinate value for a Frame axis. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c const char *astFormat( AstFrame *this, int axis, double value ) f RESULT = AST_FORMAT( THIS, AXIS, VALUE, STATUS ) * Class Membership: * Frame method. * Description: c This function returns a pointer to a string containing the f This function returns a character string containing the * formatted (character) version of a coordinate value for a Frame * axis. The formatting applied is determined by the Frame's * attributes and, in particular, by any Format attribute string * that has been set for the axis. A suitable default format (based * on the Digits attribute value) will be applied if necessary. * Parameters: c this f THIS = INTEGER (given) * Pointer to the Frame. c axis f AXIS = INTEGER (Given) * The number of the Frame axis for which formatting is to be * performed (axis numbering starts at 1 for the first axis). c value f VALUE = DOUBLE PRECISION (Given) * The coordinate value to be formatted. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astFormat() c A pointer to a null-terminated string containing the formatted c value. f AST_FORMAT = CHARACTER * ( AST__SZCHR ) f The formatted value. * Notes: c - The returned pointer is guaranteed to remain valid and the c string to which it points will not be over-written for a total c of 50 successive invocations of this function. After this, the c memory containing the string may be re-used, so a copy of the c string should be made if it is needed for longer than this. c - A formatted value may be converted back into a numerical (double) c value using astUnformat. f - A formatted value may be converted back into a numerical f (double precision) value using AST_UNFORMAT. c - A NULL pointer will be returned if this function is invoked c with the AST error status set, or if it should fail for any c reason. f - A blank string will be returned if this function is invoked f with STATUS set to an error value, or if it should fail for any f reason. *-- * Implementation Notes: * This function implements the public interface for the astFormat * method. It is identical to astFormat_ except that: * * - The axis index is decremented by 1 before use. This allows the * public interface to use 1-based axis numbers (whereas internally * axis numbers are zero-based). * * - The returned string value is buffered in dynamically allocated * memory so that it will remain valid for a guaranteed number of * function invocations. */ /* Local Variables: */ astDECLARE_GLOBALS /* Thread-specific global data */ const char *fvalue; /* Pointer to formatted value */ const char *result; /* Pointer value to return */ int i; /* Loop counter for initialisation */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to Thread-specific global data. */ astGET_GLOBALS(this); /* If the "astformatid_strings" array has not been initialised, fill it with NULL pointers. */ if ( !astformatid_init ) { astformatid_init = 1; for ( i = 0; i < ASTFORMATID_MAX_STRINGS; i++ ) astformatid_strings[ i ] = NULL; } /* Invoke the normal astFormat_ function to obtain a pointer to the required formatted value, adjusting the axis index to become zero-based. */ fvalue = astFormat( this, axis - 1, value ); /* If OK, store a copy of the resulting string in dynamically allocated memory, putting a pointer to the copy into the next element of the "astformatid_strings" array. (This process also de-allocates any previously allocated memory pointed at by this "astformatid_strings" element, so the earlier string is effectively replaced by the new one.) */ if ( astOK ) { astBeginPM; astformatid_strings[ astformatid_istr ] = astStore( astformatid_strings[ astformatid_istr ], fvalue, strlen( fvalue ) + (size_t) 1 ); astEndPM; /* If OK, return a pointer to the copy and increment "astformatid_istr" to use the next element of "astformatid_strings" on the next invocation. Recycle "astformatid_istr" to zero when all elements have been used. */ if ( astOK ) { result = astformatid_strings[ astformatid_istr++ ]; if ( astformatid_istr == ( ASTFORMATID_MAX_STRINGS - 1 ) ) astformatid_istr = 0; } } /* Return the result. */ return result; } AstFrame *astFrameId_( int naxes, const char *options, ... ) { /* *++ * Name: c astFrame f AST_FRAME * Purpose: * Create a Frame. * Type: * Public function. * Synopsis: c #include "frame.h" c AstFrame *astFrame( int naxes, const char *options, ... ) f RESULT = AST_FRAME( NAXES, OPTIONS, STATUS ) * Class Membership: * Frame constructor. * Description: * This function creates a new Frame and optionally initialises its * attributes. * * A Frame is used to represent a coordinate system. It does this * in rather the same way that a frame around a graph describes the * coordinate space in which data are plotted. Consequently, a * Frame has a Title (string) attribute, which describes the * coordinate space, and contains axes which in turn hold * information such as Label and Units strings which are used for * labelling (e.g.) graphical output. In general, however, the * number of axes is not restricted to two. * * Functions are available for converting Frame coordinate values * into a form suitable for display, and also for calculating * distances and offsets between positions within the Frame. * * Frames may also contain knowledge of how to transform to and * from related coordinate systems. * Parameters: c naxes f NAXES = INTEGER (Given) * The number of Frame axes (i.e. the number of dimensions of * the coordinate space which the Frame describes). c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new Frame. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new Frame. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astFrame() f AST_FRAME = INTEGER * A pointer to the new Frame. * Examples: c frame = astFrame( 2, "Title=Energy Spectrum: Plot %d", n ); c Creates a new 2-dimensional Frame and initialises its Title c attribute to the string "Energy Spectrum: Plot ", where c takes the value of the int variable "n". c frame = astFrame( 2, "Label(1)=Energy, Label(2)=Response" ); c Creates a new 2-dimensional Frame and initialises its axis c Label attributes to suitable string values. f FRAME = AST_FRAME( 2, 'Title=Energy Spectrum', STATUS ); f Creates a new 2-dimensional Frame and initialises its Title f attribute to the string "Energy Spectrum". f FRAME = AST_FRAME( 2, 'Label(1)=Energy, Label(2)=Response', STATUS ); f Creates a new 2-dimensional Frame and initialises its axis f Label attributes to suitable string values. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astFrame constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astFrame_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - The variable argument list also prevents this function from * invoking astFrame_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFrame *new; /* Pointer to new Frame */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the Frame, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab, "Frame", naxes ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new Frame's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new Frame. */ return astMakeId( new ); } void astPermAxesId_( AstFrame *this, const int perm[], int *status ) { /* *++ * Name: c astPermAxes f AST_PERMAXES * Purpose: * Permute the axis order in a Frame. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c void astPermAxes( AstFrame *this, const int perm[] ) f CALL AST_PERMAXES( THIS, PERM, STATUS ) * Class Membership: * Frame method. * Description: c This function permutes the order in which a Frame's axes occur. f This routine permutes the order in which a Frame's axes occur. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c perm f PERM( * ) = INTEGER (Given) * An array with one element for each axis of the Frame (Naxes * attribute). This should list the axes in their new order, * using the original axis numbering (which starts at 1 for the * first axis). f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Only genuine permutations of the axis order are permitted, so c each axis must be referenced exactly once in the "perm" array. f each axis must be referenced exactly once in the PERM array. * - If successive axis permutations are applied to a Frame, then * the effects are cumulative. *-- * Implementation Notes: * This function implements the public interface for the * astPermAxes method. It is identical to astPermAxes_ except that * the axis numbers in the "perm" array are decremented by 1 before * use. This is to allow the public interface to use one-based axis * numbering (internally, zero-based axis numbering is used). */ /* Local Variables: */ int *perm1; /* Pointer to modified perm array */ int axis; /* Loop counter for Frame axes */ int naxes; /* Number of Frame axes */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain the number of Frame axes. */ naxes = astGetNaxes( this ); /* Allocate an array to hold a modified version of the "perm" array. */ perm1 = astMalloc( sizeof( int ) * (size_t) naxes ); if ( astOK ) { /* Make a modified copy of the "perm" array by subtracting one from each element. This allows the public interface to use one-based axis numbering, whereas all internal code is zero-based. */ for ( axis = 0; axis < naxes; axis++ ) perm1[ axis ] = perm[ axis ] - 1; /* Invoke the normal astPermAxes_ function to permute the Frame's axes. */ astPermAxes( this, perm1 ); } /* Free the temporary array. */ perm1 = astFree( perm1 ); } AstFrame *astPickAxesId_( AstFrame *this, int naxes, const int axes[], AstMapping **map, int *status ) { /* *++ * Name: c astPickAxes f AST_PICKAXES * Purpose: * Create a new Frame by picking axes from an existing one. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c AstFrame *astPickAxes( AstFrame *this, int naxes, const int axes[], c AstMapping **map ) f RESULT = AST_PICKAXES( THIS, NAXES, AXES, MAP, STATUS ) * Class Membership: * Frame method. * Description: * This function creates a new Frame whose axes are copied from an * existing Frame along with other Frame attributes, such as its * Title. Any number (zero or more) of the original Frame's axes * may be copied, in any order, and additional axes with default * attributes may also be included in the new Frame. * c Optionally, a Mapping that converts between the coordinate f A Mapping that converts between the coordinate * systems described by the two Frames will also be returned. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the original Frame. c naxes f NAXES = INTEGER (Given) * The number of axes required in the new Frame. c axes f AXES( NAXES ) = INTEGER (Given) c An array, with "naxes" elements, which lists the axes to be f An array which lists the axes to be * copied. These should be given in the order required in the * new Frame, using the axis numbering in the original Frame * (which starts at 1 for the first axis). Axes may be selected * in any order, but each may only be used once. If additional * (default) axes are also to be included, the corresponding * elements of this array should be set to zero. c map f MAP = INTEGER (Returned) c Address of a location in which to return a pointer to a new f A pointer to a new * Mapping. This will be a PermMap (or a UnitMap as a special * case) that describes the axis permutation that has taken * place between the original and new Frames. The Mapping's * forward transformation will convert coordinates from the * original Frame into the new one, and vice versa. c c If this Mapping is not required, a NULL value may be supplied c for this parameter. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astPickAxes() f AST_PICKAXES = INTEGER * A pointer to the new Frame. * Applicability: * Frame * This function applies to all Frames. The class of Frame returned * may differ from that of the original Frame, depending on which * axes are selected. For example, if a single axis is picked from a * SkyFrame (which must always have two axes) then the resulting * Frame cannot be a valid SkyFrame, so will revert to the parent * class (Frame) instead. * FrameSet * Using this function on a FrameSet is identical to using it on * the current Frame in the FrameSet. The returned Frame will not * be a FrameSet. * Region * If this function is used on a Region, an attempt is made to * retain the bounds information on the selected axes. If * succesful, the returned Frame will be a Region of some class. * Otherwise, the returned Frame is obtained by calling this * function on the Frame represented by the supplied Region (the * returned Frame will then not be a Region). In order to be * succesful, the selected axes in the Region must be independent * of the others. For instance, a Box can be split in this way but * a Circle cannot. Another requirement for success is that no * default axes are added (that is, the c "axes" f AXES * array must not contain any zero values. * Notes: c - The new Frame will contain a "deep" copy (c.f. astCopy) of all f - The new Frame will contain a "deep" copy (c.f. AST_COPY) of all * the data selected from the original Frame. Modifying any aspect * of the new Frame will therefore not affect the original one. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * This function implements the public interface for the * astPickAxes method. It is identical to astPickAxes_ except for * the following: * * - The axis numbers in the "axes" array are decremented by 1 before * use. This is to allow the public interface to use one-based axis * numbering (internally, zero-based axis numbering is used). * * - An ID value is returned via the "map" parameter (if used) * instead of a true C pointer. This is required because this * conversion cannot be performed by the macro that invokes the * function. */ /* Local Variables: */ AstFrame *result; /* Pointer to result Frame */ int *axes1; /* Pointer to modified axes array */ int axis; /* Loop counter for axes */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Allocate an array to hold a modified version of the "axes" array (check that "naxes" is valid first - if not, this error will be reported by astPickAxes_ below). */ axes1 = ( naxes >= 0 ) ? astMalloc( sizeof( int ) * (size_t) naxes ) : NULL; if ( astOK ) { /* Make a modified copy of the "axes" array by subtracting one from each element. This allows the public interface to use one-based axis numbering, whereas all internal code is zero-based. */ for ( axis = 0; axis < naxes; axis++ ) axes1[ axis ] = axes[ axis ] - 1; /* Invoke the normal astPickAxes_ function to select the required axes. */ result = astPickAxes( this, naxes, axes1, map ); } /* Free the temporary array. */ axes1 = astFree( axes1 ); /* If required, return an ID value for the Mapping. */ if ( map ) *map = astMakeId( *map ); /* Return the result. */ return result; } int astUnformatId_( AstFrame *this, int axis, const char *string, double *value, int *status ) { /* *++ * Name: c astUnformat f AST_UNFORMAT * Purpose: * Read a formatted coordinate value for a Frame axis. * Type: * Public virtual function. * Synopsis: c #include "frame.h" c int astUnformat( AstFrame *this, int axis, const char *string, c double *value ) f RESULT = AST_UNFORMAT( THIS, AXIS, STRING, VALUE, STATUS ) * Class Membership: * Frame method. * Description: c This function reads a formatted coordinate value (given as a c character string) for a Frame axis and returns the equivalent c numerical (double) value. It also returns the number of c characters read from the string. f This function reads a formatted coordinate value (given as a f character string) for a Frame axis and returns the equivalent f numerical (double precision) value. It also returns the number f of characters read from the string. * c The principle use of this function is in decoding user-supplied c input which contains formatted coordinate values. Free-format c input is supported as far as possible. If input is ambiguous, it c is interpreted with reference to the Frame's attributes (in c particular, the Format string associated with the Frame's c axis). This function is, in essence, the inverse of astFormat. f The principle use of this function is in decoding user-supplied f input which contains formatted coordinate values. Free-format f input is supported as far as possible. If input is ambiguous, it f is interpreted with reference to the Frame's attributes (in f particular, the Format string associated with the Frame's f axis). This function is, in essence, the inverse of AST_FORMAT. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the Frame. c axis f AXIS = INTEGER (Given) * The number of the Frame axis for which a coordinate value is to * be read (axis numbering starts at 1 for the first axis). c string f STRING = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string containing the c formatted coordinate value. f A character string containing the formatted coordinate value. * This string may contain additional information following the * value to be read, in which case reading stops at the first * character which cannot be interpreted as part of the value. * Any white space before or after the value is discarded. c value f VALUE = DOUBLE PRECISION (Returned) c Pointer to a double in which the coordinate value read will be c returned. f The coordinate value read. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astUnformat() f AST_UNFORMAT = INTEGER * The number of characters read from the string in order to * obtain the coordinate value. This will include any white * space which occurs before or after the value. * Applicability: * Frame * This function applies to all Frames. See the "Frame Input * Format" section below for details of the input formats * accepted by a basic Frame. * SkyFrame * The SkyFrame class re-defines the input format to be suitable * for representing angles and times, with the resulting * coordinate value returned in radians. See the "SkyFrame * Input Format" section below for details of the formats * accepted. * FrameSet * The input formats accepted by a FrameSet are determined by * its current Frame (as specified by the Current attribute). * Frame Input Format * The input format accepted for a basic Frame axis is as follows: * - An optional sign, followed by: * - A sequence of one or more digits possibly containing a decimal point, * followed by: * - An optional exponent field. * - The exponent field, if present, consists of "E" or "e" * followed by a possibly signed integer. * * Examples of acceptable Frame input formats include: * - 99 * - 1.25 * - -1.6 * - 1E8 * - -.99e-17 * - * SkyFrame Input Format * The input format accepted for a SkyFrame axis is as follows: * - An optional sign, followed by between one and three fields * representing either degrees, arc-minutes, arc-seconds or hours, * minutes, seconds (e.g. "-12 42 03"). * - Each field should consist of a sequence of one or more digits, * which may include leading zeros. At most one field may contain a * decimal point, in which case it is taken to be the final field * (e.g. decimal degrees might be given as "124.707", while degrees * and decimal arc-minutes might be given as "-13 33.8"). * - The first field given may take any value, allowing angles and * times outside the conventional ranges to be * represented. However, subsequent fields must have values of less * than 60 (e.g. "720 45 31" is valid, whereas "11 45 61" is not). * - Fields may be separated by white space or by ":" (colon), but * the choice of separator must be used consistently throughout the * value. Additional white space may be present around fields and * separators (e.g. "- 2: 04 : 7.1"). * - The following field identification characters may be used as * separators to replace either of those above (or may be appended * to the final field), in order to identify the field to which * they are appended: "d"---degrees; "h"---hours; "m"---minutes of * arc or time; "s"---seconds of arc or time; "'" (single * quote)---minutes of arc; """ (double quote)---seconds of arc. * Either lower or upper case may be used. Fields must be given in * order of decreasing significance (e.g. "-11D 3' 14.4"" or * "22h14m11.2s"). * - The presence of any of the field identification characters * "d", "'" (single quote) or """ (double quote) indicates that the * value is to be interpreted as an angle. Conversely, the presence * of "h" indicates that it is to be interpreted as a time (with 24 * hours corresponding to 360 degrees). Incompatible angle/time * identification characters may not be mixed (e.g. "10h14'3"" is * not valid). The remaining field identification characters and * separators do not specify a preference for an angle or a time * and may be used with either. c - If no preference for an angle or a time is expressed anywhere c within the value, it is interpreted as an angle if the Format c attribute string associated with the SkyFrame axis generates an c angle and as a time otherwise. This ensures that values produced c by astFormat are correctly interpreted by astUnformat. f - If no preference for an angle or a time is expressed anywhere f within the value, it is interpreted as an angle if the Format f attribute string associated with the SkyFrame axis generates an f angle and as a time otherwise. This ensures that values produced f by AST_FORMAT are correctly interpreted by AST_UNFORMAT. * - Fields may be omitted, in which case they default to zero. The * remaining fields may be identified by using appropriate field * identification characters (see above) and/or by adding extra * colon separators (e.g. "-05m13s" is equivalent to "-:05:13"). If * a field is not identified explicitly, it is assumed that * adjacent fields have been given, after taking account of any * extra separator characters (e.g. "14:25.4s" specifies minutes * and seconds, while "14::25.4s" specifies degrees and seconds). c - If fields are omitted in such a way that the remaining ones c cannot be identified uniquely (e.g. "01:02"), then the first c field (either given explicitly or implied by an extra leading c colon separator) is taken to be the most significant field that c astFormat would produce when formatting a value (using the c Format attribute associated with the SkyFrame axis). By c default, this means that the first field will normally be c interpreted as degrees or hours. However, if this does not c result in consistent field identification, then the last field c (either given explicitly or implied by an extra trailing colon c separator) is taken to to be the least significant field that c astFormat would produce. f - If fields are omitted in such a way that the remaining ones f cannot be identified uniquely (e.g. "01:02"), then the first f field (either given explicitly or implied by an extra leading f colon separator) is taken to be the most significant field that f AST_FORMAT would produce when formatting a value (using the f Format attribute associated with the SkyFrame axis). By f default, this means that the first field will normally be f interpreted as degrees or hours. However, if this does not f result in consistent field identification, then the last field f (either given explicitly or implied by an extra trailing colon f separator) is taken to to be the least significant field that f AST_FORMAT would produce. * c This final convention is intended to ensure that values formatted c by astFormat which contain less than three fields will be c correctly interpreted if read back using astUnformat, even if c they do not contain field identification characters. f This final convention is intended to ensure that values formatted f by AST_FORMAT which contain less than three fields will be f correctly interpreted if read back using AST_UNFORMAT, even if f they do not contain field identification characters. * * Examples of acceptable SkyFrame input formats (with * interpretation in parentheses) include: * - -14d 13m 22.2s (-14d 13' 22.2") * - + 12:34:56.7 (12d 34' 56.7" or 12h 34m 56.7s) * - 001 : 02 : 03.4 (1d 02' 03.4" or 1h 02m 03.4s) * - 22h 30 (22h 30m 00s) * - 136::10" (136d 00' 10" or 136h 00m 10s) * - -14M 27S (-0d 14' 27" or -0h 14m 27s) * - -:14: (-0d 14' 00" or -0h 14m 00s) * - -::4.1 (-0d 00' 04.1" or -0h 00m 04.1s) * - .9" (0d 00' 00.9") * - d12m (0d 12' 00") * - H 12:22.3s (0h 12m 22.3s) * - (AST__BAD) * * Where alternative interpretations are shown, the choice of angle or * time depends on the associated Format(axis) attribute. * Notes: * - A function value of zero (and no coordinate value) will be * returned, without error, if the string supplied does not contain * a suitably formatted value. c - Beware that it is possible for a formatting error part-way c through an input string to terminate input before it has been c completely read, but to yield a coordinate value that appears c valid. For example, if a user types "1.5r6" instead of "1.5e6", c the "r" will terminate input, giving an incorrect coordinate c value of 1.5. It is therefore most important to check the return c value of this function to ensure that the correct number of c characters have been read. f - Beware that it is possible for a formatting error part-way f through an input string to terminate input before it has been f completely read, but to yield a coordinate value that appears f valid. For example, if a user types "1.5R6" instead of "1.5E6", f the "R" will terminate input, giving an incorrect coordinate f value of 1.5. It is therefore most important to check the return f value of this function to ensure that the correct number of f characters have been read. * - An error will result if a value is read which appears to have * the correct format, but which cannot be converted into a valid * coordinate value (for instance, because the value of one or more * of its fields is invalid). * - The string "" is recognised as a special case and will * yield the coordinate value AST__BAD without error. The test for * this string is case-insensitive and also permits embedded white * space. c - A function result of zero will be returned and no coordinate c value will be returned via the "value" pointer if this function c is invoked with the AST error status set, or if it should fail c for any reason. f - A function result of zero will be returned and no coordinate f value will be returned via the VALUE argument if this function f is invoked with the AST error status set, or if it should fail f for any reason. *-- * Implementation Notes: * This function implements the public interface for the * astUnformat method. It is identical to astUnformat_ except that: * * - The axis index is decremented by 1 before use. This allows the * public interface to use 1-based axis numbers (whereas internally * axis numbers are zero-based). */ /* Invoke the normal astUnformat_ function, adjusting the axis index to become zero-based. */ return astUnformat( this, axis - 1, string, value ); } ./ast-7.3.3/fswitchmap.c0000644000175000017500000000720512262533650013457 0ustar olesoles/* *+ * Name: * fswitchmap.c * Purpose: * Define a FORTRAN 77 interface to the AST SwitchMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the SwitchMap class. * Routines Defined: * AST_ISASWITCHMAP * AST_SWITCHMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S.Berry (Starlink) * History: * 13-MAR-2006 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "switchmap.h" /* C interface to the SwitchMap class */ F77_LOGICAL_FUNCTION(ast_isaswitchmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astWatchSTATUS( astAt( "AST_ISASWITCHMAP", NULL, 0 ); RESULT = astIsASwitchMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_switchmap)( INTEGER(FSMAP), INTEGER(ISMAP), INTEGER(NROUTE), INTEGER_ARRAY(ROUTEMAPS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FSMAP) GENPTR_INTEGER(ISMAP) GENPTR_INTEGER(NROUTE) GENPTR_INTEGER_ARRAY(ROUTEMAPS) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; AstObject **routemaps; astAt( "AST_SWITCHMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); routemaps = astMalloc( sizeof(AstObject *) * (*NROUTE) ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } for ( i = 0; i < *NROUTE; i++ ) { routemaps[ i ] = astI2P( ROUTEMAPS[ i ] ); } } RESULT = astP2I( astSwitchMap( astI2P( *FSMAP ), astI2P( *ISMAP ), *NROUTE, (void **) routemaps, "%s", options ) ); astFree( routemaps ); astFree( options ); ) return RESULT; } ./ast-7.3.3/COPYING.LIB0000644000175000017500000006126112262533650012610 0ustar olesoles GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ./ast-7.3.3/stccatalogentrylocation.c0000644000175000017500000007451312262533650016257 0ustar olesoles/* *class++ * Name: * StcCatalogEntryLocation * Purpose: * Correspond to the IVOA STCCatalogEntryLocation class. * Constructor Function: c astStcCatalogEntryLocation f AST_STCCATALOGENTRYLOCATION * Description: * The StcCatalogEntryLocation class is a sub-class of Stc used to describe * the coverage of the datasets contained in some VO resource. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * Inheritance: * The StcCatalogEntryLocation class inherits from the Stc class. * Attributes: * The StcCatalogEntryLocation class does not define any new attributes beyond * those which are applicable to all Stcs. * Functions: c The StcCatalogEntryLocation class does not define any new functions beyond those f The StcCatalogEntryLocation class does not define any new routines beyond those * which are applicable to all Stcs. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 26-NOV-2004 (DSB): * Original version. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS StcCatalogEntryLocation /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "stc.h" /* Coordinate stcs (parent class) */ #include "channel.h" /* I/O channels */ #include "region.h" /* Regions within coordinate systems */ #include "stccatalogentrylocation.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(StcCatalogEntryLocation) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(StcCatalogEntryLocation,Class_Init) #define class_vtab astGLOBAL(StcCatalogEntryLocation,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstStcCatalogEntryLocationVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstStcCatalogEntryLocation *astStcCatalogEntryLocationId_( void *, int, AstKeyMap **, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static void Dump( AstObject *, AstChannel *, int * ); /* Member functions. */ /* ================= */ void astInitStcCatalogEntryLocationVtab_( AstStcCatalogEntryLocationVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitStcCatalogEntryLocationVtab * Purpose: * Initialise a virtual function table for a StcCatalogEntryLocation. * Type: * Protected function. * Synopsis: * #include "stccatalogentrylocation.h" * void astInitStcCatalogEntryLocationVtab( AstStcCatalogEntryLocationVtab *vtab, const char *name ) * Class Membership: * StcCatalogEntryLocation vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the StcCatalogEntryLocation class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstStcVtab *stc; /* Pointer to Stc component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitStcVtab( (AstStcVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAStcCatalogEntryLocation) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstStcVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ mapping = (AstMappingVtab *) vtab; stc = (AstStcVtab *) vtab; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ /* Declare the copy constructor, destructor and class dump functions. */ astSetDump( vtab, Dump, "StcCatalogEntryLocation", "Resource coverage" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ /* None */ /* Destructor. */ /* ----------- */ /* None */ /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for StcCatalogEntryLocation objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the StcCatalogEntryLocation class to an output Channel. * Parameters: * this * Pointer to the StcCatalogEntryLocation whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstStcCatalogEntryLocation *this; /* Pointer to the StcCatalogEntryLocation structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the StcCatalogEntryLocation structure. */ this = (AstStcCatalogEntryLocation *) this_object; /* Write out values representing the instance variables for the StcCatalogEntryLocation class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* There are no values to write, so return without further action. */ } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAStcCatalogEntryLocation and astCheckStcCatalogEntryLocation functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(StcCatalogEntryLocation,Stc) astMAKE_CHECK(StcCatalogEntryLocation) AstStcCatalogEntryLocation *astStcCatalogEntryLocation_( void *region_void, int ncoords, AstKeyMap **coords, const char *options, int *status, ...) { /* *++ * Name: c astStcCatalogEntryLocation f AST_STCCATALOGENTRYLOCATION * Purpose: * Create a StcCatalogEntryLocation. * Type: * Public function. * Synopsis: c #include "stccatalogentrylocation.h" c AstStcCatalogEntryLocation *astStcCatalogEntryLocation( AstRegion *region, c int ncoords, AstKeyMap *coords[], const char *options, ... ) f RESULT = AST_STCCATALOGENTRYLOCATION( REGION, NCOORDS, COORDS, OPTIONS, STATUS ) * Class Membership: * StcCatalogEntryLocation constructor. * Description: * This function creates a new StcCatalogEntryLocation and optionally initialises its * attributes. * * The StcCatalogEntryLocation class is a sub-class of Stc used to describe * the coverage of the datasets contained in some VO resource. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * Parameters: c region f REGION = INTEGER (Given) * Pointer to the encapsulated Region. c ncoords f NCOORDS = INTEGER (Given) c The length of the "coords" array. Supply zero if "coords" is NULL. f The length of the COORDS array. Supply zero if COORDS should be f ignored. c coords f COORDS( NCOORDS ) = INTEGER (Given) c Pointer to an array holding "ncoords" AstKeyMap pointers (if "ncoords" f An array holding NCOORDS AstKeyMap pointers (if NCOORDS * is zero, the supplied value is ignored). Each supplied KeyMap * describes the contents of a single STC element, and * should have elements with keys given by constants AST__STCNAME, * AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. Any of these elements may be omitted, but no other * elements should be included. If supplied, the AST__STCNAME element * should be a vector of character string pointers holding the "Name" * item for each axis in the coordinate system represented by c "region". f REGION. * Any other supplied elements should be scalar elements, each holding * a pointer to a Region describing the associated item of ancillary * information (error, resolution, size, pixel size or value). These * Regions should describe a volume within the coordinate system c represented by "region". f represented by REGION. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new StcCatalogEntryLocation. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new StcCatalogEntryLocation. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astStcCatalogEntryLocation() f AST_STCCATALOGENTRYLOCATION = INTEGER * A pointer to the new StcCatalogEntryLocation. * Notes: * - A deep copy is taken of the supplied Region. This means that * any subsequent changes made to the encapsulated Region using the * supplied pointer will have no effect on the Stc. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRegion *region; /* Pointer to Region structure */ AstStcCatalogEntryLocation *new; /* Pointer to new StcCatalogEntryLocation */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate a pointer to the Region structure provided. */ region = astCheckRegion( region_void ); /* Initialise the StcCatalogEntryLocation, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitStcCatalogEntryLocation( NULL, sizeof( AstStcCatalogEntryLocation ), !class_init, &class_vtab, "StcCatalogEntryLocation", region, ncoords, coords ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new StcCatalogEntryLocation's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new StcCatalogEntryLocation. */ return new; } AstStcCatalogEntryLocation *astStcCatalogEntryLocationId_( void *region_void, int ncoords, AstKeyMap **coords, const char *options, ... ) { /* * Name: * astStcCatalogEntryLocationId_ * Purpose: * Create a StcCatalogEntryLocation. * Type: * Private function. * Synopsis: * #include "stccatalogentrylocation.h" * AstStcCatalogEntryLocation *astStcCatalogEntryLocationId( AstRegion *region, * int ncoords, AstKeyMap *coords[], const char *options, ..., int *status ) * Class Membership: * StcCatalogEntryLocation constructor. * Description: * This function implements the external (public) interface to the * astStcCatalogEntryLocation constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astStcCatalogEntryLocation_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astStcCatalogEntryLocation_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astStcCatalogEntryLocation_. * status * Pointer to the inherited status variable. * Returned Value: * The ID value associated with the new StcCatalogEntryLocation. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstKeyMap **keymaps; /* Pointer to array of KeyMap pointers */ AstRegion *region; /* Pointer to Region structure */ AstStcCatalogEntryLocation *new;/* Pointer to new StcCatalogEntryLocation */ int icoord; /* Keymap index */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain a Region pointer from the supplied ID and validate the pointer to ensure it identifies a valid Region. */ region = astVerifyRegion( astMakePointer( region_void ) ); /* Obtain pointer from the supplied KeyMap ID's and validate the pointers to ensure it identifies a valid KeyMap. */ keymaps = astMalloc( sizeof( AstKeyMap * )*(size_t) ncoords ); if( keymaps ) { for( icoord = 0; icoord < ncoords; icoord++ ) { keymaps[ icoord ] = astVerifyKeyMap( astMakePointer( coords[ icoord ] ) ); } } /* Initialise the StcCatalogEntryLocation, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitStcCatalogEntryLocation( NULL, sizeof( AstStcCatalogEntryLocation ), !class_init, &class_vtab, "StcCatalogEntryLocation", region, ncoords, keymaps ); /* Free resources. */ keymaps = astFree( keymaps ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new StcCatalogEntryLocation's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new StcCatalogEntryLocation. */ return astMakeId( new ); } AstStcCatalogEntryLocation *astInitStcCatalogEntryLocation_( void *mem, size_t size, int init, AstStcCatalogEntryLocationVtab *vtab, const char *name, AstRegion *region, int ncoords, AstKeyMap **coords, int *status ) { /* *+ * Name: * astInitStcCatalogEntryLocation * Purpose: * Initialise a StcCatalogEntryLocation. * Type: * Protected function. * Synopsis: * #include "stccatalogentrylocation.h" * AstStcCatalogEntryLocation *astInitStcCatalogEntryLocation_( void *mem, size_t size, * int init, AstStcCatalogEntryLocationVtab *vtab, * const char *name, AstRegion *region, * int ncoords, AstKeyMap **coords ) * Class Membership: * StcCatalogEntryLocation initialiser. * Description: * This function is provided for use by class implementations to initialise * a new StcCatalogEntryLocation object. It allocates memory (if necessary) to accommodate * the StcCatalogEntryLocation plus any additional data associated with the derived class. * It then initialises a StcCatalogEntryLocation structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a StcCatalogEntryLocation at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the StcCatalogEntryLocation is to be initialised. * This must be of sufficient size to accommodate the StcCatalogEntryLocation data * (sizeof(StcCatalogEntryLocation)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the StcCatalogEntryLocation (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the StcCatalogEntryLocation * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the StcCatalogEntryLocation's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new StcCatalogEntryLocation. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * region * A pointer to the Region encapsulated by the StcCatalogEntryLocation. * ncoords * Number of KeyMap pointers supplied in "coords". Can be zero. * Ignored if "coords" is NULL. * coords * Pointer to an array of "ncoords" KeyMap pointers, or NULL if * "ncoords" is zero. Each KeyMap defines defines a single * element, and should have elements with keys given by constants * AST__STCNAME, AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. These elements hold values for the corresponding * components of the STC AstroCoords element. Any of these elements may * be omitted, but no other elements should be included. All supplied * elements should be vector elements, with vector length less than or * equal to the number of axes in the supplied Region. The data type of * all elements should be "double", except for AST__STCNAME which should * be "character string". If no value is available for a given axis, then * AST__BAD (or NULL for the AST__STCNAME element) should be stored in * the vector at the index corresponding to the axis (trailing axes * can be omitted completely from the KeyMap). * Returned Value: * A pointer to the new StcCatalogEntryLocation. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstStcCatalogEntryLocation *new; /* Pointer to new StcCatalogEntryLocation */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitStcCatalogEntryLocationVtab( vtab, name ); /* Initialise a Stc structure (the parent class) as the first component within the StcCatalogEntryLocation structure, allocating memory if necessary. */ new = (AstStcCatalogEntryLocation *) astInitStc( mem, size, 0, (AstStcVtab *) vtab, name, region, ncoords, coords ); /* If an error occurred, clean up by deleting the new StcCatalogEntryLocation. */ if ( !astOK ) new = astDelete( new ); /* Return a pointer to the new StcCatalogEntryLocation. */ return new; } AstStcCatalogEntryLocation *astLoadStcCatalogEntryLocation_( void *mem, size_t size, AstStcCatalogEntryLocationVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadStcCatalogEntryLocation * Purpose: * Load a StcCatalogEntryLocation. * Type: * Protected function. * Synopsis: * #include "stccatalogentrylocation.h" * AstStcCatalogEntryLocation *astLoadStcCatalogEntryLocation( void *mem, size_t size, AstStcCatalogEntryLocationVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * StcCatalogEntryLocation loader. * Description: * This function is provided to load a new StcCatalogEntryLocation using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * StcCatalogEntryLocation structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a StcCatalogEntryLocation at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the StcCatalogEntryLocation is to be * loaded. This must be of sufficient size to accommodate the * StcCatalogEntryLocation data (sizeof(StcCatalogEntryLocation)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the StcCatalogEntryLocation (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the StcCatalogEntryLocation structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstStcCatalogEntryLocation) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new StcCatalogEntryLocation. If this is NULL, a pointer * to the (static) virtual function table for the StcCatalogEntryLocation class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "StcCatalogEntryLocation" is used instead. * Returned Value: * A pointer to the new StcCatalogEntryLocation. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstStcCatalogEntryLocation *new; /* Pointer to the new StcCatalogEntryLocation */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this StcCatalogEntryLocation. In this case the StcCatalogEntryLocation belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstStcCatalogEntryLocation ); vtab = &class_vtab; name = "StcCatalogEntryLocation"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitStcCatalogEntryLocationVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built StcCatalogEntryLocation. */ new = astLoadStc( mem, size, (AstStcVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "StcCatalogEntryLocation" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* There are no values to read. */ /* ---------------------------- */ /* If an error occurred, clean up by deleting the new StcCatalogEntryLocation. */ if ( !astOK ) new = astDelete( new ); } /* Return the new StcCatalogEntryLocation pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/error.c0000644000175000017500000010043312262533650012440 0ustar olesoles/* * Name: * error.c * Purpose: * Implement error handling functions. * Description: * This file implements the Error module which provides functions * for handling error conditions in the AST library. For a * description of the module and its interface, see the .h file of * the same name. * * Since its initial release, AST has used a global status variable * rather than adding an explicit status parameter to the argument * list of each AST function. This caused problems for the thread-safe * version of AST since each thread needs its own status value. Whilst * it would have been possible for each function to access a global * status value via the pthreads "thread speific data key" mechanism, * the huge number of status checks performed within AST caused this * option to be slow. Instead AST has been modified so that every * function has an explicit status pointer parameter. This though * causes problems in that we cannot change the public interface to * AST because doing so would break large amounts of external software. * To get round this, the macros that define the public interface to * AST have been modified so that they provide a status pointer * automatically to the function that is being invoked. This is how * the system works... * * All AST functions have an integer inherited status pointer parameter * called "status". This parameter is "hidden" in AST functions that * are invoked via macros (typically public and protected functions). * This means that whilst "int *status" appears explicitly at the end * of the function argument list (in both prototype and definition), it * is not included in the prologue documentation, and is not included * explicitly in the argument list when invoking the function. Instead, * the macro that is used to invoke the function adds in the required * status parameter to the function invocation. * * Macros which are invoked within AST (the protected interface) expand * to include ", status" at the end of the function parameter list. For * backward compatability with previous versions of AST, macros which * are invoked from outside AST (the public interface) expand to include * ", astGetStatusPtr" at the end of the function parameter list. The * astGetStatusPtr function returns a pointer to the interbal AST * status variable or to the external variable specified via astWatch. * * Parameter lists for functions that have variable argument lists * (such as astError) cannot be handled in this way, since macros cannot * have variable numbers of arguments. Instead, separate public and * protected implementations of such functions are provided within AST. * Protected implementations include an explicit, documented status * pointer parameter that must be given explicitly when invoking the * function. Public implementations do not have a status pointer * parameter. Instead they obtain the status pointer internally using * astGetStatusPtr. * * Private functions are called directly rather than via macros, and so * they have a documented status pointer parameter that should be * included explicitly in the parameter list when invoking the * function. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2008-2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 2-JAN-1996 (RFWS): * Original version. * 8-JAN-1996 (RFWS): * Tidied up. * 26-JAN-1996 (RFWS): * Incorporated changes to prologue style. * 14-JUN-1996 (RFWS): * Added astAt. * 20-JUN-1996 (RFWS): * Added astSetStatus. * 15-JUL-1996 (RFWS): * Sorted out the public interface. * 16-JUL-1996 (RFWS): * Added astWatch. * 18-MAR-1998 (RFWS): * Added notes about functions being available for writing * foreign language and graphics interfaces, etc. * 27-NOV-2002 (DSB): * Added suppression of error reporting using astReporting. * 11-MAR-2004 (DSB): * Add facility to astAt to allow astAt to be called from public * interface without private interface settings over-riding the * public interface settings. * 30-MAR-2005 (DSB): * Added facility to report deferred messages when reporting is * switched back on. * 16-FEB-2006 (DSB): * Improve efficiency by replacing the astOK_ function with a macro * which tests the value of status variable. The pointer which points * to the AST status variable are now global rather than static. * 19-SEP-2008 (DSB): * Big changes for the thread-safe version of AST. * 3-FEB-2009 (DSB): * Added astBacktrace. */ /* Define the astCLASS macro (even although this is not a class implementation) to obtain access to protected interfaces. */ #define astCLASS /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "err.h" /* Interface to the err module */ #include "error.h" /* Interface to this module */ #include "globals.h" /* Thread-safe global data access */ /* C header files. */ /* --------------- */ #include #include #include #include /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* Select the appropriate memory management functions. These will be the system's malloc, free and realloc unless AST was configured with the "--with-starmem" option, in which case they will be the starmem malloc, free and realloc. */ #ifdef HAVE_STAR_MEM_H # include # define MALLOC starMalloc # define FREE starFree # define REALLOC starRealloc #else # define MALLOC malloc # define FREE free # define REALLOC realloc #endif /* Include execinfo.h if the backtrace function is available */ #if HAVE_EXECINFO_H #include #endif /* Module Variables. */ /* ================= */ /* Define macros for accessing all items of thread-safe global data used by this module. */ #ifdef THREAD_SAFE #define reporting astGLOBAL(Error,Reporting) #define current_file astGLOBAL(Error,Current_File) #define current_routine astGLOBAL(Error,Current_Routine) #define current_line astGLOBAL(Error,Current_Line) #define foreign_set astGLOBAL(Error,Foreign_Set) #define message_stack astGLOBAL(Error,Message_Stack) #define mstack_size astGLOBAL(Error,Mstack_Size) /* Since the external astPutErr function may not be thread safe, we need to ensure that it cannot be invoked simultaneously from two different threads. So we lock a mutex before each call to astPutErr. */ static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; #define INVOKE_ASTPUTERR( status, buff ) \ ( pthread_mutex_lock( &mutex1 ), \ astPutErr( (status), (buff) ), \ (void) pthread_mutex_unlock( &mutex1 ) ) /* Define the initial values for the global data for this module. */ #define GLOBAL_inits \ globals->Reporting = 1; \ globals->Current_File = NULL; \ globals->Current_Routine = NULL; \ globals->Current_Line = 0; \ globals->Foreign_Set = 0; \ globals->Mstack_Size = 0; \ /* Create the global initialisation function. */ astMAKE_INITGLOBALS(Error) /* If thread safety is not needed, declare globals at static variables. */ /* -------------------------------------------------------------------- */ #else /* Status variable. */ static int internal_status = 0; /* Internal error status */ int *starlink_ast_status_ptr = &internal_status; /* Pointer to status variable */ /* Reporting flag: delivery of message is supressed if zero. */ static int reporting = 1; /* Error context. */ static const char *current_file = NULL; /* Current file name pointer */ static const char *current_routine = NULL; /* Current routine name pointer */ static int current_line = 0; /* Current line number */ static int foreign_set = 0; /* Have foreign values been set? */ /* Un-reported message stack */ static char *message_stack[ AST__ERROR_MSTACK_SIZE ]; static int mstack_size = 0; /* If thread-safety is not needed, we can invoke the external astPutErr function directly. */ #define INVOKE_ASTPUTERR( status, buff ) \ astPutErr( (status), (buff) ); #endif /* Function prototypes. */ /* ==================== */ static void EmptyStack( int, int * ); /* Function implementations. */ /* ========================= */ void astAt_( const char *routine, const char *file, int line, int forn, int *status) { /* *+ * Name: * astAt * Purpose: * Store a routine, file and line number context in case of error. * Type: * Protected function. * Synopsis: * #include "error.h" * void astAt( const char *routine, const char *file, int line, int forn) * Description: * This function stores a pointer to two strings containing the * names of a routine and a file, together with an integer line * number. These values are retained for subsequent use in * reporting the context of any error that may arise. * Parameters: * routine * Pointer to a null terminated C string containing a routine * name (which should reside in static memory). * file * Pointer to a null terminated C string containing a file name * (which should reside in static memory). * line * The line number in the file. * for * Is this call being made from a foreign language interface? * If so any values supplied will take precedence of the values * set by the C interface. * Notes: * - This function returns without action (i.e. without changing * the stored values) if the global error status is set. It * performs no other error checking. * - Any (or all) of the arguments may be omitted by supplying a * NULL or zero value (as appropriate) and will then not be included * in any error report. * - This function is documented as protected because it should not * be invoked by external code. However, it is available via the * external C interface so that it may be used when writing (e.g.) * foreign language or graphics interfaces. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ /* Check the global error status. */ if ( !astOK ) return; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* If the values refer to a foreign interface, or if no foreign values have yet been set, store the supplied values. */ if( forn|| !foreign_set ) { current_routine = routine; current_file = file; current_line = line; } /* If the values relate to a foreign interface, set a flag which prevents local values set later replacing them. */ foreign_set = forn; } void astBacktrace_( int *status ) { /* c+ * Name: * astBacktrace * Purpose: * Display a backtrace on standard output. * Type: * Protected macro. * Synopsis: * #include "error.h" * astBacktrace; * Description: * This macro displays a set of messages on standard output that * give a backtrace of the caller. It can be useful for debugging AST * code in situations when it is not easy or possible to use a * debugger (for instance, when debugging JNIAST). * Notes: * - Only non-static function names are included in the backtrace. * - This function requires the GNU C library. When called, it will * just issue a warning if the GNU 'backtrace' function was not * available when AST was configured. c- */ #if HAVE_BACKTRACE #define MAX_ADDR 100 /* Local Variables: */ char **strings; /* Pointer to array of formated strings */ char buf[ 120 ]; /* Output line buffer */ int j; /* String index */ int np; /* Number of used return addresses */ void *buffer[ MAX_ADDR ]; /* Array of return addresses */ /* Get the array of return addresses. */ np = backtrace( buffer, MAX_ADDR ); /* Convert them into strings. */ strings = backtrace_symbols( buffer, np ); /* If succesful, display them and then free the array. Note we skip the first one since that will refer to this function. */ if( strings ) { INVOKE_ASTPUTERR( astStatus, " " ); for( j = 1; j < np; j++ ) { sprintf( buf, "%d: %s", j, strings[j] ); INVOKE_ASTPUTERR( astStatus, buf ); } free( strings ); INVOKE_ASTPUTERR( astStatus, " " ); /* If not succesful, issue a warning. */ } else { INVOKE_ASTPUTERR( astStatus, "Cannot convert backtrace addresses into formatted strings" ); } #else INVOKE_ASTPUTERR( astStatus, "Backtrace functionality is not available " "on the current operating system." ); #endif } void astClearStatus_( int *status ) { /* c++ * Name: * astClearStatus * Purpose: * Clear the AST error status. * Type: * Public macro. * Synopsis: * #include "error.h" * void astClearStatus * Description: * This macro resets the AST error status to an OK value, * indicating that an error condition (if any) has been cleared. * Notes: * - If the AST error status is set to an error value (after an * error), most AST functions will not execute and will simply * return without action. Using astClearStatus will restore normal * behaviour. c-- */ /* Empty the deferred error stack without displaying the messages on the stack. */ EmptyStack( 0, status ); /* Reset the error status value. */ *status = 0; } static void EmptyStack( int display, int *status ) { /* * Name: * EmptyStack * Purpose: * Empty the stack of deferred error messages, optionally displaying * them. * Type: * Private function. * Synopsis: * #include "error.h" * void EmptyStack( int display, int *status ) * Description: * This function removes all messages from the stack of deferred error * messages. If "display" is non-zero it reports them using astPutErr * before deleting them. * Parameters: * display * Report messages before deleting them? * status * Pointer to the integer holding the inherited status value. */ /* Local variables; */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int i; /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Loop round all messages on the stack. */ for( i = 0; i < mstack_size; i++ ) { /* Display the message if required. */ if( display ) INVOKE_ASTPUTERR( astStatus, message_stack[ i ] ); /* Free the memory used to hold the message. */ FREE( message_stack[ i ] ); message_stack[ i ] = NULL; } /* Reset the stack size to zero. */ mstack_size = 0; } void astErrorPublic_( int status_value, const char *fmt, ... ) { /* *+ * Name: * astError * Purpose: * Set the AST error status and report an error message. * Type: * Protected function. * Synopsis: * #include "error.h" * void astError( int status_value, const char *fmt, ... ) * Description: * This function sets the AST error status to a specified value and * reports an associated error message. * Parameters: * status_value * The new error status value to be set. * fmt * Pointer to a null-terminated character string containing the * format specification for the error message, in the same way * as for a call to the C "printf" family of functions. * ... * Additional optional arguments (as used by e.g. "printf") * which specify values which are to appear in the error * message. * Notes: * This function operates just like "printf", except that: * - The first argument is an error status. * - The return value is void. * - A newline is automatically appended to the error message * (there is no need to add one). * - This function is documented as protected because it should not * be invoked by external code. However, it is available via the * external C interface so that it may be used when writing (e.g.) * foreign language or graphics interfaces. *- * This is the public implementation of astError. It does not have an status pointer parameter, but instead obtains the status pointer explicitly using the astGetStatusPtr function. This is different to other public functions, which typically have a status pointer parameter that is supplied via a call to astGetStatusPtr within the associated interface macro. The benefit of doing it the usual way is that the public and protected implementations are the same, with the differences between public and protecte dinterfaces wrapped up in the associated interface macro. We cannot do this with this function because of the variale argument list. The prologue for the astError_ function defines the interface for use internally within AST. */ /* Local Constants: */ #define BUFF_LEN 1023 /* Max. length of an error message */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char buff[ BUFF_LEN + 1 ]; /* Message buffer */ int *status; /* Pointer to inherited status value */ int imess; /* Index into deferred message stack */ int nc; /* Number of characters written */ va_list args; /* Variable argument list pointer */ /* Initialise the variable argument list pointer. */ va_start( args, fmt ); /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get a pointer to the integer holding the inherited status value. */ status = astGetStatusPtr; /* If this is the first report of an error (the global status has not previously been set) and error context information is available, then construct an error context message. */ if ( astOK && ( current_routine || current_file || current_line ) ) { nc = sprintf( buff, "AST: Error" ); if ( current_routine ) { nc += sprintf( buff + nc, " in routine %s", current_routine ); } if ( current_line ) { nc += sprintf( buff + nc, " at line %d", current_line ); } if ( current_file ) { nc += sprintf( buff + nc, " in file %s", current_file ); } nc += sprintf( buff + nc, "." ); /* Deliver the error message unless reporting has been switched off using astReporting. In which case store them in a static array. */ if( reporting ) { INVOKE_ASTPUTERR( status_value, buff ); } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){ imess = mstack_size++; message_stack[ imess ] = MALLOC( strlen( buff ) + 1 ); if( message_stack[ imess ] ) { strcpy( message_stack[ imess ], buff ); } } /* Set the global status. */ astSetStatus( status_value ); } /* Write the error message supplied to the formatting buffer. */ nc = vsprintf( buff, fmt, args ); /* Tidy up the argument pointer. */ va_end( args ); /* Deliver the error message unless reporting has been switched off using astReporting. */ if( reporting ) { INVOKE_ASTPUTERR( status_value, buff ); } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){ imess = mstack_size++; message_stack[ imess ] = MALLOC( strlen( buff ) + 1 ); if( message_stack[ imess ] ) { strcpy( message_stack[ imess ], buff ); } } /* Set the error status value. */ astSetStatus( status_value ); /* Undefine macros local to this function. */ #undef BUFF_LEN } void astError_( int status_value, const char *fmt, int *status, ... ) { /* *+ * Name: * astError * Purpose: * Set the AST error status and report an error message. * Type: * Protected function. * Synopsis: * #include "error.h" * void astError( int status_value, const char *fmt, int *status, ... ) * Description: * This function sets the AST error status to a specified value and * reports an associated error message. * Parameters: * status_value * The error status value to be set. * fmt * Pointer to a null-terminated character string containing the * format specification for the error message, in the same way * as for a call to the C "printf" family of functions. * status * Pointer to the integer holding the inherited status value. * ... * Additional optional arguments (as used by e.g. "printf") * which specify values which are to appear in the error * message. * Notes: * This function operates just like "printf", except that: * - The first argument is an error status. * - The return value is void. * - A newline is automatically appended to the error message * (there is no need to add one). * - This function is documented as protected because it should not * be invoked by external code. However, it is available via the * external C interface so that it may be used when writing (e.g.) * foreign language or graphics interfaces. *- * This is the protected implementation of astError. It has a status pointer parameter that is not present in the public form. Different implementations for protected and public interfaces are required because of the variable argument list. */ /* Local Constants: */ #define BUFF_LEN 1023 /* Max. length of an error message */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ char buff[ BUFF_LEN + 1 ]; /* Message buffer */ int imess; /* Index into deferred message stack */ int nc; /* Number of characters written */ va_list args; /* Variable argument list pointer */ /* Initialise the variable argument list pointer. */ va_start( args, status ); /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* If this is the first report of an error (the global status has not previously been set) and error context information is available, then construct an error context message. */ if ( astOK && ( current_routine || current_file || current_line ) ) { nc = sprintf( buff, "AST: Error" ); if ( current_routine ) { nc += sprintf( buff + nc, " in routine %s", current_routine ); } if ( current_line ) { nc += sprintf( buff + nc, " at line %d", current_line ); } if ( current_file ) { nc += sprintf( buff + nc, " in file %s", current_file ); } nc += sprintf( buff + nc, "." ); /* Deliver the error message unless reporting has been switched off using astReporting. In which case store them in a static array. */ if( reporting ) { INVOKE_ASTPUTERR( status_value, buff ); } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){ imess = mstack_size++; message_stack[ imess ] = MALLOC( strlen( buff ) + 1 ); if( message_stack[ imess ] ) { strcpy( message_stack[ imess ], buff ); } } /* Set the global status. */ astSetStatus( status_value ); } /* Write the error message supplied to the formatting buffer. */ nc = vsprintf( buff, fmt, args ); /* Tidy up the argument pointer. */ va_end( args ); /* Deliver the error message unless reporting has been switched off using astReporting. */ if( reporting ) { INVOKE_ASTPUTERR( status_value, buff ); } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){ imess = mstack_size++; message_stack[ imess ] = MALLOC( strlen( buff ) + 1 ); if( message_stack[ imess ] ) { strcpy( message_stack[ imess ], buff ); } } /* Set the error status value. */ astSetStatus( status_value ); /* Undefine macros local to this function. */ #undef BUFF_LEN } int *astGetStatusPtr_(){ /* *+ * Name: * astGetStatusPtr * Purpose: * Return a pointer to the integer holding the inherited status value. * Type: * Protected function. * Synopsis: * #include "error.h" * int *astGetStatusPtr; * Description: * This macro returns a pointer to the integer holding the inherited * status pointer. This will either be an internal global integer * (possibly stored as thread specific data), or an ineger specified * via the astWatch function. * Returned Value: * A pointer to the integer holding the inherited status value. *- */ /* The thread-safe version of AST stores the status pointer in thread specific data, using the key stored in the global variable "starlink_ast_status_key". */ #if defined(THREAD_SAFE) astDECLARE_GLOBALS AstStatusBlock *sb; astGET_GLOBALS(NULL); sb = (AstStatusBlock *) pthread_getspecific(starlink_ast_status_key); return sb->status_ptr; /* The non thread-safe version of AST stores the status pointer in the global variable "starlink_ast_status_ptr". */ #else return starlink_ast_status_ptr; #endif } /* c++ * Name: * astOK * Purpose: * Test whether AST functions have been successful. * Type: * Public macro. * Synopsis: * #include "error.h" * int astOK * Description: * This macro returns a boolean value (0 or 1) to indicate if * preceding AST functions have completed successfully * (i.e. without setting the AST error status). If the error status * is set to an error value, a value of zero is returned, otherwise * the result is one. * Returned Value: * astOK * One if the AST error status is OK, otherwise zero. * Notes: * - If the AST error status is set to an error value (after an * error), most AST functions will not execute and will simply * return without action. To clear the error status and restore * normal behaviour, use astClearStatus. c-- */ int astReporting_( int report, int *status ) { /* c+ * Name: * astReporting * Purpose: * Controls the reporting of error messages. * Type: * Protected function. * Synopsis: * #include "error.h" * int astReporting( int report ) * Description: * Error messages supplied to astError will only be delivered to the * underlying error system if the "Reporting" flag is set to a * non-zero value. Setting this flag to zero suppresses the reporting * of error messages (the value of the AST error status however is * unaffected). Instead, the reports are saved in an internal message * stack. When reporting is switched back on again, any messages on this * stack of deferred messages will be reported (and the stack emptied) * if the AST error status is not astOK. Also the stack is emptied each * time astClearStatus is called (the stacked messages are not displayed * in this case). * Parameters: * report * The new value for the Reporting flag. * Returned Value: * The original value of the Reporting flag. * Notes: * - The Reporting flag is initially set to 1. c- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int oldval; /* Original "reporting" value */ /* If needed, get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Save the original reporting value, and then store the new value. */ oldval = reporting; reporting = report; /* If we are now reporting errors, flush any messages on the error stack. This causes the messages to be displayed and the stack emptied. */ if( reporting ) EmptyStack( 1, status ); /* Return the original reporting value. */ return oldval; } /* c++ * Name: * astSetStatus * Purpose: * Set the AST error status to an explicit value. * Type: * Public function. * Synopsis: * #include "error.h" * void astSetStatus( int status_value ) * Description: * This function sets the AST error status to the value supplied. * It does not cause any error message to be produced and should * not be used as part of normal error reporting. Its purpose is * simply to communicate to AST that an error has occurred in some * other item of software. * * For example, a source or sink function supplied as an argument * to astChannel or astFitsChan might use this to signal that an * input/output error has occurred. AST could then respond by * terminating the current read or write operation. * Parameters: * status_value * The new error status value to be set. * Notes: * - If the AST error status is set to an error value, most AST * functions will not execute and will simply return without * action. To clear the error status and restore normal behaviour, * use astClearStatus. c-- */ /* c++ * Name: * astStatus * Purpose: * Obtain the current AST error status value. * Type: * Public function. * Synopsis: * #include "error.h" * int astStatus * Description: * This function returns the current value of the AST error status. * Returned Value: * astStatus * The AST error status value. * Notes: * - If the AST error status is set to an error value (after an * error), most AST functions will not execute and will simply * return without action. To clear the error status and restore * normal behaviour, use astClearStatus. c-- */ int *astWatch_( int *status_ptr ) { /* c++ * Name: * astWatch * Purpose: * Identify a new error status variable for the AST library. * Type: * Public function. * Synopsis: * #include "error.h" * int *astWatch( int *status_ptr ) * Description: * This function allows a new error status variable to be accessed * by the AST library when checking for and reporting error * conditions. * * By default, the library uses an internal integer error status * which is set to an error value if an error occurs. Use of * astWatch allows the internal error status to be replaced by an * integer variable of your choosing, so that the AST library can * share its error status directly with other code which uses the * same error detection convention. * * If an alternative error status variable is supplied, it is used * by all related AST functions and macros (e.g. astOK, astStatus * and astClearStatus). * Parameters: * status_ptr * Pointer to an int whose value is to be used subsequently as * the AST inherited status value. If a NULL pointer is supplied, * the AST library will revert to using its own internal error status. * Returned Value: * astWatch() * Address of the previous error status variable. This may later * be passed back to astWatch to restore the previous behaviour * of the library. (Note that on the first invocation of * astWatch the returned value will be the address of the * internal error status variable.) * Notes: * - This function is not available in the FORTRAN 77 interface to * the AST library. c-- */ /* Local Variables: */ int *result; /* Value to be returned */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #if defined(THREAD_SAFE) AstStatusBlock *sb = NULL; #endif /* Ensure that the thread-specific status block has been created and ininitialised. */ astGET_GLOBALS(NULL); #if defined(THREAD_SAFE) sb = (AstStatusBlock *) pthread_getspecific( starlink_ast_status_key ); result = sb->status_ptr; sb->status_ptr = status_ptr ? status_ptr : &(sb->internal_status); #else result = starlink_ast_status_ptr; starlink_ast_status_ptr = status_ptr ? status_ptr : &internal_status; #endif /* Return the old address. */ return result; } ./ast-7.3.3/mathmap.c0000644000175000017500000111343112262533650012741 0ustar olesoles/* *class++ * Name: * MathMap * Purpose: * Transform coordinates using mathematical expressions. * Constructor Function: c astMathMap f AST_MATHMAP * Description: c A MathMap is a Mapping which allows you to specify a set of forward c and/or inverse transformation functions using arithmetic operations c and mathematical functions similar to those available in C. The c MathMap interprets these functions at run-time, whenever its forward c or inverse transformation is required. Because the functions are not c compiled in the normal sense (unlike an IntraMap), they may be used to c describe coordinate transformations in a transportable manner. A c MathMap therefore provides a flexible way of defining new types of c Mapping whose descriptions may be stored as part of a dataset and c interpreted by other programs. f A MathMap is a Mapping which allows you to specify a set of forward f and/or inverse transformation functions using arithmetic operations f and mathematical functions similar to those available in Fortran. The f MathMap interprets these functions at run-time, whenever its forward f or inverse transformation is required. Because the functions are not f compiled in the normal sense (unlike an IntraMap), they may be used to f describe coordinate transformations in a transportable manner. A f MathMap therefore provides a flexible way of defining new types of f Mapping whose descriptions may be stored as part of a dataset and f interpreted by other programs. * Inheritance: * The MathMap class inherits from the Mapping class. * Attributes: * In addition to those attributes common to all Mappings, every * MathMap also has the following attributes: * - Seed: Random number seed * - SimpFI: Forward-inverse MathMap pairs simplify? * - SimpIF: Inverse-forward MathMap pairs simplify? * Functions: c The MathMap class does not define any new functions beyond those f The MathMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 3-SEP-1999 (RFWS): * Original version. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitMathMapVtab * method. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 14-MAR-2006 (DSB): * - Add QIF function. * - Override astEqual method. * 20-NOV-2006 (DSB): * Re-implement the Equal method to avoid use of astSimplify. * 30-AUG-2012 (DSB): * Fix bug in undocumented Gaussian noise function. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS MathMap /* Allocate pointer array. */ /* ----------------------- */ /* This macro allocates an array of pointers. If successful, each element of the array is initialised to NULL. */ #define MALLOC_POINTER_ARRAY(array_name,array_type,array_size) \ \ /* Allocate the array. */ \ (array_name) = astMalloc( sizeof(array_type) * (size_t) (array_size) ); \ if ( astOK ) { \ \ /* If successful, loop to initialise each element. */ \ int array_index_; \ for ( array_index_ = 0; array_index_ < (array_size); array_index_++ ) { \ (array_name)[ array_index_ ] = NULL; \ } \ } /* Free pointer array. */ /* ------------------- */ /* This macro frees a dynamically allocated array of pointers, each of whose elements may point at a further dynamically allocated array (which is also to be freed). It also allows for the possibility of any of the pointers being NULL. */ #define FREE_POINTER_ARRAY(array_name,array_size) \ \ /* Check that the main array pointer is not NULL. */ \ if ( (array_name) ) { \ \ /* If OK, loop to free each of the sub-arrays. */ \ int array_index_; \ for ( array_index_ = 0; array_index_ < (array_size); array_index_++ ) { \ \ /* Check that each sub-array pointer is not NULL before freeing it. */ \ if ( (array_name)[ array_index_ ] ) { \ (array_name)[ array_index_ ] = \ astFree( (array_name)[ array_index_ ] ); \ } \ } \ \ /* Free the main pointer array. */ \ (array_name) = astFree( (array_name) ); \ } /* SizeOf pointer array. */ /* --------------------- */ /* This macro increments "result" by the number of bytes allocated for an array of pointers, each of whose elements may point at a further dynamically allocated array (which is also to be included). It also allows for the possibility of any of the pointers being NULL. */ #define SIZEOF_POINTER_ARRAY(array_name,array_size) \ \ /* Check that the main array pointer is not NULL. */ \ if ( (array_name) ) { \ \ /* If OK, loop to measure each of the sub-arrays. */ \ int array_index_; \ for ( array_index_ = 0; array_index_ < (array_size); array_index_++ ) { \ \ /* Check that each sub-array pointer is not NULL before measuring it. */ \ if ( (array_name)[ array_index_ ] ) { \ result += astTSizeOf( (array_name)[ array_index_ ] ); \ } \ } \ \ /* Include the main pointer array. */ \ result += astTSizeOf( (array_name) ); \ } /* Header files. */ /* ============= */ /* Interface definitions. */ /* ---------------------- */ #include "channel.h" /* I/O channels */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "cmpmap.h" /* Compound Mappings */ #include "mathmap.h" /* Interface definition for this class */ #include "memory.h" /* Memory allocation facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points */ #include "unitmap.h" /* Unit Mapping */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* This type is made obscure since it is publicly accessible (but not useful). Provide shorthand for use within this module. */ typedef AstMathMapRandContext_ Rcontext; /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); /* This declaration enumerates the operation codes recognised by the EvaluateFunction function which evaluates arithmetic expressions. */ typedef enum { /* User-supplied constants and variables. */ OP_LDCON, /* Load constant */ OP_LDVAR, /* Load variable */ /* System constants. */ OP_LDBAD, /* Load bad value (AST__BAD) */ OP_LDDIG, /* Load # decimal digits (DBL_DIG) */ OP_LDEPS, /* Load relative precision (DBL_EPSILON) */ OP_LDMAX, /* Load largest value (DBL_MAX) */ OP_LDMAX10E, /* Max. decimal exponent (DBL_MAX_10_EXP) */ OP_LDMAXE, /* Load maximum exponent (DBL_MAX_EXP) */ OP_LDMDIG, /* Load # mantissa digits (DBL_MANT_DIG) */ OP_LDMIN, /* Load smallest value (DBL_MIN) */ OP_LDMIN10E, /* Min. decimal exponent (DBL_MIN_10_EXP) */ OP_LDMINE, /* Load minimum exponent (DBL_MIN_EXP) */ OP_LDRAD, /* Load floating radix (FLT_RADIX) */ OP_LDRND, /* Load rounding mode (FLT_ROUNDS) */ /* Mathematical constants. */ OP_LDE, /* Load e (base of natural logarithms) */ OP_LDPI, /* Load pi */ /* Functions with one argument. */ OP_ABS, /* Absolute value (sign removal) */ OP_ACOS, /* Inverse cosine (radians) */ OP_ACOSD, /* Inverse cosine (degrees) */ OP_ACOSH, /* Inverse hyperbolic cosine */ OP_ACOTH, /* Inverse hyperbolic cotangent */ OP_ACSCH, /* Inverse hyperbolic cosecant */ OP_ASECH, /* Inverse hyperbolic secant */ OP_ASIN, /* Inverse sine (radians) */ OP_ASIND, /* Inverse sine (degrees) */ OP_ASINH, /* Inverse hyperbolic sine */ OP_ATAN, /* Inverse tangent (radians) */ OP_ATAND, /* Inverse tangent (degrees) */ OP_ATANH, /* Inverse hyperbolic tangent */ OP_CEIL, /* C ceil function (round up) */ OP_COS, /* Cosine (radians) */ OP_COSD, /* Cosine (degrees) */ OP_COSH, /* Hyperbolic cosine */ OP_COTH, /* Hyperbolic cotangent */ OP_CSCH, /* Hyperbolic cosecant */ OP_EXP, /* Exponential function */ OP_FLOOR, /* C floor function (round down) */ OP_INT, /* Integer value (round towards zero) */ OP_ISBAD, /* Test for bad value */ OP_LOG, /* Natural logarithm */ OP_LOG10, /* Base 10 logarithm */ OP_NINT, /* Fortran NINT function (round to nearest) */ OP_POISS, /* Poisson random number */ OP_SECH, /* Hyperbolic secant */ OP_SIN, /* Sine (radians) */ OP_SINC, /* Sinc function [= sin(x)/x] */ OP_SIND, /* Sine (degrees) */ OP_SINH, /* Hyperbolic sine */ OP_SQR, /* Square */ OP_SQRT, /* Square root */ OP_TAN, /* Tangent (radians) */ OP_TAND, /* Tangent (degrees) */ OP_TANH, /* Hyperbolic tangent */ /* Functions with two arguments. */ OP_ATAN2, /* Inverse tangent (2 arguments, radians) */ OP_ATAN2D, /* Inverse tangent (2 arguments, degrees) */ OP_DIM, /* Fortran DIM (positive difference) fn. */ OP_GAUSS, /* Gaussian random number */ OP_MOD, /* Modulus function */ OP_POW, /* Raise to power */ OP_RAND, /* Uniformly distributed random number */ OP_SIGN, /* Transfer of sign function */ /* Functions with three arguments. */ OP_QIF, /* C "question mark" operator "a?b:c" */ /* Functions with variable numbers of arguments. */ OP_MAX, /* Maximum of 2 or more values */ OP_MIN, /* Minimum of 2 or more values */ /* Unary arithmetic operators. */ OP_NEG, /* Negate (change sign) */ /* Unary boolean operators. */ OP_NOT, /* Boolean NOT */ /* Binary arithmetic operators. */ OP_ADD, /* Add */ OP_DIV, /* Divide */ OP_MUL, /* Multiply */ OP_SUB, /* Subtract */ /* Bit-shift operators. */ OP_SHFTL, /* Shift bits left */ OP_SHFTR, /* Shift bits right */ /* Relational operators. */ OP_EQ, /* Relational equal */ OP_GE, /* Greater than or equal */ OP_GT, /* Greater than */ OP_LE, /* Less than or equal */ OP_LT, /* Less than */ OP_NE, /* Not equal */ /* Bit-wise operators. */ OP_BITAND, /* Bit-wise AND */ OP_BITOR, /* Bit-wise OR */ OP_BITXOR, /* Bit-wise exclusive OR */ /* Binary boolean operators. */ OP_AND, /* Boolean AND */ OP_EQV, /* Fortran logical .EQV. operation */ OP_OR, /* Boolean OR */ OP_XOR, /* Boolean exclusive OR */ /* Null operation. */ OP_NULL /* Null operation */ } Oper; /* This structure holds a description of each symbol which may appear in an expression. */ typedef struct { const char *text; /* Symbol text as it appears in expressions */ const int size; /* Size of symbol text */ const int operleft; /* An operator when seen from the left? */ const int operright; /* An operator when seen from the right? */ const int unarynext; /* May be followed by a unary +/- ? */ const int unaryoper; /* Is a unary +/- ? */ const int leftpriority; /* Priority when seen from the left */ const int rightpriority; /* Priority when seen from the right */ const int parincrement; /* Change in parenthesis level */ const int stackincrement; /* Change in evaluation stack size */ const int nargs; /* Number of function arguments */ const Oper opcode; /* Resulting operation code */ } Symbol; /* This initialises an array of Symbol structures to hold data on all the supported symbols. The order is not important, but symbols are arranged here in approximate order of descending evaluation priority. The end of the array is indicated by an element with a NULL "text" component. */ static const Symbol symbol[] = { /* User-supplied constants and variables. */ { "" , 0, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDCON }, { "" , 0, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDVAR }, /* System constants. */ { "" , 5, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDBAD }, { "" , 5, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDDIG }, { "" , 9, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDEPS }, { "" , 10, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMDIG }, { "" , 5, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMAX }, { "", 12, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMAX10E }, { "" , 9, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMAXE }, { "" , 5, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMIN }, { "", 12, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMIN10E }, { "" , 9, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDMINE }, { "" , 7, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDRAD }, { "" , 8, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDRND }, /* Mathematical constants. */ { "" , 3, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDE }, { "" , 4, 0, 0, 0, 0, 19, 19, 0, 1, 0, OP_LDPI }, /* Functions with one argument. */ { "abs(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ABS }, { "acos(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ACOS }, { "acosd(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ACOSD }, { "acosh(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ACOSH }, { "acoth(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ACOTH }, { "acsch(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ACSCH }, { "aint(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_INT }, { "asech(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ASECH }, { "asin(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ASIN }, { "asind(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ASIND }, { "asinh(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ASINH }, { "atan(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ATAN }, { "atand(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ATAND }, { "atanh(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ATANH }, { "ceil(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_CEIL }, { "cos(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_COS }, { "cosd(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_COSD }, { "cosh(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_COSH }, { "coth(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_COTH }, { "csch(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_CSCH }, { "exp(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_EXP }, { "fabs(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ABS }, { "floor(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_FLOOR }, { "int(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_INT }, { "isbad(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_ISBAD }, { "log(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_LOG }, { "log10(" , 6, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_LOG10 }, { "nint(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_NINT }, { "poisson(" , 8, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_POISS }, { "sech(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SECH }, { "sin(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SIN }, { "sinc(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SINC }, { "sind(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SIND }, { "sinh(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SINH }, { "sqr(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SQR }, { "sqrt(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_SQRT }, { "tan(" , 4, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_TAN }, { "tand(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_TAND }, { "tanh(" , 5, 0, 1, 1, 0, 19, 1, 1, 0, 1, OP_TANH }, /* Functions with two arguments. */ { "atan2(" , 6, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_ATAN2 }, { "atan2d(" , 7, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_ATAN2D }, { "dim(" , 4, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_DIM }, { "fmod(" , 5, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_MOD }, { "gauss(" , 6, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_GAUSS }, { "mod(" , 4, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_MOD }, { "pow(" , 4, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_POW }, { "rand(" , 5, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_RAND }, { "sign(" , 5, 0, 1, 1, 0, 19, 1, 1, -1, 2, OP_SIGN }, /* Functions with two arguments. */ { "qif(" , 4, 0, 1, 1, 0, 19, 1, 1, -2, 3, OP_QIF }, /* Functions with variable numbers of arguments. */ { "max(" , 4, 0, 1, 1, 0, 19, 1, 1, -1, -2, OP_MAX }, { "min(" , 4, 0, 1, 1, 0, 19, 1, 1, -1, -2, OP_MIN }, /* Parenthesised expressions. */ { ")" , 1, 1, 0, 0, 0, 2, 19, -1, 0, 0, OP_NULL }, { "(" , 1, 0, 1, 1, 0, 19, 1, 1, 0, 0, OP_NULL }, /* Unary arithmetic operators. */ { "+" , 1, 0, 1, 1, 1, 17, 16, 0, 0, 0, OP_NULL }, { "-" , 1, 0, 1, 1, 1, 17, 16, 0, 0, 0, OP_NEG }, /* Unary boolean operators. */ { "!" , 1, 0, 1, 1, 0, 17, 16, 0, 0, 0, OP_NOT }, { ".not." , 5, 0, 1, 1, 0, 17, 16, 0, 0, 0, OP_NOT }, /* Binary arithmetic operators. */ { "**" , 2, 1, 1, 1, 0, 18, 15, 0, -1, 0, OP_POW }, { "*" , 1, 1, 1, 1, 0, 14, 14, 0, -1, 0, OP_MUL }, { "/" , 1, 1, 1, 1, 0, 14, 14, 0, -1, 0, OP_DIV }, { "+" , 1, 1, 1, 1, 0, 13, 13, 0, -1, 0, OP_ADD }, { "-" , 1, 1, 1, 1, 0, 13, 13, 0, -1, 0, OP_SUB }, /* Bit-shift operators. */ { "<<" , 2, 1, 1, 1, 0, 12, 12, 0, -1, 0, OP_SHFTL }, { ">>" , 2, 1, 1, 1, 0, 12, 12, 0, -1, 0, OP_SHFTR }, /* Relational operators. */ { "<" , 1, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_LT }, { ".lt." , 4, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_LT }, { "<=" , 2, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_LE }, { ".le." , 4, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_LE }, { ">" , 1, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_GT }, { ".gt." , 4, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_GT }, { ">=" , 2, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_GE }, { ".ge." , 4, 1, 1, 1, 0, 11, 11, 0, -1, 0, OP_GE }, { "==" , 2, 1, 1, 1, 0, 10, 10, 0, -1, 0, OP_EQ }, { ".eq." , 4, 1, 1, 1, 0, 10, 10, 0, -1, 0, OP_EQ }, { "!=" , 2, 1, 1, 1, 0, 10, 10, 0, -1, 0, OP_NE }, { ".ne." , 4, 1, 1, 1, 0, 10, 10, 0, -1, 0, OP_NE }, /* Bit-wise operators. */ { "&" , 1, 1, 1, 1, 0, 9, 9, 0, -1, 0, OP_BITAND }, { "^" , 1, 1, 1, 1, 0, 8, 8, 0, -1, 0, OP_BITXOR }, { "|" , 1, 1, 1, 1, 0, 7, 7, 0, -1, 0, OP_BITOR }, /* Binary boolean operators. */ { "&&" , 2, 1, 1, 1, 0, 6, 6, 0, -1, 0, OP_AND }, { ".and." , 5, 1, 1, 1, 0, 6, 6, 0, -1, 0, OP_AND }, { "^^" , 2, 1, 1, 1, 0, 5, 5, 0, -1, 0, OP_XOR }, { "||" , 2, 1, 1, 1, 0, 4, 4, 0, -1, 0, OP_OR }, { ".or." , 4, 1, 1, 1, 0, 4, 4, 0, -1, 0, OP_OR }, { ".eqv." , 5, 1, 1, 1, 0, 3, 3, 0, -1, 0, OP_EQV }, { ".neqv." , 6, 1, 1, 1, 0, 3, 3, 0, -1, 0, OP_XOR }, { ".xor." , 5, 1, 1, 1, 0, 3, 3, 0, -1, 0, OP_XOR }, /* Separators. */ { "," , 1, 1, 1, 1, 0, 2, 2, 0, 0, 0, OP_NULL }, /* End of symbol data. */ { NULL , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, OP_NULL } }; /* These variables identify indices in the above array which hold special symbols used explicitly in the code. */ static const int symbol_ldcon = 0; /* Load a constant */ static const int symbol_ldvar = 1; /* Load a variable */ /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(MathMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(MathMap,Class_Init) #define class_vtab astGLOBAL(MathMap,Class_Vtab) #define getattrib_buff astGLOBAL(MathMap,GetAttrib_Buff) static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 ); #define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 ); static pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX4 pthread_mutex_lock( &mutex4 ); #define UNLOCK_MUTEX4 pthread_mutex_unlock( &mutex4 ); static pthread_mutex_t mutex5 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX5 pthread_mutex_lock( &mutex5 ); #define UNLOCK_MUTEX5 pthread_mutex_unlock( &mutex5 ); static pthread_mutex_t mutex6 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX6 pthread_mutex_lock( &mutex6 ); #define UNLOCK_MUTEX6 pthread_mutex_unlock( &mutex6 ); static pthread_mutex_t mutex7 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX7 pthread_mutex_lock( &mutex7 ); #define UNLOCK_MUTEX7 pthread_mutex_unlock( &mutex7 ); /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 51 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstMathMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #define LOCK_MUTEX3 #define UNLOCK_MUTEX3 #define LOCK_MUTEX4 #define UNLOCK_MUTEX4 #define LOCK_MUTEX5 #define UNLOCK_MUTEX5 #define LOCK_MUTEX6 #define UNLOCK_MUTEX6 #define LOCK_MUTEX7 #define UNLOCK_MUTEX7 #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstMathMap *astMathMapId_( int, int, int, const char *[], int, const char *[], const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int GetObjSize( AstObject *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static double Gauss( Rcontext *, int * ); static double LogGamma( double, int * ); static double Poisson( Rcontext *, double, int * ); static double Rand( Rcontext *, int * ); static int DefaultSeed( const Rcontext *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetSeed( AstMathMap *, int * ); static int GetSimpFI( AstMathMap *, int * ); static int GetSimpIF( AstMathMap *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int TestSeed( AstMathMap *, int * ); static int TestSimpFI( AstMathMap *, int * ); static int TestSimpIF( AstMathMap *, int * ); static void CleanFunctions( int, const char *[], char ***, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void ClearSeed( AstMathMap *, int * ); static void ClearSimpFI( AstMathMap *, int * ); static void ClearSimpIF( AstMathMap *, int * ); static void CompileExpression( const char *, const char *, const char *, int, const char *[], int **, double **, int *, int * ); static void CompileMapping( const char *, const char *, int, int, int, const char *[], int, const char *[], int ***, int ***, double ***, double ***, int *, int *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void EvaluateFunction( Rcontext *, int, const double **, const int *, const double *, int, double *, int * ); static void EvaluationSort( const double [], int, int [], int **, int *, int * ); static void ExtractExpressions( const char *, const char *, int, const char *[], int, char ***, int * ); static void ExtractVariables( const char *, const char *, int, const char *[], int, int, int, int, int, char ***, int * ); static void ParseConstant( const char *, const char *, const char *, int, int *, double *, int * ); static void ParseName( const char *, int, int *, int * ); static void ParseVariable( const char *, const char *, const char *, int, int, const char *[], int *, int *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SetSeed( AstMathMap *, int, int * ); static void SetSimpFI( AstMathMap *, int, int * ); static void SetSimpIF( AstMathMap *, int, int * ); static void ValidateSymbol( const char *, const char *, const char *, int, int, int *, int **, int **, int *, double **, int * ); /* Member functions. */ /* ================= */ static void CleanFunctions( int nfun, const char *fun[], char ***clean, int *status ) { /* * Name: * CleanFunctions * Purpose: * Make a clean copy of a set of functions. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void CleanFunctions( int nfun, const char *fun[], char ***clean, int *status ) * Class Membership: * MathMap member function. * Description: * This function copies an array of strings, eliminating any white space * characters and converting to lower case. It is intended for cleaning * up arrays of function definitions prior to compilation. The returned * copy is stored in dynamically allocated memory. * Parameters: * nfun * The number of functions to be cleaned. * fun * Pointer to an array, with "nfun" elements, of pointers to null * terminated strings which contain each of the functions. * clean * Address in which to return a pointer to an array (with "nfun" * elements) of pointers to null terminated strings containing the * cleaned functions (i.e. this returns an array of strings). * * Both the returned array of pointers, and the strings to which they * point, will be dynamically allocated and should be freed by the * caller (using astFree) when no longer required. * status * Pointer to the inherited status variable. * Notes: * - A NULL value will be returned for "*clean" if this function is * invoked with the global error status set, or if it should fail for * any reason. */ /* Local Variables: */ char c; /* Character from function string */ int i; /* Loop counter for characters */ int ifun; /* Loop counter for functions */ int nc; /* Count of non-blank characters */ /* Initialise. */ *clean = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Allocate and initialise an array to hold the returned pointers. */ MALLOC_POINTER_ARRAY( *clean, char *, nfun ) /* Loop through all the input functions. */ if ( astOK ) { for ( ifun = 0; ifun < nfun; ifun++ ) { /* Count the number of non-blank characters in each function string. */ nc = 0; for ( i = 0; ( c = fun[ ifun ][ i ] ); i++ ) nc += !isspace( c ); /* Allocate a string long enough to hold the function with all the white space removed, storing its pointer in the array allocated earlier. Check for errors. */ ( *clean )[ ifun ] = astMalloc( sizeof( char ) * (size_t) ( nc + 1 ) ); if ( !astOK ) break; /* Loop to copy the non-blank function characters into the new string. */ nc = 0; for ( i = 0; ( c = fun[ ifun ][ i ] ); i++ ) { if ( !isspace( c ) ) ( *clean )[ ifun ][ nc++ ] = tolower( c ); } /* Null-terminate the result. */ ( *clean )[ ifun ][ nc ] = '\0'; } /* If an error occurred, then free the main pointer array together with any strings that have been allocated, resetting the output value. */ if ( !astOK ) { FREE_POINTER_ARRAY( *clean, nfun ) } } } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a MathMap. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * MathMap member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * MathMap, so that the default value will subsequently be used. * Parameters: * this * Pointer to the MathMap. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstMathMap *this; /* Pointer to the MathMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) this_object; /* Check the attribute name and clear the appropriate attribute. */ /* Seed. */ /* ----- */ if ( !strcmp( attrib, "seed" ) ) { astClearSeed( this ); /* SimpFI. */ /* ------- */ } else if ( !strcmp( attrib, "simpfi" ) ) { astClearSimpFI( this ); /* SimpIF. */ /* ------- */ } else if ( !strcmp( attrib, "simpif" ) ) { astClearSimpIF( this ); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static void CompileExpression( const char *method, const char *class, const char *exprs, int nvar, const char *var[], int **code, double **con, int *stacksize, int *status ) { /* * Name: * CompileExpression * Purpose: * Compile a mathematical expression. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void CompileExpression( const char *method, const char *class, * const char *exprs, int nvar, const char *var[], * int **code, double **con, int *stacksize ) * Class Membership: * MathMap member function. * Description: * This function checks and compiles a mathematical expression. It * produces a sequence of operation codes (opcodes) and a set of * numerical constants which may subsequently be used to evaluate the * expression on a push-down stack. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * exprs * Pointer to a null-terminated string containing the expression * to be compiled. This is case sensitive and should contain no white * space. * nvar * The number of variable names defined for use in the expression. * var * An array of pointers (with "nvar" elements) to null-terminated * strings. Each of these should contain a variable name which may * appear in the expression. These strings are case sensitive and * should contain no white space. * code * Address of a pointer which will be set to point at a dynamically * allocated array of int containing the set of opcodes (cast to int) * produced by this function. The first element of this array will * contain a count of the number of opcodes which follow. * * The allocated space must be freed by the caller (using astFree) when * no longer required. * con * Address of a pointer which will be set to point at a dynamically * allocated array of double containing the set of constants * produced by this function (this may be NULL if no constants are * produced). * * The allocated space must be freed by the caller (using astFree) when * no longer required. * stacksize * Pointer to an int in which to return the size of the push-down stack * required to evaluate the expression using the returned opcodes and * constants. * Algorithm: * The function passes through the input expression searching for * symbols. It looks for standard symbols (arithmetic operators, * parentheses, function calls and delimiters) in the next part of the * expression to be parsed, using identification information stored in * the static "symbol" array. It ignores certain symbols, according to * whether they appear to be operators or operands. The choice depends on * what the previous symbol was; for instance, two operators may not * occur in succession. Unary +/- operators are also ignored in * situations where they are not permitted. * * If a standard symbol is found, it is passed to the ValidateSymbol * function, which keeps track of the current level of parenthesis in the * expression and of the number of arguments supplied to any (possibly * nested) function calls. This function then accepts or rejects the * symbol according to whether it is valid within the current context. An * error is reported if it is rejected. * * If the part of the expression currently being parsed did not contain a * standard symbol, an attempt is made to parse it first as a constant, * then as a variable name. If either of these succeeds, an appropriate * symbol number is added to the list of symbols identified so far, and a * value is added to the list of constants - this is either the value of * the constant itself, or the identification number of the variable. If * the expression cannot be parsed, an error is reported. * * When the entire expression has been analysed as a sequence of symbols * (and associated constants), the EvaluationSort function is * invoked. This sorts the symbols into evaluation order, which is the * order in which the associated operations must be performed on a * push-down arithmetic stack to evaluate the expression. This routine * also substitutes operation codes (defined in the "Oper" enum) for the * symbol numbers and calculates the size of evaluation stack which will * be required. * Notes: * - A value of NULL will be returned for the "*code" and "*con" pointers * and a value of zero will be returned for the "*stacksize" value if this * function is invoked with the global error status set, or if it should * fail for any reason. */ /* Local Variables: */ double c; /* Value of parsed constant */ int *argcount; /* Array of argument count information */ int *opensym; /* Array of opening parenthesis information */ int *symlist; /* Array of symbol indices */ int found; /* Standard symbol identified? */ int iend; /* Ending index in the expression string */ int istart; /* Staring index in the expression string */ int isym; /* Loop counter for symbols */ int ivar; /* Index of variable name */ int lpar; /* Parenthesis level */ int ncon; /* Number of constants generated */ int nsym; /* Number of symbols identified */ int opernext; /* Next symbol an operator (from left)? */ int size; /* Size of symbol matched */ int sym; /* Index of symbol in static "symbol" array */ int unarynext; /* Next symbol may be unary +/- ? */ /* Initialise. */ *code = NULL; *con = NULL; *stacksize = 0; /* Check the global error status. */ if ( !astOK ) return; /* Further initialisation. */ argcount = NULL; lpar = 0; ncon = 0; nsym = 0; opensym = NULL; symlist = NULL; sym = 0; ivar = 0; /* The first symbol to be encountered must not look like an operator from the left. It may be a unary + or - operator. */ opernext = 0; unarynext = 1; /* Search through the expression to classify each symbol which appears in it. Stop when there are no more input characters or an error is detected. */ istart = 0; for ( istart = 0; astOK && exprs[ istart ]; istart = iend + 1 ) { /* Compare each of the symbols in the symbol data with the next section of the expression, looking for the longest symbol text which will match. Stop if a NULL "text" value is found, which acts as the end flag. */ found = 0; size = 0; for ( isym = 0; symbol[ isym ].text; isym++ ) { /* Only consider symbols which have text associated with them and which look like operators or operands from the left, according to the setting of the "opernext" flag. Thus, if an operator or operand is missing from the input expression, the next symbol will not be identified, because it will be of the wrong type. Also exclude unary +/- operators if they are out of context. */ if ( symbol[ isym ].size && ( symbol[ isym ].operleft == opernext ) && ( !symbol[ isym ].unaryoper || unarynext ) ) { /* Test if the text of the symbol matches the expression at the current position. If so, note that a match has been found. */ if ( !strncmp( exprs + istart, symbol[ isym ].text, (size_t) symbol[ isym ].size ) ) { found = 1; /* If this symbol matches more characters than any previous symbol, then store the symbol's index and note its size. */ if ( symbol[ isym ].size > size ) { sym = isym; size = symbol[ isym ].size; /* Calculate the index of the last symbol character in the expression string. */ iend = istart + size - 1; } } } } /* If the symbol was identified as one of the standard symbols, then validate it, updating the parenthesis level and argument count information at the same time. */ if ( found ) { ValidateSymbol( method, class, exprs, iend, sym, &lpar, &argcount, &opensym, &ncon, con, status ); /* If it was not one of the standard symbols, then check if the next symbol was expected to be an operator. If so, then there is a missing operator, so report an error. */ } else { if ( opernext ) { astError( AST__MIOPR, "%s(%s): Missing or invalid operator in the expression " "\"%.*s\".", status, method, class, istart + 1, exprs ); /* If the next symbol was expected to be an operand, then it may be a constant, so try to parse it as one. */ } else { ParseConstant( method, class, exprs, istart, &iend, &c, status ); if ( astOK ) { /* If successful, set the symbol number to "symbol_ldcon" (load constant) and extend the "*con" array to accommodate a new constant. Check for errors. */ if ( iend >= istart ) { sym = symbol_ldcon; *con = astGrow( *con, ncon + 1, sizeof( double ) ); if ( astOK ) { /* Append the constant to the "*con" array. */ ( *con )[ ncon++ ] = c; } /* If the symbol did not parse as a constant, then it may be a variable name, so try to parse it as one. */ } else { ParseVariable( method, class, exprs, istart, nvar, var, &ivar, &iend, status ); if ( astOK ) { /* If successful, set the symbol to "symbol_ldvar" (load variable) and extend the "*con" array to accommodate a new constant. Check for errors. */ if ( ivar != -1 ) { sym = symbol_ldvar; *con = astGrow( *con, ncon + 1, sizeof( double ) ); if ( astOK ) { /* Append the variable identification number as a constant to the "*con" array. */ ( *con )[ ncon++ ] = (double) ivar; } /* If the expression did not parse as a variable name, then there is a missing operand in the expression, so report an error. */ } else { astError( AST__MIOPA, "%s(%s): Missing or invalid operand in the " "expression \"%.*s\".", status, method, class, istart + 1, exprs ); } } } } } } /* If there has been no error, then the next symbol in the input expression has been identified and is valid. */ if ( astOK ) { /* Decide whether the next symbol should look like an operator or an operand from the left. This is determined by the nature of the symbol just identified (seen from the right) - two operands or two operators cannot be adjacent. */ opernext = !symbol[ sym ].operright; /* Also decide whether the next symbol may be a unary +/- operator, according to the "unarynext" symbol data entry for the symbol just identified. */ unarynext = symbol[ sym ].unarynext; /* Extend the "symlist" array to accommodate the symbol just identified. Check for errors. */ symlist = astGrow( symlist, nsym + 1, sizeof( int ) ); if ( astOK ) { /* Append the symbol's index to the end of this list. */ symlist[ nsym++ ] = sym; } } } /* If there has been no error, check the final context after identifying all the symbols... */ if ( astOK ) { /* If an operand is still expected, then there is an unsatisfied operator on the end of the expression, so report an error. */ if ( !opernext ) { astError( AST__MIOPA, "%s(%s): Missing or invalid operand in the expression " "\"%s\".", status, method, class, exprs ); /* If the final parenthesis level is positive, then there is a missing right parenthesis, so report an error. */ } else if ( lpar > 0 ) { astError( AST__MRPAR, "%s(%s): Missing right parenthesis in the expression " "\"%s\".", status, method, class, exprs ); } } /* Sort the symbols into evaluation order to produce output opcodes. */ EvaluationSort( *con, nsym, symlist, code, stacksize, status ); /* Free any memory used as workspace. */ if ( argcount ) argcount = astFree( argcount ); if ( opensym ) opensym = astFree( opensym ); if ( symlist ) symlist = astFree( symlist ); /* If OK, re-allocate the "*con" array to have the correct size (since astGrow may have over-allocated space). */ if ( astOK && *con ) { *con = astRealloc( *con, sizeof( double ) * (size_t) ncon ); } /* If an error occurred, free any allocated memory and reset the output values. */ if ( !astOK ) { *code = astFree( *code ); *con = astFree( *con ); *stacksize = 0; } } static void CompileMapping( const char *method, const char *class, int nin, int nout, int nfwd, const char *fwdfun[], int ninv, const char *invfun[], int ***fwdcode, int ***invcode, double ***fwdcon, double ***invcon, int *fwdstack, int *invstack, int *status ) { /* * Name: * CompileMapping * Purpose: * Compile the transformation functions for a MathMap. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void CompileMapping( const char *method, const char *class, * int nin, int nout, * int nfwd, const char *fwdfun[], * int ninv, const char *invfun[], * int ***fwdcode, int ***invcode, * double ***fwdcon, double ***invcon, * int *fwdstack, int *invstack, int *status ) * Class Membership: * MathMap member function. * Description: * This function checks and compiles the transformation functions required * to create a MathMap. It produces sequences of operation codes (opcodes) * and numerical constants which may subsequently be used to evaluate the * functions on a push-down stack. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * nin * Number of input variables for the MathMap. * nout * Number of output variables for the MathMap. * nfwd * The number of forward transformation functions being supplied. * This must be at least equal to "nout". * fwdfun * Pointer to an array, with "nfwd" elements, of pointers to null * terminated strings which contain each of the forward transformation * functions. These must be in lower case and should contain no white * space. * ninv * The number of inverse transformation functions being supplied. * This must be at least equal to "nin". * invfun * Pointer to an array, with "ninv" elements, of pointers to null * terminated strings which contain each of the inverse transformation * functions. These must be in lower case and should contain no white * space. * fwdcode * Address in which to return a pointer to an array (with "nfwd" * elements) of pointers to arrays of int containing the set of opcodes * (cast to int) for each forward transformation function. The number * of opcodes produced for each function is given by the first element * of the opcode array. * * Both the returned array of pointers, and the arrays of int to which * they point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. * * If the right hand sides (including the "=" sign) of all the supplied * functions are absent, then this indicates an undefined transformation * and the returned pointer value will be NULL. An error results if * an "=" sign is present but no expression follows it. * invcode * Address in which to return a pointer to an array (with "ninv" * elements) of pointers to arrays of int containing the set of opcodes * (cast to int) for each inverse transformation function. The number * of opcodes produced for each function is given by the first element * of the opcode array. * * Both the returned array of pointers, and the arrays of int to which * they point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. * * If the right hand sides (including the "=" sign) of all the supplied * functions are absent, then this indicates an undefined transformation * and the returned pointer value will be NULL. An error results if * an "=" sign is present but no expression follows it. * fwdcon * Address in which to return a pointer to an array (with "nfwd" * elements) of pointers to arrays of double containing the set of * constants for each forward transformation function. * * Both the returned array of pointers, and the arrays of double to which * they point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. Note * that any of the pointers to the arrays of double may be NULL if no * constants are associated with a particular function. * * If the forward transformation is undefined, then the returned pointer * value will be NULL. * invcon * Address in which to return a pointer to an array (with "ninv" * elements) of pointers to arrays of double containing the set of * constants for each inverse transformation function. * * Both the returned array of pointers, and the arrays of double to which * they point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. Note * that any of the pointers to the arrays of double may be NULL if no * constants are associated with a particular function. * * If the inverse transformation is undefined, then the returned pointer * value will be NULL. * fwdstack * Pointer to an int in which to return the size of the push-down stack * required to evaluate the forward transformation functions. * invstack * Pointer to an int in which to return the size of the push-down stack * required to evaluate the inverse transformation functions. * status * Pointer to the inherited status variable. * Notes: * - A value of NULL will be returned for the "*fwdcode", "*invcode", * "*fwdcon" and "*invcon" pointers and a value of zero will be returned * for the "*fwdstack" and "*invstack" values if this function is invoked * with the global error status set, or if it should fail for any reason. */ /* Local Variables: */ char **exprs; /* Pointer to array of expressions */ char **var; /* Pointer to array of variable names */ const char **strings; /* Pointer to temporary array of strings */ int ifun; /* Loop counter for functions */ int nvar; /* Number of variables to extract */ int stacksize; /* Required stack size */ /* Initialise. */ *fwdcode = NULL; *invcode = NULL; *fwdcon = NULL; *invcon = NULL; *fwdstack = 0; *invstack = 0; nvar = 0; /* Check the global error status. */ if ( !astOK ) return; /* Further initialisation. */ exprs = NULL; var = NULL; /* Compile the forward transformation. */ /* ----------------------------------- */ /* Allocate space for an array of pointers to the functions from which we will extract variable names. */ strings = astMalloc( sizeof( char * ) * (size_t) ( nin + nfwd ) ); /* Fill the first elements of this array with pointers to the inverse transformation functions ("nin" in number) which yield the final input values. These will have the names of the input variables on their left hand sides. */ if ( astOK ) { nvar = 0; for ( ifun = ninv - nin; ifun < ninv; ifun++ ) { strings[ nvar++ ] = invfun[ ifun ]; } /* Fill the remaining elements of the array with pointers to the forward transformation functions. These will have the names of any intermediate variables plus the final output variables on their left hand sides. */ for ( ifun = 0; ifun < nfwd; ifun++ ) strings[ nvar++ ] = fwdfun[ ifun ]; /* Extract the variable names from the left hand sides of these functions and check them for validity and absence of duplication. */ ExtractVariables( method, class, nvar, strings, nin, nout, nfwd, ninv, 1, &var, status ); } /* Free the temporary array of string pointers. */ strings = astFree( strings ); /* Extract the expressions from the right hand sides of the forward transformation functions. */ ExtractExpressions( method, class, nfwd, fwdfun, 1, &exprs, status ); /* If OK, and the forward transformation is defined, then allocate and initialise space for an array of pointers to the opcodes for each expression and, similarly, for the constants for each expression. */ if ( astOK && exprs ) { MALLOC_POINTER_ARRAY( *fwdcode, int *, nfwd ) MALLOC_POINTER_ARRAY( *fwdcon, double *, nfwd ) /* If OK, loop to compile each of the expressions, storing pointers to the resulting opcodes and constants in the arrays allocated above. On each loop, we make progressively more of the variable names in "var" visible to the compilation function. This ensures that each expression can only use variables which have been defined earlier. */ if ( astOK ) { for ( ifun = 0; ifun < nfwd; ifun++ ) { CompileExpression( method, class, exprs[ ifun ], nin + ifun, (const char **) var, &( *fwdcode )[ ifun ], &( *fwdcon )[ ifun ], &stacksize, status ); /* If an error occurs, then report contextual information and quit. */ if ( !astOK ) { astError( astStatus, "Error in forward transformation function %d.", status, ifun + 1 ); break; } /* If OK, calculate the maximum evaluation stack size required by any of the expressions. */ *fwdstack = ( *fwdstack > stacksize ) ? *fwdstack : stacksize; } } } /* Free the memory containing the extracted expressions and variables. */ FREE_POINTER_ARRAY( exprs, nfwd ) FREE_POINTER_ARRAY( var, nvar ) /* Compile the inverse transformation. */ /* ----------------------------------- */ /* Allocate space for an array of pointers to the functions from which we will extract variable names. */ strings = astMalloc( sizeof( char * ) * (size_t) ( nout + ninv ) ); /* Fill the first elements of this array with pointers to the forward transformation functions ("nout" in number) which yield the final output values. These will have the names of the output variables on their left hand sides. */ if ( astOK ) { nvar = 0; for ( ifun = nfwd - nout; ifun < nfwd; ifun++ ) { strings[ nvar++ ] = fwdfun[ ifun ]; } /* Fill the remaining elements of the array with pointers to the inverse transformation functions. These will have the names of any intermediate variables plus the final input variables on their left hand sides. */ for ( ifun = 0; ifun < ninv; ifun++ ) strings[ nvar++ ] = invfun[ ifun ]; /* Extract the variable names from the left hand sides of these functions and check them for validity and absence of duplication. */ ExtractVariables( method, class, nvar, strings, nin, nout, nfwd, ninv, 0, &var, status ); } /* Free the temporary array of string pointers. */ strings = astFree( strings ); /* Extract the expressions from the right hand sides of the inverse transformation functions. */ ExtractExpressions( method, class, ninv, invfun, 0, &exprs, status ); /* If OK, and the forward transformation is defined, then allocate and initialise space for an array of pointers to the opcodes for each expression and, similarly, for the constants for each expression. */ if ( astOK && exprs ) { MALLOC_POINTER_ARRAY( *invcode, int *, ninv ) MALLOC_POINTER_ARRAY( *invcon, double *, ninv ) /* If OK, loop to compile each of the expressions, storing pointers to the resulting opcodes and constants in the arrays allocated above. On each loop, we make progressively more of the variable names in "var" visible to the compilation function. This ensures that each expression can only use variables which have been defined earlier. */ if ( astOK ) { for ( ifun = 0; ifun < ninv; ifun++ ) { CompileExpression( method, class, exprs[ ifun ], nout + ifun, (const char **) var, &( *invcode )[ ifun ], &( *invcon )[ ifun ], &stacksize, status ); /* If an error occurs, then report contextual information and quit. */ if ( !astOK ) { astError( astStatus, "Error in inverse transformation function %d.", status, ifun + 1 ); break; } /* If OK, calculate the maximum evaluation stack size required by any of the expressions. */ *invstack = ( *invstack > stacksize ) ? *invstack : stacksize; } } } /* Free the memory containing the extracted expressions and variables. */ FREE_POINTER_ARRAY( exprs, ninv ) FREE_POINTER_ARRAY( var, nvar ) /* If an error occurred, then free all remaining allocated memory and reset the output values. */ if ( !astOK ) { FREE_POINTER_ARRAY( *fwdcode, nfwd ) FREE_POINTER_ARRAY( *invcode, ninv ) FREE_POINTER_ARRAY( *fwdcon, nfwd ) FREE_POINTER_ARRAY( *invcon, ninv ) *fwdstack = 0; *invstack = 0; } } static int DefaultSeed( const Rcontext *context, int *status ) { /* * Name: * DefaultSeed * Purpose: * Generate an unpredictable seed for a random number generator. * Type: * Private function. * Synopsis: * #include "mathmap.h" * int DefaultSeed( Rcontext *context, int *status ) * Class Membership: * MathMap member function. * Description: * On each invocation this function returns an integer value which is * highly unpredictable. This value may be used as a default seed for the * random number generator associated with a MathMap, so that it * generates a different sequence on each occasion. * Parameters: * context * Pointer to the random number generator context associated with * the MathMap. * status * Pointer to the inherited status variable. * Returned Value: * The unpredictable integer. * Notes: * - This function does not perform error checking and will execute even * if the global error status is set. */ /* Local Constants: */ const int nwarm = 5; /* Number of warm-up iterations */ const long int a = 8121L; /* Constants for random number generator... */ const long int c = 28411L; const long int m = 134456L; /* Local Variables; */ int iwarm; /* Loop counter for warm-up iterations */ static long init = 0; /* Local initialisation performed? */ static long int rand; /* Local random integer */ unsigned long int bits; /* Bit pattern for producing result */ /* On the first invocation, initialise a local random number generator to a value derived by combining bit patterns obtained from the system clock and the processor time used. The result needs to be positive and lie in the range 0 to "m-1". */ LOCK_MUTEX5 if ( !init ) { rand = (long int) ( ( (unsigned long int) time( NULL ) ^ (unsigned long int) clock() ) % (unsigned long int) m ); /* These values will typically only change in their least significant bits between programs run successively, but by using the bit pattern as a seed, we ensure that these differences are rapidly propagated to other bits. To hasten this process, we "warm up" the local generator with a few iterations. This is a quick and dirty generator using constants from Press et al. (Numerical recipes). */ for ( iwarm = 0; iwarm < nwarm; iwarm++ ) { rand = ( rand * a + c ) % m; } /* Note that this initialisation has been performed. */ init = 1; } UNLOCK_MUTEX5 /* Generate a new bit pattern from the system time. Apart from the first invocation, this will be a different time to that used above. */ bits = (unsigned long int) time( NULL ); /* Mask in a pattern derived from the CPU time used. */ bits ^= (unsigned long int) clock(); /* The system time may change quite slowly (e.g. every second), so also mask in the address of the random number generator context supplied. This makes the seed depend on which MathMap is in use. */ bits ^= (unsigned long int) context; /* Now mask in the last random integer produced by the random number generator whose context has been supplied. This makes the seed depend on the MathMap's past use of random numbers. */ bits ^= (unsigned long int) context->random_int; /* Finally, in order to produce different seeds when this function is invoked twice in rapid succession on the same object (with no intermediate processing), we also mask in a pseudo-random value generated here. Generate the next local random integer. */ rand = ( rand * a + c ) % m; /* We then scale this value to give an integer in the range 0 to ULONG_MAX and mask the corresponding bit pattern into our seed. */ bits ^= (unsigned long int) ( ( (double) rand / (double) ( m - 1UL ) ) * ( ( (double) ULONG_MAX + 1.0 ) * ( 1.0 - DBL_EPSILON ) ) ); /* Return the integer value of the seed (which may involve discarding some unwanted bits). */ return (int) bits; } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two MathMaps are equivalent. * Type: * Private function. * Synopsis: * #include "mapping.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * MathMap member function (over-rides the astEqual protected * method inherited from the Object class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two MathMaps are equivalent. * Parameters: * this * Pointer to the first Object (a MathMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the MathMaps are equivalent, zero otherwise. * Notes: * - The two MathMaps are considered equivalent if the combination of * the first in series with the inverse of the second simplifies to a * UnitMap. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstMathMap *that; /* Pointer to the second MathMap structure */ AstMathMap *this; /* Pointer to the first MathMap structure */ double **that_con; /* Lists of constants from "that" */ double **this_con; /* Lists of constants from "this" */ int **that_code; /* Lists of opcodes from "that" */ int **this_code; /* Lists of opcodes from "this" */ int code; /* Opcode value */ int icode; /* Opcode index */ int icon; /* Constant index */ int ifun; /* Function index */ int ncode; /* No. of opcodes for current "this" function */ int ncode_that; /* No. of opcodes for current "that" function */ int nin; /* Number of inputs */ int nout; /* Number of outputs */ int pass; /* Check fwd or inv */ int result; /* Result value to return */ int that_nfun; /* Number of functions from "that" */ int this_nfun; /* Number of functions from "this" */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two MathMap structures. */ this = (AstMathMap *) this_object; that = (AstMathMap *) that_object; /* Check the second object is a MathMap. We know the first is a MathMap since we have arrived at this implementation of the virtual function. */ if( astIsAMathMap( that ) ) { /* Check they have the same number of inputs and outputs */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNout( that ) == nout && astGetNin( that ) == nin ) { /* Assume equality. */ result = 1; /* The first pass through this next loop compares forward functions, and the second pass compares inverse functions. */ for( pass = 0; pass < 2 && result; pass++ ) { /* On the first pass, get pointers to the lists of opcodes and constants for the effective forward transformations (taking into account the value of the Invert attribute), together with the number of such functions. */ if( pass == 0 ) { if( !astGetInvert( this ) ) { this_code = this->fwdcode; this_con = this->fwdcon; this_nfun = this->nfwd; } else { this_code = this->invcode; this_con = this->invcon; this_nfun = this->ninv; } if( !astGetInvert( that ) ) { that_code = that->fwdcode; that_con = that->fwdcon; that_nfun = that->nfwd; } else { that_code = that->invcode; that_con = that->invcon; that_nfun = that->ninv; } /* On the second pass, get pointers to the lists of opcodes and constants for the effective inverse transformations, together with the number of such functions. */ } else { if( astGetInvert( this ) ) { this_code = this->fwdcode; this_con = this->fwdcon; this_nfun = this->nfwd; } else { this_code = this->invcode; this_con = this->invcon; this_nfun = this->ninv; } if( astGetInvert( that ) ) { that_code = that->fwdcode; that_con = that->fwdcon; that_nfun = that->nfwd; } else { that_code = that->invcode; that_con = that->invcon; that_nfun = that->ninv; } } /* Check that "this" and "that" have the same number of functions */ if( that_nfun != this_nfun ) result = 0; /* Loop round each function. */ for( ifun = 0; ifun < this_nfun && result; ifun++ ) { /* The first element in the opcode array is the number of subsequent opcodes. Obtain and compare these counts. */ ncode = this_code ? this_code[ ifun ][ 0 ] : 0; ncode_that = that_code ? that_code[ ifun ][ 0 ] : 0; if( ncode != ncode_that ) result = 0; /* Compare the following opcodes. Some opcodes consume constants from the list of constants associated with the MathMap. Compare the constants for such opcodes. */ icon = 0; for( icode = 0; icode < ncode && result; icode++ ){ code = this_code[ ifun ][ icode ]; if( that_code[ ifun ][ icode ] != code ) { result = 0; } else if( code == OP_LDCON || code == OP_LDVAR || code == OP_MAX || code == OP_MIN ) { if( this_con[ ifun ][ icon ] != that_con[ ifun ][ icon ] ) { result = 0; } else { icon++; } } } } } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static void EvaluateFunction( Rcontext *rcontext, int npoint, const double **ptr_in, const int *code, const double *con, int stacksize, double *out, int *status ) { /* * Name: * EvaluateFunction * Purpose: * Evaluate a compiled function. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void EvaluateFunction( Rcontext *rcontext, int npoint, * const double **ptr_in, const int *code, * const double *con, int stacksize, double *out, int *status ) * Class Membership: * MathMap member function. * Description: * This function implements a "virtual machine" which executes operations * on an arithmetic stack in order to evaluate transformation functions. * Each operation is specified by an input operation code (opcode) and * results in the execution of a vector operation on a stack. The final * result, after executing all the supplied opcodes, is returned as a * vector. * * This function detects arithmetic errors (such as overflow and division * by zero) and propagates any "bad" coordinate values, including those * present in the input, to the output. * Parameters: * npoint * The number of points to be transformd (i.e. the size of the vector * of values on which operations are to be performed). * ptr_in * Pointer to an array of pointers to arrays of double (with "npoint" * elements). These arrays should contain the input coordinate values, * such that coordinate number "coord" for point number "point" can be * found in "ptr_in[coord][point]". * code * Pointer to an array of int containing the set of opcodes (cast to int) * for the operations to be performed. The first element of this array * should contain a count of the number of opcodes which follow. * con * Pointer to an array of double containing the set of constants required * to evaluate the function (this may be NULL if no constants are * required). * stacksize * The size of the stack required to evaluate the expression using the * opcodes and constants supplied. This value should be calculated during * expression compilation. * out * Pointer to an array of double (with "npoint" elements) in which to * return the vector of result values. * status * Pointer to the inherited status variable. */ /* Local Constants: */ const int bits = /* Number of bits in an unsigned long */ sizeof( unsigned long ) * CHAR_BIT; const double eps = /* Smallest number subtractable from 2.0 */ 2.0 * DBL_EPSILON; const double scale = /* 2.0 raised to the power "bits" */ ldexp( 1.0, bits ); const double scale1 = /* 2.0 raised to the power "bits-1" */ scale * 0.5; const double rscale = /* Reciprocal scale factor */ 1.0 / scale; const double rscale1 = /* Reciprocal initial scale factor */ 1.0 / scale1; const int nblock = /* Number of blocks of bits to process */ ( sizeof( double ) + sizeof( unsigned long ) - 1 ) / sizeof( unsigned long ); const unsigned long signbit = /* Mask for extracting sign bit */ 1UL << ( bits - 1 ); /* Local Variables: */ double **stack; /* Array of pointers to stack elements */ double *work; /* Pointer to stack workspace */ double *xv1; /* Pointer to first argument vector */ double *xv2; /* Pointer to second argument vector */ double *xv3; /* Pointer to third argument vector */ double *xv; /* Pointer to sole argument vector */ double *y; /* Pointer to result */ double *yv; /* Pointer to result vector */ double abs1; /* Absolute value (temporary variable) */ double abs2; /* Absolute value (temporary variable) */ double frac1; /* First (maybe normalised) fraction */ double frac2; /* Second (maybe normalised) fraction */ double frac; /* Sole normalised fraction */ double newexp; /* New power of 2 exponent value */ double ran; /* Random number */ double result; /* Function result value */ double unscale; /* Factor for removing scaling */ double value; /* Value to be assigned to stack vector */ double x1; /* First argument value */ double x2; /* Second argument value */ double x3; /* Third argument value */ double x; /* Sole argument value */ int expon1; /* First power of 2 exponent */ int expon2; /* Second power of 2 exponent */ int expon; /* Sole power of 2 exponent */ int iarg; /* Loop counter for arguments */ int iblock; /* Loop counter for blocks of bits */ int icode; /* Opcode value */ int icon; /* Counter for number of constants used */ int istk; /* Loop counter for stack elements */ int ivar; /* Input variable number */ int narg; /* Number of function arguments */ int ncode; /* Number of opcodes to process */ int point; /* Loop counter for stack vector elements */ int sign; /* Argument is non-negative? */ int tos; /* Top of stack index */ static double d2r; /* Degrees to radians conversion factor */ static double log2; /* Natural logarithm of 2.0 */ static double pi; /* Value of PI */ static double r2d; /* Radians to degrees conversion factor */ static double rsafe_sq; /* Reciprocal of "safe_sq" */ static double safe_sq; /* Huge value that can safely be squared */ static int init = 0; /* Initialisation performed? */ unsigned long b1; /* Block of bits from first argument */ unsigned long b2; /* Block of bits from second argument */ unsigned long b; /* Block of bits for result */ unsigned long neg; /* Result is negative? (sign bit) */ /* Check the global error status. */ if ( !astOK ) return; /* If this is the first invocation of this function, then initialise constant values. */ LOCK_MUTEX2 if ( !init ) { /* Trigonometrical conversion factors. */ pi = acos( -1.0 ); r2d = 180.0 / pi; d2r = pi / 180.0; /* Natural logarithm of 2.0. */ log2 = log( 2.0 ); /* This value must be safe to square without producing overflow, yet large enough that adding or subtracting 1.0 from the square makes no difference. We also need its reciprocal. */ safe_sq = 0.9 * sqrt( DBL_MAX ); rsafe_sq = 1.0 / safe_sq; /* Note that initialisation has been performed. */ init = 1; } UNLOCK_MUTEX2 /* Allocate space for an array of pointers to elements of the workspace stack (each stack element being an array of double). */ stack = astMalloc( sizeof( double * ) * (size_t) stacksize ); /* Allocate space for the stack itself. */ work = astMalloc( sizeof( double ) * (size_t) ( npoint * ( stacksize - 1 ) ) ); /* If OK, then initialise the stack pointer array to identify the start of each vector on the stack. The first element points at the output array (in which the result will be accumulated), while other elements point at successive vectors within the workspace allocated above. */ if ( astOK ) { stack[ 0 ] = out; for ( istk = 1; istk < stacksize; istk++ ) { stack[ istk ] = work + ( istk - 1 ) * npoint; } /* Define stack operations. */ /* ======================== */ /* We now define a set of macros for performing vector operations on elements of the stack. Each is in the form of a "case" block for execution in response to the appropriate operation code (opcode). */ /* Zero-argument operation. */ /* ------------------------ */ /* This macro performs a zero-argument operation, which results in the insertion of a new vector on to the stack. */ #define ARG_0(oper,setup,function) \ \ /* Test for the required opcode value. */ \ case oper: \ \ /* Perform any required initialisation. */ \ {setup;} \ \ /* Increment the top of stack index and obtain a pointer to the new stack \ element (vector). */ \ yv = stack[ ++tos ]; \ \ /* Loop to access each vector element, obtaining a pointer to it. */ \ for ( point = 0; point < npoint; point++ ) { \ y = yv + point; \ \ /* Perform the processing, which results in assignment to this element. */ \ {function;} \ } \ \ /* Break out of the "case" block. */ \ break; /* One-argument operation. */ /* ----------------------- */ /* This macro performs a one-argument operation, which processes the top stack element without changing the stack size. */ #define ARG_1(oper,function) \ \ /* Test for the required opcode value. */ \ case oper: \ \ /* Obtain a pointer to the top stack element (vector). */ \ xv = stack[ tos ]; \ \ /* Loop to access each vector element, obtaining its value and \ checking that it is not bad. */ \ for ( point = 0; point < npoint; point++ ) { \ if ( ( x = xv[ point ] ) != AST__BAD ) { \ \ /* Also obtain a pointer to the element. */ \ y = xv + point; \ \ /* Perform the processing, which uses the element's value and then \ assigns the result to this element. */ \ {function;} \ } \ } \ \ /* Break out of the "case" block. */ \ break; /* One-argument boolean operation. */ /* ------------------------------- */ /* This macro is similar in function to ARG_1 above, except that no checks are made for bad argument values. It is intended for use with boolean functions where bad values are handled explicitly. */ #define ARG_1B(oper,function) \ \ /* Test for the required opcode value. */ \ case oper: \ \ /* Obtain a pointer to the top stack element (vector). */ \ xv = stack[ tos ]; \ \ /* Loop to access each vector element, obtaining the argument value \ and a pointer to the element. */ \ for ( point = 0; point < npoint; point++ ) { \ x = xv[ point ]; \ y = xv + point; \ \ /* Perform the processing, which uses the element's value and then \ assigns the result to this element. */ \ {function;} \ } \ \ /* Break out of the "case" block. */ \ break; /* Two-argument operation. */ /* ----------------------- */ /* This macro performs a two-argument operation, which processes the top two stack elements and produces a single result, resulting in the stack size decreasing by one. In this case, we first define a macro without the "case" block statements present. */ #define DO_ARG_2(function) \ \ /* Obtain pointers to the top two stack elements (vectors), decreasing \ the top of stack index by one. */ \ xv2 = stack[ tos-- ]; \ xv1 = stack[ tos ]; \ \ /* Loop to access each vector element, obtaining the value of the \ first argument and checking that it is not bad. */ \ for ( point = 0; point < npoint; point++ ) { \ if ( ( x1 = xv1[ point ] ) != AST__BAD ) { \ \ /* Also obtain a pointer to the element which is to receive the \ result. */ \ y = xv1 + point; \ \ /* Obtain the value of the second argument, again checking that it is \ not bad. */ \ if ( ( x2 = xv2[ point ] ) != AST__BAD ) { \ \ /* Perform the processing, which uses the two argument values and then \ assigns the result to the appropriate top of stack element. */ \ {function;} \ \ /* If the second argument was bad, so is the result. */ \ } else { \ *y = AST__BAD; \ } \ } \ } /* This macro simply wraps the one above up in a "case" block. */ #define ARG_2(oper,function) \ case oper: \ DO_ARG_2(function) \ break; /* Two-argument boolean operation. */ /* ------------------------------- */ /* This macro is similar in function to ARG_2 above, except that no checks are made for bad argument values. It is intended for use with boolean functions where bad values are handled explicitly. */ #define ARG_2B(oper,function) \ \ /* Test for the required opcode value. */ \ case oper: \ \ /* Obtain pointers to the top two stack elements (vectors), decreasing \ the top of stack index by one. */ \ xv2 = stack[ tos-- ]; \ xv1 = stack[ tos ]; \ \ /* Loop to access each vector element, obtaining the value of both \ arguments and a pointer to the element which is to receive the \ result. */ \ for ( point = 0; point < npoint; point++ ) { \ x1 = xv1[ point ]; \ x2 = xv2[ point ]; \ y = xv1 + point; \ \ /* Perform the processing, which uses the two argument values and then \ assigns the result to the appropriate top of stack element. */ \ {function;} \ } \ \ /* Break out of the "case" block. */ \ break; /* Three-argument boolean operation. */ /* --------------------------------- */ /* This macro is similar in function to ARG_2B above, except that it takes three values of the stack and puts one back. It performs no checks for bad values. */ #define ARG_3B(oper,function) \ \ /* Test for the required opcode value. */ \ case oper: \ \ /* Obtain pointers to the top three stack elements (vectors), decreasing \ the top of stack index by two. */ \ xv3 = stack[ tos-- ]; \ xv2 = stack[ tos-- ]; \ xv1 = stack[ tos ]; \ \ /* Loop to access each vector element, obtaining the value of all 3 \ arguments and a pointer to the element which is to receive the \ result. */ \ for ( point = 0; point < npoint; point++ ) { \ x1 = xv1[ point ]; \ x2 = xv2[ point ]; \ x3 = xv3[ point ]; \ y = xv1 + point; \ \ /* Perform the processing, which uses the three argument values and then \ assigns the result to the appropriate top of stack element. */ \ {function;} \ } \ \ /* Break out of the "case" block. */ \ break; /* Define arithmetic operations. */ /* ============================= */ /* We now define macros for performing some of the arithmetic operations we will require in a "safe" way - i.e. trapping numerical problems such as overflow and invalid arguments and translating them into the AST__BAD value. */ /* Absolute value. */ /* --------------- */ /* This is just shorthand. */ #define ABS(x) ( ( (x) >= 0.0 ) ? (x) : -(x) ) /* Integer part. */ /* ------------- */ /* This implements rounding towards zero without involving conversion to an integer (which could overflow). */ #define INT(x) ( ( (x) >= 0.0 ) ? floor( (x) ) : ceil( (x) ) ) /* Trap maths overflow. */ /* -------------------- */ /* This macro calls a C maths library function and checks for overflow in the result. */ #define CATCH_MATHS_OVERFLOW(function) \ ( \ \ /* Clear the "errno" value. */ \ errno = 0, \ \ /* Evaluate the function. */ \ result = (function), \ \ /* Check if "errno" and the returned result indicate overflow and \ return the appropriate result. */ \ ( ( errno == ERANGE ) && ( ABS( result ) == HUGE_VAL ) ) ? AST__BAD : \ result \ ) /* Trap maths errors. */ /* ------------------ */ /* This macro is similar to the one above, except that it also checks for domain errors (i.e. invalid argument values). */ #define CATCH_MATHS_ERROR(function) \ ( \ \ /* Clear the "errno" value. */ \ errno = 0, \ \ /* Evaluate the function. */ \ result = (function), \ \ /* Check if "errno" and the returned result indicate a domain error or \ overflow and return the appropriate result. */ \ ( ( errno == EDOM ) || \ ( ( errno == ERANGE ) && ( ABS( result ) == HUGE_VAL ) ) ) ? \ AST__BAD : result \ ) /* Tri-state boolean OR. */ /* --------------------- */ /* This evaluates a boolean OR using tri-state logic. For example, "a||b" may evaluate to 1 if "a" is bad but "b" is non-zero, so that the normal rules of bad value propagation do not apply. */ #define TRISTATE_OR(x1,x2) \ \ /* Test if the first argument is bad. */ \ ( (x1) == AST__BAD ) ? ( \ \ /* If so, test the second argument. */ \ ( ( (x2) == 0.0 ) || ( (x2) == AST__BAD ) ) ? AST__BAD : 1.0 \ ) : ( \ \ /* Test if the second argument is bad. */ \ ( (x2) == AST__BAD ) ? ( \ \ /* If so, test the first argument. */ \ ( (x1) == 0.0 ) ? AST__BAD : 1.0 \ \ /* If neither argument is bad, use the normal OR operator. */ \ ) : ( \ ( (x1) != 0.0 ) || ( (x2) != 0.0 ) \ ) \ ) /* Tri-state boolean AND. */ /* ---------------------- */ /* This evaluates a boolean AND using tri-state logic. */ #define TRISTATE_AND(x1,x2) \ \ /* Test if the first argument is bad. */ \ ( (x1) == AST__BAD ) ? ( \ \ /* If so, test the second argument. */ \ ( (x2) != 0.0 ) ? AST__BAD : 0.0 \ ) : ( \ \ /* Test if the second argument is bad. */ \ ( (x2) == AST__BAD ) ? ( \ \ /* If so, test the first argument. */ \ ( (x1) != 0.0 ) ? AST__BAD : 0.0 \ \ /* If neither argument is bad, use the normal AND operator. */ \ ) : ( \ ( (x1) != 0.0 ) && ( (x2) != 0.0 ) \ ) \ ) /* Safe addition. */ /* -------------- */ /* This macro performs addition while avoiding possible overflow. */ #define SAFE_ADD(x1,x2) ( \ \ /* Test if the first argument is non-negative. */ \ ( (x1) >= 0.0 ) ? ( \ \ /* If so, then we can perform addition if the second argument is \ non-positive. Otherwise, we must calculate the most positive safe \ second argument value that can be added and test for this (the test \ itself is safe against overflow). */ \ ( ( (x2) <= 0.0 ) || ( ( (DBL_MAX) - (x1) ) >= (x2) ) ) ? ( \ \ /* Perform addition if it is safe, otherwise return AST__BAD. */ \ (x1) + (x2) \ ) : ( \ AST__BAD \ ) \ \ /* If the first argument is negative, then we can perform addition if \ the second argument is non-negative. Otherwise, we must calculate the \ most negative second argument value that can be added and test for \ this (the test itself is safe against overflow). */ \ ) : ( \ ( ( (x2) >= 0.0 ) || ( ( (DBL_MAX) + (x1) ) >= -(x2) ) ) ? ( \ \ /* Perform addition if it is safe, otherwise return AST__BAD. */ \ (x1) + (x2) \ ) : ( \ AST__BAD \ ) \ ) \ ) /* Safe subtraction. */ /* ----------------- */ /* This macro performs subtraction while avoiding possible overflow. */ #define SAFE_SUB(x1,x2) ( \ \ /* Test if the first argument is non-negative. */ \ ( (x1) >= 0.0 ) ? ( \ \ /* If so, then we can perform subtraction if the second argument is \ also non-negative. Otherwise, we must calculate the most negative safe \ second argument value that can be subtracted and test for this (the \ test itself is safe against overflow). */ \ ( ( (x2) >= 0.0 ) || ( ( (DBL_MAX) - (x1) ) >= -(x2) ) ) ? ( \ \ /* Perform subtraction if it is safe, otherwise return AST__BAD. */ \ (x1) - (x2) \ ) : ( \ AST__BAD \ ) \ \ /* If the first argument is negative, then we can perform subtraction \ if the second argument is non-positive. Otherwise, we must calculate \ the most positive second argument value that can be subtracted and \ test for this (the test itself is safe against overflow). */ \ ) : ( \ ( ( (x2) <= 0.0 ) || ( ( (DBL_MAX) + (x1) ) >= (x2) ) ) ? ( \ \ /* Perform subtraction if it is safe, otherwise return AST__BAD. */ \ (x1) - (x2) \ ) : ( \ AST__BAD \ ) \ ) \ ) /* Safe multiplication. */ /* -------------------- */ /* This macro performs multiplication while avoiding possible overflow. */ #define SAFE_MUL(x1,x2) ( \ \ /* Multiplication is safe if the absolute value of either argument is \ unity or less. Otherwise, we must use the first argument to calculate \ the maximum absolute value that the second argument may have and test \ for this (the test itself is safe against overflow). */ \ ( ( ( abs1 = ABS( (x1) ) ) <= 1.0 ) || \ ( ( abs2 = ABS( (x2) ) ) <= 1.0 ) || \ ( ( (DBL_MAX) / abs1 ) >= abs2 ) ) ? ( \ \ /* Perform multiplication if it is safe, otherwise return AST__BAD. */ \ (x1) * (x2) \ ) : ( \ AST__BAD \ ) \ ) /* Safe division. */ /* -------------- */ /* This macro performs division while avoiding possible overflow. */ #define SAFE_DIV(x1,x2) ( \ \ /* Division is unsafe if the second argument is zero. Otherwise, it is \ safe if the abolute value of the second argument is unity or \ more. Otherwise, we must use the second argument to calculate the \ maximum absolute value that the first argument may have and test for \ this (the test itself is safe against overflow). */ \ ( ( (x2) != 0.0 ) && \ ( ( ( abs2 = ABS( (x2) ) ) >= 1.0 ) || \ ( ( (DBL_MAX) * abs2 ) >= ABS( (x1) ) ) ) ) ? ( \ \ /* Perform division if it is safe, otherwise return AST__BAD. */ \ (x1) / (x2) \ ) : ( \ AST__BAD \ ) \ ) /* Bit-shift operation. */ /* -------------------- */ /* This macro shifts the bits in a double value a specified number of places to the left, which simply corresponds to multiplying by the appropriate power of two. */ #define SHIFT_BITS(x1,x2) ( \ \ /* Decompose the value into a normalised fraction and a power of 2. */ \ frac = frexp( (x1), &expon ), \ \ /* Calculate the new power of 2 which should apply after the shift, \ rounding towards zero to give an integer value. */ \ newexp = INT( (x2) ) + (double) expon, \ \ /* If the new exponent is too negative to convert to an integer, then \ the result must underflow to zero. */ \ ( newexp < (double) -INT_MAX ) ? ( \ 0.0 \ \ /* Otherwise, if it is too positive to convert to an integer, then the \ result must overflow, unless the normalised fraction is zero. */ \ ) : ( ( newexp > (double) INT_MAX ) ? ( \ ( frac == 0.0 ) ? 0.0 : AST__BAD \ \ /* Otherwise, convert the new exponent to an integer and apply \ it. Trap any overflow which may still occur. */ \ ) : ( \ CATCH_MATHS_OVERFLOW( ldexp( frac, (int) newexp ) ) \ ) ) \ ) /* Two-argument bit-wise boolean operation. */ /* ---------------------------------------- */ /* This macro expands to code which performs a bit-wise boolean operation on a pair of arguments and assigns the result to the variable "result". It operates on floating point (double) values, which are regarded as if they are fixed-point binary numbers with negative values expressed in twos-complement notation. This means that it delivers the same results for integer values as the normal (integer) C bit-wise operations. However, it will also operate on the fraction bits of floating point numbers. It also offers greater precision (the first 53 or so significant bits of the result being preserved for typical IEEE floating point implementations). */ #define BIT_OPER(oper,x1,x2) \ \ /* Convert each argument to a normalised fraction in the range \ [0.5,1.0) and a power of two exponent, removing any sign \ information. */ \ frac1 = frexp( ABS( (x1) ), &expon1 ); \ frac2 = frexp( ABS( (x2) ), &expon2 ); \ \ /* Set "expon" to be the larger of the two exponents. If the two \ exponents are not equal, divide the fraction with the smaller exponent \ by 2 to the power of the exponent difference. This gives both \ fractions the same effective exponent (although one of them may no \ longer be normalised). Note that overflow is avoided because all \ numbers remain less than 1.0, but underflow may occur. */ \ expon = expon1; \ if ( expon2 > expon1 ) { \ expon = expon2; \ frac1 = ldexp( frac1, expon1 - expon ); \ } else if ( expon1 > expon2 ) { \ frac2 = ldexp( frac2, expon2 - expon ); \ } \ \ /* If either of the original arguments is negative, we now subtract \ the corresponding fraction from 2.0. If we think of the fraction as \ represented in fixed-point binary notation, this corresponds to \ converting negative numbers into the twos-complement form normally used \ for integers (the sign bit being the bit with value 1) instead \ of having a separate sign bit as for floating point numbers. \ \ Note that one of the fractions may have underflowed during the \ scaling above. In that case (if the original argument was negative), \ we must subtract the value "eps" (= 2.0 * DBL_EPSILON) from 2.0 \ instead, so that we produce the largest number less than 2.0. In \ twos-complement notation this represents the smallest possible \ negative number and corresponds to extending the sign bit of the \ original number up into more significant bits. This causes all bits to \ be set as we require (rather than all being clear if the underflow \ is simply ignored). */ \ if ( (x1) < 0.0 ) frac1 = 2.0 - ( ( frac1 > eps ) ? frac1 : eps ); \ if ( (x2) < 0.0 ) frac2 = 2.0 - ( ( frac2 > eps ) ? frac2 : eps ); \ \ /* We now extract the bits from the fraction values into integer \ variables so that we may perform bit-wise operations on them. However, \ since a double may be longer than any available integer, we may \ have to handle several successive blocks of bits individually. */ \ \ /* Extract the first block of bits by scaling by the required power of \ 2 to shift the required bits to the left of the binary point. Then \ extract the integer part. Note that this initial shift is one bit less \ than the number of bits in an unsigned long, because we have \ introduced an extra sign bit. */ \ frac1 *= scale1; \ frac2 *= scale1; \ b1 = (unsigned long) frac1; \ b2 = (unsigned long) frac2; \ \ /* Perform the required bit-wise operation on the extracted blocks of \ bits. */ \ b = b1 oper b2; \ \ /* Extract the sign bit from this initial result. This determines \ whether the final result bit pattern should represent a negative \ floating point number. */ \ neg = b & signbit; \ \ /* Initialise the floating point result by setting it to the integer \ result multipled by the reciprocal of the scale factor used to shift \ the bits above. This returns the result bits to their correct \ significance. */ \ unscale = rscale1; \ result = (double) b * unscale; \ \ /* We now loop to extract and process further blocks of bits (if \ present). The number of blocks is determined by the relative lengths \ of a double and an unsigned long. In practice, some bits of the double \ will be used by its exponent, so the last block may be incomplete and \ will simply be padded with zeros. */ \ for ( iblock = 1; iblock < nblock; iblock++ ) { \ \ /* Subtract the integer part (which has already been processed) from \ each fraction, to leave the bits which remain to be processed. Then \ multiply by a scale factor to shift the next set of bits to the left \ of the binary point. This time, we use as many bits as will fit into \ an unsigned long. */ \ frac1 = ( frac1 - (double) b1 ) * scale; \ frac2 = ( frac2 - (double) b2 ) * scale; \ \ /* Extract the integer part, which contains the required bits. */ \ b1 = (unsigned long) frac1; \ b2 = (unsigned long) frac2; \ \ /* Perform the required bit-wise operation on the extracted blocks of \ bits. */ \ b = b1 oper b2; \ \ /* Update the result floating point value by adding the new integer \ result multiplied by a scale factor to return the bits to their \ original significance. */ \ unscale *= rscale; \ result += (double) b * unscale; \ } \ \ /* If the (normalised fraction) result represents a negative number, \ then subtract 2.0 from it (equivalent to subtracting it from 2 and \ negating the result). This converts back to using a separate sign bit \ instead of twos-complement notation. */ \ if ( neg ) result -= 2.0; \ \ /* Scale by the required power of 2 to remove the initial \ normalisation applied and assign the result to the "result" \ variable. */ \ result = ldexp( result, expon ) /* Gaussian random number. */ /* ----------------------- */ /* This macro expands to code which assigns a pseudo-random value to the "result" variable. The value is drawn from a Gaussian distribution with mean "x1" and standard deviation "ABS(x2)". */ #define GAUSS(x1,x2) \ \ /* Loop until a satisfactory result is obtained. */ \ do { \ \ /* Obtain a value drawn from a standard Gaussian distribution. */ \ ran = Gauss( rcontext, status ); \ \ /* Multiply by "ABS(x2)", trapping possible overflow. */ \ result = ABS( (x2) ); \ result = SAFE_MUL( ran, result ); \ \ /* If OK, add "x1", again trapping possible overflow. */ \ if ( result != AST__BAD ) result = SAFE_ADD( result, (x1) ); \ \ /* Continue generating values until one is found which does not cause \ overflow. */ \ } while ( result == AST__BAD ); /* Implement the stack-based arithmetic. */ /* ===================================== */ /* Initialise the top of stack index and constant counter. */ tos = -1; icon = 0; /* Determine the number of opcodes to be processed and loop to process them, executing the appropriate "case" block for each one. */ ncode = code[ 0 ]; for ( icode = 1; icode <= ncode; icode++ ) { switch ( (Oper) code[ icode ] ) { /* Ignore any null opcodes (which shouldn't occur). */ case OP_NULL: break; /* Otherwise, perform the required vector operation on the stack... */ /* User-supplied constants and variables. */ /* -------------------------------------- */ /* Loading a constant involves incrementing the constant count and assigning the next constant's value to the top of stack element. */ ARG_0( OP_LDCON, value = con[ icon++ ], *y = value ) /* Loading a variable involves obtaining the variable's index by consuming a constant (as above), and then copying the variable's values into the top of stack element. */ ARG_0( OP_LDVAR, ivar = (int) ( con[ icon++ ] + 0.5 ), *y = ptr_in[ ivar ][ point ] ) /* System constants. */ /* ----------------- */ /* Loading a "bad" value simply means assigning AST__BAD to the top of stack element. */ ARG_0( OP_LDBAD, ;, *y = AST__BAD ) /* The following load constants associated with the (double) floating point representation into the top of stack element. */ ARG_0( OP_LDDIG, ;, *y = (double) DBL_DIG ) ARG_0( OP_LDEPS, ;, *y = DBL_EPSILON ) ARG_0( OP_LDMAX, ;, *y = DBL_MAX ) ARG_0( OP_LDMAX10E, ;, *y = (double) DBL_MAX_10_EXP ) ARG_0( OP_LDMAXE, ;, *y = (double) DBL_MAX_EXP ) ARG_0( OP_LDMDIG, ;, *y = (double) DBL_MANT_DIG ) ARG_0( OP_LDMIN, ;, *y = DBL_MIN ) ARG_0( OP_LDMIN10E, ;, *y = (double) DBL_MIN_10_EXP ) ARG_0( OP_LDMINE, ;, *y = (double) DBL_MIN_EXP ) ARG_0( OP_LDRAD, ;, *y = (double) FLT_RADIX ) ARG_0( OP_LDRND, ;, *y = (double) FLT_ROUNDS ) /* Mathematical constants. */ /* ----------------------- */ /* The following load mathematical constants into the top of stack element. */ ARG_0( OP_LDE, value = exp( 1.0 ), *y = value ) ARG_0( OP_LDPI, ;, *y = pi ) /* Functions with one argument. */ /* ---------------------------- */ /* The following simply evaluate a function of the top of stack element and assign the result to the same element. */ ARG_1( OP_ABS, *y = ABS( x ) ) ARG_1( OP_ACOS, *y = ( ABS( x ) <= 1.0 ) ? acos( x ) : AST__BAD ) ARG_1( OP_ACOSD, *y = ( ABS( x ) <= 1.0 ) ? acos( x ) * r2d : AST__BAD ) ARG_1( OP_ACOSH, *y = ( x < 1.0 ) ? AST__BAD : ( ( x > safe_sq ) ? log( x ) + log2 : log( x + sqrt( x * x - 1.0 ) ) ) ) ARG_1( OP_ACOTH, *y = ( ABS( x ) <= 1.0 ) ? AST__BAD : 0.5 * ( log( ( x + 1.0 ) / ( x - 1.0 ) ) ) ) ARG_1( OP_ACSCH, *y = ( ( x == 0.0 ) ? AST__BAD : ( sign = ( x >= 0.0 ), x = ABS( x ), ( sign ? 1.0 : -1.0 ) * ( ( x < rsafe_sq ) ? log2 - log( x ) : ( x = 1.0 / x, log( x + sqrt( x * x + 1.0 ) ) ) ) ) ) ) ARG_1( OP_ASECH, *y = ( ( x <= 0 ) || ( x > 1.0 ) ) ? AST__BAD : ( ( x < rsafe_sq ) ? log2 - log( x ) : ( x = 1.0 / x, log( x + sqrt( x * x - 1.0 ) ) ) ) ) ARG_1( OP_ASIN, *y = ( ABS( x ) <= 1.0 ) ? asin( x ) : AST__BAD ) ARG_1( OP_ASIND, *y = ( ABS( x ) <= 1.0 ) ? asin( x ) * r2d : AST__BAD ) ARG_1( OP_ASINH, *y = ( sign = ( x >= 0.0 ), x = ABS( x ), ( sign ? 1.0 : -1.0 ) * ( ( x > safe_sq ) ? log( x ) + log2 : log( x + sqrt( x * x + 1.0 ) ) ) ) ) ARG_1( OP_ATAN, *y = atan( x ) ) ARG_1( OP_ATAND, *y = atan( x ) * r2d ) ARG_1( OP_ATANH, *y = ( ABS( x ) >= 1.0 ) ? AST__BAD : 0.5 * ( log( ( 1.0 + x ) / ( 1.0 - x ) ) ) ) ARG_1( OP_CEIL, *y = ceil( x ) ) ARG_1( OP_COS, *y = cos( x ) ) ARG_1( OP_COSD, *y = cos( x * d2r ) ) ARG_1( OP_COSH, *y = CATCH_MATHS_OVERFLOW( cosh( x ) ) ) ARG_1( OP_COTH, *y = ( x = tanh( x ), SAFE_DIV( 1.0, x ) ) ) ARG_1( OP_CSCH, *y = ( x = CATCH_MATHS_OVERFLOW( sinh( x ) ), ( x == AST__BAD ) ? 0.0 : SAFE_DIV( 1.0, x ) ) ) ARG_1( OP_EXP, *y = CATCH_MATHS_OVERFLOW( exp( x ) ) ) ARG_1( OP_FLOOR, *y = floor( x ) ) ARG_1( OP_INT, *y = INT( x ) ) ARG_1B( OP_ISBAD, *y = ( x == AST__BAD ) ) ARG_1( OP_LOG, *y = ( x > 0.0 ) ? log( x ) : AST__BAD ) ARG_1( OP_LOG10, *y = ( x > 0.0 ) ? log10( x ) : AST__BAD ) ARG_1( OP_NINT, *y = ( x >= 0 ) ? floor( x + 0.5 ) : ceil( x - 0.5 ) ) ARG_1( OP_POISS, *y = Poisson( rcontext, x, status ) ) ARG_1( OP_SECH, *y = ( x = CATCH_MATHS_OVERFLOW( cosh( x ) ), ( x == AST__BAD ) ? 0.0 : 1.0 / x ) ) ARG_1( OP_SIN, *y = sin( x ) ) ARG_1( OP_SINC, *y = ( x == 0.0 ) ? 1.0 : sin( x ) / x ) ARG_1( OP_SIND, *y = sin( x * d2r ) ) ARG_1( OP_SINH, *y = CATCH_MATHS_OVERFLOW( sinh( x ) ) ) ARG_1( OP_SQR, *y = SAFE_MUL( x, x ) ) ARG_1( OP_SQRT, *y = ( x >= 0.0 ) ? sqrt( x ) : AST__BAD ) ARG_1( OP_TAN, *y = CATCH_MATHS_OVERFLOW( tan( x ) ) ) ARG_1( OP_TAND, *y = tan( x * d2r ) ) ARG_1( OP_TANH, *y = tanh( x ) ) /* Functions with two arguments. */ /* ----------------------------- */ /* These evaluate a function of the top two entries on the stack. */ ARG_2( OP_ATAN2, *y = atan2( x1, x2 ) ) ARG_2( OP_ATAN2D, *y = atan2( x1, x2 ) * r2d ) ARG_2( OP_DIM, *y = ( x1 > x2 ) ? x1 - x2 : 0.0 ) ARG_2( OP_GAUSS, GAUSS( x1, x2 ); *y = result ) ARG_2( OP_MOD, *y = ( x2 != 0.0 ) ? fmod( x1, x2 ) : AST__BAD ) ARG_2( OP_POW, *y = CATCH_MATHS_ERROR( pow( x1, x2 ) ) ) ARG_2( OP_RAND, ran = Rand( rcontext, status ); *y = x1 * ran + x2 * ( 1.0 - ran ); ) ARG_2( OP_SIGN, *y = ( ( x1 >= 0.0 ) == ( x2 >= 0.0 ) ) ? x1 : -x1 ) /* Functions with three arguments. */ /* ------------------------------- */ /* These evaluate a function of the top three entries on the stack. */ ARG_3B( OP_QIF, *y = ( ( x1 ) ? ( x2 ) : ( x3 ) ) ) /* Functions with variable numbers of arguments. */ /* --------------------------------------------- */ /* These operations take a variable number of arguments, the actual number being determined by consuming a constant. We then loop to perform a 2-argument operation on the stack (as above) the required number of times. */ case OP_MAX: narg = (int) ( con[ icon++ ] + 0.5 ); for ( iarg = 0; iarg < ( narg - 1 ); iarg++ ) { DO_ARG_2( *y = ( x1 >= x2 ) ? x1 : x2 ) } break; case OP_MIN: narg = (int) ( con[ icon++ ] + 0.5 ); for ( iarg = 0; iarg < ( narg - 1 ); iarg++ ) { DO_ARG_2( *y = ( x1 <= x2 ) ? x1 : x2 ) } break; /* Unary arithmetic operators. */ /* --------------------------- */ ARG_1( OP_NEG, *y = -x ) /* Unary boolean operators. */ /* ------------------------ */ ARG_1( OP_NOT, *y = ( x == 0.0 ) ) /* Binary arithmetic operators. */ /* ---------------------------- */ ARG_2( OP_ADD, *y = SAFE_ADD( x1, x2 ) ) ARG_2( OP_SUB, *y = SAFE_SUB( x1, x2 ) ) ARG_2( OP_MUL, *y = SAFE_MUL( x1, x2 ) ) ARG_2( OP_DIV , *y = SAFE_DIV( x1, x2 ) ) /* Bit-shift operators. */ /* -------------------- */ ARG_2( OP_SHFTL, *y = SHIFT_BITS( x1, x2 ) ) ARG_2( OP_SHFTR, *y = SHIFT_BITS( x1, -x2 ) ) /* Relational operators. */ /* --------------------- */ ARG_2( OP_EQ, *y = ( x1 == x2 ) ) ARG_2( OP_GE, *y = ( x1 >= x2 ) ) ARG_2( OP_GT, *y = ( x1 > x2 ) ) ARG_2( OP_LE, *y = ( x1 <= x2 ) ) ARG_2( OP_LT, *y = ( x1 < x2 ) ) ARG_2( OP_NE, *y = ( x1 != x2 ) ) /* Bit-wise operators. */ /* ------------------- */ ARG_2( OP_BITOR, BIT_OPER( |, x1, x2 ); *y = result ) ARG_2( OP_BITXOR, BIT_OPER( ^, x1, x2 ); *y = result ) ARG_2( OP_BITAND, BIT_OPER( &, x1, x2 ); *y = result ) /* Binary boolean operators. */ /* ------------------------- */ ARG_2B( OP_AND, *y = TRISTATE_AND( x1, x2 ) ) ARG_2( OP_EQV, *y = ( ( x1 != 0.0 ) == ( x2 != 0.0 ) ) ) ARG_2B( OP_OR, *y = TRISTATE_OR( x1, x2 ) ) ARG_2( OP_XOR, *y = ( ( x1 != 0.0 ) != ( x2 != 0.0 ) ) ) } } } /* When all opcodes have been processed, the result of the function evaluation will reside in the lowest stack entry - i.e. the output array. */ /* Free the workspace arrays. */ work = astFree( work ); stack = astFree( stack ); /* Undefine macros local to this function. */ #undef ARG_0 #undef ARG_1 #undef ARG_1B #undef DO_ARG_2 #undef ARG_2 #undef ARG_2B #undef ABS #undef INT #undef CATCH_MATHS_OVERFLOW #undef CATCH_MATHS_ERROR #undef TRISTATE_OR #undef TRISTATE_AND #undef SAFE_ADD #undef SAFE_SUB #undef SAFE_MUL #undef SAFE_DIV #undef SHIFT_BITS #undef BIT_OPER #undef GAUSS } static void EvaluationSort( const double con[], int nsym, int symlist[], int **code, int *stacksize, int *status ) { /* * Name: * EvaluationSort * Purpose: * Perform an evaluation-order sort on parsed expression symbols. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void EvaluationSort( const double con[], int nsym, int symlist[], * int **code, int *stacksize, int *status ) * Class Membership: * MathMap member function. * Description: * This function sorts a sequence of numbers representing symbols * identified in an expression. The symbols (i.e. the expression syntax) * must have been fully validated beforehand, as no validation is * performed here. * * The symbols are sorted into the order in which corresponding * operations must be performed on a push-down arithmetic stack in order * to evaluate the expression. Operation codes (opcodes), as defined in * the "Oper" enum, are then substituted for the symbol numbers. * Parameters: * con * Pointer to an array of double containing the set of constants * generated while parsing the expression (these are required in order * to determine the number of arguments associated with functions which * take a variable number of arguments). * nsym * The number of symbols identified while parsing the expression. * symlist * Pointer to an array of int, with "nsym" elements. On entry, this * should contain the indices in the static "symbol" array of the * symbols identified while parsing the expression. On exit, the * contents are undefined. * code * Address of a pointer which will be set to point at a dynamically * allocated array of int containing the set of opcodes (cast to int) * produced by this function. The first element of this array will * contain a count of the number of opcodes which follow. * * The allocated space must be freed by the caller (using astFree) when * no longer required. * stacksize * Pointer to an int in which to return the size of the push-down stack * required to evaluate the expression using the returned opcodes. * status * Pointer to the inherited status variable. * Notes: * - A value of NULL will be returned for the "*code" pointer and a value * of zero will be returned for the "*stacksize" value if this function is * invoked with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ int flush; /* Flush parenthesised symbol sequence? */ int icon; /* Input constant counter */ int isym; /* Input symbol counter */ int ncode; /* Number of opcodes generated */ int nstack; /* Evaluation stack size */ int push; /* Push a new symbol on to stack? */ int sym; /* Variable for symbol number */ int tos; /* Top of sort stack index */ /* Initialise */ *code = NULL; *stacksize = 0; /* Check the global error status. */ if ( !astOK ) return; /* Further initialisation. */ flush = 0; icon = 0; isym = 0; ncode = 0; nstack = 0; tos = -1; /* Loop to generate output opcodes until the sort stack is empty and there are no further symbols to process, or an error is detected. */ while ( astOK && ( ( tos > -1 ) || ( isym < nsym ) ) ) { /* Decide whether to push a symbol on to the sort stack (which "diverts" it so that higher-priority symbols can be output), or to pop the top symbol off the sort stack and send it to the output stream... */ /* We must push a symbol on to the sort stack if the stack is currently empty. */ if ( tos == -1 ) { push = 1; /* We must pop the top symbol off the sort stack if there are no more input symbols to process. */ } else if ( isym >= nsym ) { push = 0; /* If the sort stack is being flushed to complete the evaluation of a parenthesised expression, then the top symbol (which will be the opening parenthesis or function call) must be popped. This is only done once, so reset the "flush" flag before the next loop. */ } else if ( flush ) { push = 0; flush = 0; /* In all other circumstances, we must push a symbol on to the sort stack if its evaluation priority (seen from the left) is higher than that of the current top of stack symbol (seen from the right). This means it will eventually be sent to the output stream ahead of the current top of stack symbol. */ } else { push = ( symbol[ symlist[ isym ] ].leftpriority > symbol[ symlist[ tos ] ].rightpriority ); } /* If a symbol is being pushed on to the sort stack, then get the next input symbol which is to be used. */ if ( push ) { sym = symlist[ isym++ ]; /* If the symbol decreases the parenthesis level (a closing parenthesis), then all the sort stack entries down to the symbol which opened the current level of parenthesis (the matching opening parenthesis or function call) will already have been sent to the output stream as a consequence of the evaluation priority defined for a closing parenthesis in the symbol data. The opening parenthesis (or function call) must next be flushed from the sort stack, so set the "flush" flag which is interpreted on the next loop. Ignore the current symbol, which cancels with the opening parenthesis on the stack. */ if ( symbol[ sym ].parincrement < 0 ) { flush = 1; /* All other symbols are pushed on to the sort stack. The stack occupies that region of the "symlist" array from which the input symbol numbers have already been extracted. */ } else { symlist[ ++tos ] = sym; } /* If a symbol is being popped from the top of the sort stack, then the top of stack entry is transferred to the output stream. Obtain the symbol number from the stack. Increment the local constant counter if the associated operation will use a constant. */ } else { sym = symlist[ tos-- ]; icon += ( ( sym == symbol_ldvar ) || ( sym == symbol_ldcon ) ); /* If the output symbol does not represent a "null" operation, increase the size of the output opcode array to accommodate it, checking for errors. Note that we allocate one extra array element (the first) which will eventually hold a count of all the opcodes generated. */ if ( symbol[ sym ].opcode != OP_NULL ) { *code = astGrow( *code, ncode + 2, sizeof( int ) ); if ( astOK ) { /* Append the new opcode to the end of this array. */ ( *code )[ ++ncode ] = (int) symbol[ sym ].opcode; /* Increment/decrement the counter representing the stack size required for evaluation of the expression. If the symbol is a function with a variable number of arguments (indicated by a negative "nargs" entry in the symbol data table), then the change in stack size must be determined from the argument number stored in the constant table. */ if ( symbol[ sym ].nargs >= 0 ) { nstack += symbol[ sym ].stackincrement; } else { nstack -= (int) ( con[ icon++ ] + 0.5 ) - 1; } /* Note the maximum size of the stack. */ *stacksize = ( nstack > *stacksize ) ? nstack : *stacksize; } } } } /* If no "*code" array has been allocated, then allocate one simply to store the number of opcodes generated, i.e. zero (this shouldn't normally happen as this represents an invalid expression). */ if ( !*code ) *code = astMalloc( sizeof( int ) ); /* If no error has occurred, store the count of opcodes generated in the first element of the "*code" array and re-allocate the array to its final size (since astGrow may have over-allocated space). */ if ( astOK ) { ( *code )[ 0 ] = ncode; *code = astRealloc( *code, sizeof( int ) * (size_t) ( ncode + 1 ) ); } /* If an error occurred, free any memory that was allocated and reset the output values. */ if ( !astOK ) { *code = astFree( *code ); *stacksize = 0; } } static void ExtractExpressions( const char *method, const char *class, int nfun, const char *fun[], int forward, char ***exprs, int *status ) { /* * Name: * ExtractExpressions * Purpose: * Extract and validate expressions. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ExtractExpressions( const char *method, const char *class, * int nfun, const char *fun[], int forward, * char ***exprs, int *status ) * Class Membership: * MathMap member function. * Description: * This function extracts expressions from the right hand sides of a set * of functions. These expressions are then validated to check that they * are either all present, or all absent (absence indicating an undefined * transformation). An error is reported if anything is found to be * wrong. * * Note that the syntax of the expressions is not checked by this function * (i.e. they are not compiled). * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * nfun * The number of functions to be analysed. * fun * Pointer to an array, with "nfun" elements, of pointers to null * terminated strings which contain each of the functions. These * strings should contain no white space. * forward * A non-zero value indicates the the MathMap's forward transformation * functions are being processed, while a zero value indicates processing * of the inverse transformation functions. This value is used solely for * constructing error messages. * exprs * Address in which to return a pointer to an array (with "nfun" * elements) of pointers to null terminated strings containing the * extracted expressions (i.e. this returns an array of strings). * * Both the returned array of pointers, and the strings to which they * point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. * * If the right hand sides (including the "=" sign) of all the supplied * functions are absent, then this indicates an undefined transformation * and the returned pointer value will be NULL. An error results if * an "=" sign is present but no expression follows it. * status * Pointer to the inherited status variable. * Notes: * - A NULL value will be returned for "*exprs" if this function is * invoked with the global error status set, or if it should fail for * any reason. */ /* Local Variables: */ char *ex; /* Pointer to start of expression string */ int ifun; /* Loop counter for functions */ int iud; /* Index of first undefined function */ int nud; /* Number of undefined expressions */ /* Initialise. */ *exprs = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Further initialisation. */ nud = 0; iud = 0; /* Allocate and initialise memory for the returned array of pointers. */ MALLOC_POINTER_ARRAY( *exprs, char *, nfun ) /* Loop to inspect each function in turn. */ if ( astOK ) { for ( ifun = 0; ifun < nfun; ifun++ ) { /* Search for the first "=" sign. */ if ( ( ex = strchr( fun[ ifun ], '=' ) ) ) { /* If found, and there are more characters after the "=" sign, then find the length of the expression which follows. Allocate a string to hold this expression, storing its pointer in the array allocated above. Check for errors. */ if ( *++ex ) { ( *exprs )[ ifun ] = astMalloc( strlen( ex ) + (size_t) 1 ); if ( !astOK ) break; /* If OK, extract the expression string. */ (void) strcpy( ( *exprs )[ ifun ], ex ); /* If an "=" sign was found but there are no characters following it, then there is a missing right hand side to a function, so report an error and quit. */ } else { astError( AST__NORHS, "%s(%s): Missing right hand side in expression: " "\"%s\".", status, method, class, fun[ ifun ] ); astError( astStatus, "Error in %s transformation function %d.", status, forward ? "forward" : "inverse", ifun + 1 ); break; } /* If no "=" sign was found, then the transformation may be undefined, in which case each function should only contain a variable name. Count the number of times this happens and record the index of the first instance. */ } else { nud++; if ( nud == 1 ) iud = ifun; } } } /* Either all functions should have an "=" sign (in which case the transformation is defined), or none of them should have (in which case it is undefined). If some do and some don't, then report an error, citing the first instance of a missing "=" sign. */ if ( astOK && ( nud != 0 ) && ( nud != nfun ) ) { astError( AST__NORHS, "%s(%s): Missing right hand side in function: \"%s\".", status, method, class, fun[ iud ] ); astError( astStatus, "Error in %s transformation function %d.", status, forward ? "forward" : "inverse", iud + 1 ); } /* If an error occurred, or all the expressions were absent, then free any allocated memory and reset the output value. */ if ( !astOK || nud ) { FREE_POINTER_ARRAY( *exprs, nfun ) } } static void ExtractVariables( const char *method, const char *class, int nfun, const char *fun[], int nin, int nout, int nfwd, int ninv, int forward, char ***var, int *status ) { /* * Name: * ExtractVariables * Purpose: * Extract and validate variable names. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ExtractVariables( const char *method, const char *class, * int nfun, const char *fun[], * int nin, int nout, int nfwd, int ninv, * int forward, char ***var, int *status ) * Class Membership: * MathMap member function. * Description: * This function extracts variable names from the left hand sides of a * set of transformation functions belonging to a MathMap. These variable * names are then validated to check for correct syntax and no * duplication. An error is reported if anything is wrong with the * variable names obtained. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * nfun * The number of functions to be analysed. * fun * Pointer to an array, with "nfun" elements, of pointers to null * terminated strings which contain each of the functions. These strings * are case sensitive and should contain no white space. * * The first elements of this array should point to the functions that * define the primary input/output variables (depending on direction). * These should be followed by any functions which define intermediate * variables (taken from the set of functions which transform in the * opposite direction to the first ones). * nin * Number of input variables for the MathMap. * nout * Number of output variables for the MathMap. * nfwd * Number of forward transformation functions for the MathMap. * ninv * Number of inverse transformation functions for the MathMap. * forward * A non-zero value indicates the the MathMap's forward transformation * functions are being processed, while a zero value indicates processing * of the inverse transformation functions. This value, together with * "nin", "nout", "nfwd" and "ninv" are used solely for constructing * error messages. * var * Address in which to return a pointer to an array (with "nfun" * elements) of pointers to null terminated strings containing the * extracted variable names (i.e. this returns an array of strings). * * Both the returned array of pointers, and the strings to which they * point, will be stored in dynamically allocated memory and should * be freed by the caller (using astFree) when no longer required. * status * Pointer to the inherited status variable. * Notes: * - A NULL value will be returned for "*var" if this function is * invoked with the global error status set, or if it should fail for * any reason. */ /* Local Variables: */ char *duser1; /* Transformation direction for function */ char *duser2; /* Transformation direction for function */ char c; /* Extracted character */ int i1; /* Loop counter for detecting duplicates */ int i2; /* Loop counter for detecting duplicates */ int i; /* Loop counter for characters */ int iend; /* Last character index in parsed name */ int ifun; /* Loop counter for functions */ int iuser1; /* Function number as known to the user */ int iuser2; /* Function number as known to the user */ int nc; /* Character count */ int nextra; /* Number of intermediate functions */ int nprimary; /* Number of primary input/output variables */ /* Initialise. */ *var = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Obtain the number of primary input/output variables, depending on the direction of the coordinate transformation. */ nprimary = ( forward ? nin : nout ); /* Deterine the number of extra (intermediate) functions that come before these primary ones. These affect the numbering of transformation functions as known to the user, and must be accounted for when reporting error messages. */ nextra = ( forward ? ninv - nin : nfwd - nout ); /* Allocate and initialise memory for the returned array of pointers. */ MALLOC_POINTER_ARRAY( *var, char *, nfun ) /* Loop to process each function in turn. */ if ( astOK ) { for ( ifun = 0; ifun < nfun; ifun++ ) { /* Count the number of characters appearing before the "=" sign (or in the entire string if the "=" is absent). */ for ( nc = 0; ( c = fun[ ifun ][ nc ] ); nc++ ) if ( c == '=' ) break; /* If no characters were counted, then report an appropriate error message, depending on whether the function string was entirely blank. */ if ( !nc ) { if ( c ) { astError( AST__MISVN, "%s(%s): No left hand side in expression: \"%s\".", status, method, class, fun[ ifun ] ); } else { astError( AST__MISVN, "%s: Transformation function contains no variable " "name.", status, method ); } break; } /* If OK, allocate memory to hold the output string and check for errors. */ ( *var )[ ifun ] = astMalloc( sizeof( char ) * (size_t) ( nc + 1 ) ) ; if ( !astOK ) break; /* If OK, copy the characters before the "=" sign to the new string. */ nc = 0; for ( i = 0; ( c = fun[ ifun ][ i ] ); i++ ) { if ( c == '=' ) break; ( *var )[ ifun ][ nc++] = c; } /* Null terminate the result. */ ( *var )[ ifun ][ nc ] = '\0'; /* Try to parse the contents of the extracted string as a name. */ ParseName( ( *var )[ ifun ], 0, &iend, status ); /* If unsuccessful, or if all the characters were not parsed, then we have an invalid variable name, so report an error and quit. */ if ( ( iend < 0 ) || ( *var )[ ifun ][ iend + 1 ] ) { astError( AST__VARIN, "%s(%s): Variable name is invalid: \"%s\".", status, method, class, ( *var )[ ifun ] ); break; } } /* If an error occurred above, then determine the function number, and the direction of the transformation of which it forms part, as known to the user. */ if ( !astOK ) { if ( ifun < nprimary ) { iuser1 = ifun + 1 + nextra; duser1 = ( forward ? "inverse" : "forward" ); } else { iuser1 = ifun + 1 - nprimary; duser1 = ( forward ? "forward" : "inverse" ); } /* Report a contextual error message. */ astError( astStatus, "Error in %s transformation function %d.", status, duser1, iuser1 ); } } /* If there has been no error, loop to compare all the variable names with each other to detect duplication. */ if ( astOK ) { for ( i1 = 1; i1 < nfun; i1++ ) { for ( i2 = 0; i2 < i1; i2++ ) { /* If a duplicate variable name is found, report an error. */ if ( !strcmp( ( *var )[ i1 ], ( *var )[ i2 ] ) ) { astError( AST__DUVAR, "%s(%s): Duplicate definition of variable name: " "\"%s\".", status, method, class, ( *var )[ i1 ] ); /* For each transformation function involved, determine the function number and the direction of the transformation of which it forms part, as known to the user. */ if ( i1 < nprimary ) { iuser1 = i1 + 1 + nextra; duser1 = ( forward ? "inverse" : "forward" ); } else { iuser1 = i1 + 1 - nprimary; duser1 = ( forward ? "forward" : "inverse" ); } if ( i2 < nprimary ) { iuser2 = i2 + 1 + nextra; duser2 = ( forward ? "inverse" : "forward" ); } else { iuser2 = i2 + 1 - nprimary; duser2 = ( forward ? "forward" : "inverse" ); } /* Report a contextual error message. */ astError( astStatus, "Conflict between %s function %d and %s function %d.", status, duser1, iuser1, duser2, iuser2 ); break; } } if ( !astOK ) break; } } /* If an error occurred, free any allocated memory and reset the output value. */ if ( !astOK ) { FREE_POINTER_ARRAY( *var, nfun ) } } static double Gauss( Rcontext *context, int *status ) { /* * Name: * Gauss * Purpose: * Produce a pseudo-random sample from a standard Gaussian distribution. * Type: * Private function. * Synopsis: * #include "mathmap.h" * double Gauss( Rcontext *context, int *status ) * Class Membership: * MathMap member function. * Description: * On each invocation, this function returns a pseudo-random sample drawn * from a standard Gaussian distribution with mean zero and standard * deviation unity. The Box-Muller transformation method is used. * Parameters: * context * Pointer to an Rcontext structure which holds the random number * generator's context between invocations. * status * Pointer to the inherited status variable. * Returned Value: * A sample from a standard Gaussian distribution. * Notes: * - The sequence of numbers returned is determined by the "seed" * value in the Rcontext structure supplied. * - If the seed value is changed, the "active" flag must also be cleared * so that this function can re-initiallise the Rcontext structure before * generating the next pseudo-random number. The "active" flag should * also be clear to force initialisation the first time an Rcontext * structure is used. * - This function does not perform error checking and does not generate * errors. It will execute even if the global error status is set. */ /* Local Variables: */ double rsq; /* Squared radius */ double s; /* Scale factor */ double x; /* First result value */ static double y; /* Second result value */ static int ysaved = 0; /* Previously-saved value available? */ LOCK_MUTEX7 /* If the random number generator context is not active, then it will be (re)initialised on the first invocation of Rand (below). Ensure that any previously-saved value within this function is first discarded. */ if ( !context->active ) ysaved = 0; /* If there is a previously-saved value available, then use it and mark it as no longer available. */ if ( ysaved ) { x = y; ysaved = 0; /* Otherwise, loop until a suitable new pair of values has been obtained. */ } else { while ( 1 ) { /* Loop to obtain two random values uniformly distributed inside the unit circle, while avoiding the origin (which maps to an infinite result). */ do { x = 2.0 * Rand( context, status ) - 1.0; y = 2.0 * Rand( context, status ) - 1.0; rsq = x * x + y * y; } while ( ( rsq >= 1.0 ) || ( rsq == 0.0 ) ); /* Perform the Box-Muller transformation, checking that this will not produce overflow (which is extremely unlikely). If overflow would occur, we simply repeat the above steps with a new pair of random numbers. */ s = -2.0 * log( rsq ); if ( ( DBL_MAX * rsq ) >= s ) { s = sqrt( s / rsq ); /* Scale the original random values to give a pair of results. One will be returned and the second kept until next time. */ x *= s; y *= s; break; } } /* Note that a saved value is available. */ ysaved = 1; } UNLOCK_MUTEX7 /* Return the current result. */ return x; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "mathmap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * MathMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied MathMap, * in bytes. * Parameters: * this * Pointer to the MathMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstMathMap *this; /* Pointer to MathMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the MathMap structure. */ this = (AstMathMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); SIZEOF_POINTER_ARRAY( this->fwdfun, this->nfwd ) SIZEOF_POINTER_ARRAY( this->invfun, this->ninv ) SIZEOF_POINTER_ARRAY( this->fwdcode, this->nfwd ) SIZEOF_POINTER_ARRAY( this->invcode, this->ninv ) SIZEOF_POINTER_ARRAY( this->fwdcon, this->nfwd ) SIZEOF_POINTER_ARRAY( this->invcon, this->ninv ) /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a MathMap. * Type: * Private function. * Synopsis: * #include "mathmap.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * MathMap member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a MathMap, formatted as a character string. * Parameters: * this * Pointer to the MathMap. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the MathMap, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the MathMap. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMathMap *this; /* Pointer to the MathMap structure */ const char *result; /* Pointer value to return */ int ival; /* Integer attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) this_object; /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null-terminated string in an appropriate format. Set "result" to point at the result string. */ /* Seed. */ /* ----- */ if ( !strcmp( attrib, "seed" ) ) { ival = astGetSeed( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* SimpFI. */ /* ------- */ } else if ( !strcmp( attrib, "simpfi" ) ) { ival = astGetSimpFI( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* SimpIF. */ /* ------- */ } else if ( !strcmp( attrib, "simpif" ) ) { ival = astGetSimpIF( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } void astInitMathMapVtab_( AstMathMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitMathMapVtab * Purpose: * Initialise a virtual function table for a MathMap. * Type: * Protected function. * Synopsis: * #include "mathmap.h" * void astInitMathMapVtab( AstMathMapVtab *vtab, const char *name ) * Class Membership: * MathMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the MathMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAMathMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearSeed = ClearSeed; vtab->ClearSimpFI = ClearSimpFI; vtab->ClearSimpIF = ClearSimpIF; vtab->GetSeed = GetSeed; vtab->GetSimpFI = GetSimpFI; vtab->GetSimpIF = GetSimpIF; vtab->SetSeed = SetSeed; vtab->SetSimpFI = SetSimpFI; vtab->SetSimpIF = SetSimpIF; vtab->TestSeed = TestSeed; vtab->TestSimpFI = TestSimpFI; vtab->TestSimpIF = TestSimpIF; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "MathMap", "Transformation using mathematical functions" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static double LogGamma( double x, int *status ) { /* * Name: * LogGamma * Purpose: * Calculate the logarithm of the gamma function. * Type: * Private function. * Synopsis: * #include "mathmap.h" * double LogGamma( double x, int *status ) * Class Membership: * MathMap member function. * Description: * This function returns the natural logarithm of the gamma function * for real arguments x>0. It uses the approximation of Lanczos, with * constants from Press et al. (Numerical Recipes), giving a maximum * fractional error (on the gamma function) of less than 2e-10. * Parameters: * x * The function argument, which must be greater than zero. * status * Pointer to the inherited status variable. * Returned Value: * The natural logarithm of the gamma function with "x" as argument, * or AST__BAD if "x" is not greater than zero. * Notes: * - This function does not generate errors and does not perform error * reporting. It will execute even if the global error status is set. */ /* Local Constants: */ const double c0 = 1.000000000190015; /* Coefficients for series sum... */ const double c1 = 76.18009172947146; const double c2 = -86.50532032941677; const double c3 = 24.01409824083091; const double c4 = -1.231739572450155; const double c5 = 0.1208650973866179e-2; const double c6 = -0.5395239384953e-5; const double g = 5.0; /* Local Variables: */ double result; /* Result value to return */ double sum; /* Series sum */ double xx; /* Denominator for summing series */ static double root_twopi; /* sqrt( 2.0 * pi ) */ static int init = 0; /* Initialisation performed? */ /* If initialisation has not yet been performed, calculate the constant required below. */ LOCK_MUTEX3 if ( !init ) { root_twopi = sqrt( 2.0 * acos( -1.0 ) ); /* Note that initialisation has been performed. */ init = 1; } UNLOCK_MUTEX3 /* Return a bad value if "x" is not greater than zero. */ if ( x <= 0.0 ) { result = AST__BAD; /* Otherwise, form the series sum. Since we only use 6 terms, the loop that would normally be used has been completely unrolled here. */ } else { xx = x; sum = c0; sum += c1 / ++xx; sum += c2 / ++xx; sum += c3 / ++xx; sum += c4 / ++xx; sum += c5 / ++xx; sum += c6 / ++xx; /* Calculate the result. */ result = x + g + 0.5; result -= ( x + 0.5 ) * log( result ); result = log( root_twopi * sum / x ) - result; } /* Return the result. */ return result; } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a MathMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * MathMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated MathMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated MathMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated MathMap which is to be merged with * its neighbours. This should be a cloned copy of the MathMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * MathMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated MathMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *new; /* Pointer to replacement Mapping */ AstMathMap *mathmap1; /* Pointer to first MathMap */ AstMathMap *mathmap2; /* Pointer to second MathMap */ char **fwd1; /* Pointer to first forward function array */ char **fwd2; /* Pointer to second forward function array */ char **inv1; /* Pointer to first inverse function array */ char **inv2; /* Pointer to second inverse function array */ int ifun; /* Loop counter for functions */ int imap1; /* Index of first Mapping */ int imap2; /* Index of second Mapping */ int imap; /* Loop counter for Mappings */ int invert1; /* Invert flag for first MathMap */ int invert2; /* Invert flag for second MathMap */ int nfwd1; /* No. forward functions for first MathMap */ int nfwd2; /* No. forward functions for second MathMap */ int nin1; /* Number input coords for first MathMap */ int ninv1; /* No. inverse functions for first MathMap */ int ninv2; /* No. inverse functions for second MathMap */ int nout2; /* Number output coords for second MathMap */ int result; /* Result value to return */ int simplify; /* Mappings may simplify? */ /* Initialise the returned result. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ mathmap1 = NULL; mathmap2 = NULL; imap1 = 0; imap2 = 0; invert1 = 0; invert2 = 0; nfwd1 = 0; nin1 = 0; ninv1 = 0; /* MathMaps are only worth simplifying if they occur in series. */ simplify = series; /* If simplification appears possible, then obtain the indices of the nominated mapping and of the one which follows it. Check that a mapping exists for the second index. */ if ( simplify ) { imap1 = where; imap2 = imap1 + 1; simplify = ( imap2 < *nmap ); } /* If OK, check whether the class of both Mappings is "MathMap" (a MathMap can only combine with another MathMap). */ if ( simplify ) { simplify = !strcmp( astGetClass( ( *map_list )[ imap1 ] ), "MathMap" ); } if ( astOK && simplify ) { simplify = !strcmp( astGetClass( ( *map_list )[ imap2 ] ), "MathMap" ); } /* If still OK, obtain pointers to the two MathMaps and the associated invert flag values. */ if ( astOK && simplify ) { mathmap1 = (AstMathMap *) ( *map_list )[ imap1 ]; mathmap2 = (AstMathMap *) ( *map_list )[ imap2 ]; invert1 = ( *invert_list )[ imap1 ]; invert2 = ( *invert_list )[ imap2 ]; /* Depending on the invert flag values, obtain the SimpFI or SimpIF attribute value from each MathMap and check whether they are set so as to permit simplification. */ simplify = ( ( invert1 ? astGetSimpIF( mathmap1 ) : astGetSimpFI( mathmap1 ) ) && ( invert2 ? astGetSimpFI( mathmap2 ) : astGetSimpIF( mathmap2 ) ) ); } /* If still OK, obtain the effective numbers of input coordinates for the first MathMap and output coordinates for the second. Take account of the associated invert flags and the way the Invert attribute of each MathMap is currently set. */ if ( astOK && simplify ) { nin1 = ( invert1 == astGetInvert( mathmap1 ) ) ? astGetNin( mathmap1 ) : astGetNout( mathmap1 ); nout2 = ( invert2 == astGetInvert( mathmap2 ) ) ? astGetNout( mathmap2 ) : astGetNin( mathmap2 ); /* Simplification is only possible if these two numbers are equal (otherwise the the two MathMaps cannot be identical). */ simplify = ( nin1 == nout2 ); } /* If still OK, obtain the effective number of forward transformation functions for the first MathMap (allowing for the associated invert flag). Similarly, obtain the effective number of inverse transformation functions for the second MathMap. */ if ( astOK && simplify ) { nfwd1 = !invert1 ? mathmap1->nfwd : mathmap1->ninv; ninv2 = !invert2 ? mathmap2->ninv : mathmap2->nfwd; /* Check whether these values are equal. The MathMaps cannot be identical if they are not. */ simplify = ( nfwd1 == ninv2 ); } /* As above, obtain pointers to the array of effective forward transformation functions for the first MathMap, and the effective inverse transformation functions for the second MathMap. */ if ( astOK && simplify ) { fwd1 = !invert1 ? mathmap1->fwdfun : mathmap1->invfun; inv2 = !invert2 ? mathmap2->invfun : mathmap2->fwdfun; /* Loop to check whether these two sets of functions are identical. The MathMaps cannot be merged unless they are. */ for ( ifun = 0; ifun < nfwd1; ifun++ ) { simplify = !strcmp( fwd1[ ifun ], inv2[ ifun ] ); if ( !simplify ) break; } } /* If OK, repeat the above process to compare the effective inverse transformation functions of the first MathMap with the forward functions of the second one. */ if ( astOK && simplify ) { ninv1 = !invert1 ? mathmap1->ninv : mathmap1->nfwd; nfwd2 = !invert2 ? mathmap2->nfwd : mathmap2->ninv; simplify = ( ninv1 == nfwd2 ); } if ( astOK && simplify ) { inv1 = !invert1 ? mathmap1->invfun : mathmap1->fwdfun; fwd2 = !invert2 ? mathmap2->fwdfun : mathmap2->invfun; for ( ifun = 0; ifun < ninv1; ifun++ ) { simplify = !strcmp( inv1[ ifun ], fwd2[ ifun ] ); if ( !simplify ) break; } } /* If the two MathMaps can be merged, create a UnitMap as a replacement. */ if ( astOK && simplify ) { new = (AstMapping *) astUnitMap( nin1, "", status ); /* If OK, annul the pointers to the original MathMaps. */ if ( astOK ) { ( *map_list )[ imap1 ] = astAnnul( ( *map_list )[ imap1 ] ); ( *map_list )[ imap2 ] = astAnnul( ( *map_list )[ imap2 ] ); /* Insert the pointer to the replacement UnitMap and store the associated invert flag. */ ( *map_list )[ imap1 ] = new; ( *invert_list )[ imap1 ] = 0; /* Loop to move the following Mapping pointers and invert flags down in their arrays to close the gap. */ for ( imap = imap2 + 1; imap < *nmap; imap++ ) { ( *map_list )[ imap - 1 ] = ( *map_list )[ imap ]; ( *invert_list )[ imap - 1 ] = ( *invert_list )[ imap ]; } /* Clear the final entry in each array. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = imap1; } } /* If an error occurred, clear the returned value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static void ParseConstant( const char *method, const char *class, const char *exprs, int istart, int *iend, double *con, int *status ) { /* * Name: * ParseConstant * Purpose: * Parse a constant. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ParseConstant( const char *method, const char *class, * const char *exprs, int istart, int *iend, * double *con, int *status ) * Class Membership: * MathMap member function. * Description: * This routine parses an expression, looking for a constant starting at * the character with index "istart" in the string "exprs". If it * identifies the constant successfully, "*con" it will return its value * and "*iend" will be set to the index of the final constant character * in "exprs". * * If the characters encountered are clearly not part of a constant (it * does not begin with a numeral or decimal point) the function returns * with "*con" set to zero and "*iend" set to -1, but without reporting * an error. However, if the first character appears to be a constant but * its syntax proves to be invalid, then an error is reported. * * The expression must be in lower case with no embedded white space. * The constant must not have a sign (+ or -) in front of it. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * exprs * Pointer to a null-terminated string containing the expression * to be parsed. * istart * Index of the first character in "exprs" to be considered by this * function. * iend * Pointer to an int in which to return the index in "exprs" of the * final character which forms part of the constant. If no constant is * found, a value of -1 is returned. * con * Pointer to a double, in which the value of the constant, if found, * will be returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char *str; /* Pointer to temporary string */ char c; /* Single character from the expression */ int dpoint; /* Decimal point encountered? */ int expon; /* Exponent character encountered? */ int i; /* Loop counter for characters */ int iscon; /* Character is part of the constant? */ int n; /* Number of values read by astSscanf */ int nc; /* Number of characters read by astSscanf */ int numer; /* Numeral encountered in current field? */ int sign; /* Sign encountered? */ int valid; /* Constant syntax valid? */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise. */ *con = 0.0; *iend = -1; /* Check if the expression starts with a numeral or a decimal point. */ c = exprs[ istart ]; numer = isdigit( c ); dpoint = ( c == '.' ); /* If it begins with any of these, the expression is clearly intended to be a constant, so any failure beyond this point will result in an error. Otherwise, failure to find a constant is not an error. */ if ( numer || dpoint ) { /* Initialise remaining variables specifying the parser context. */ expon = 0; sign = 0; valid = 1; /* Loop to increment the last constant character position until the following character in the expression does not look like part of the constant. */ *iend = istart; iscon = 1; while ( ( c = exprs[ *iend + 1 ] ) && iscon ) { iscon = 0; /* It may be part of a numerical constant if it is a numeral, wherever it occurs. */ if ( isdigit( c ) ) { numer = 1; iscon = 1; /* Or a decimal point, so long as it is the first one and is not in the exponent field. Otherwise it is invalid. */ } else if ( c == '.' ) { if ( !( dpoint || expon ) ) { dpoint = 1; iscon = 1; } else { valid = 0; } /* Or if it is a 'd' or 'e' exponent character, so long as it is the first one and at least one numeral has been encountered first. Otherwise it is invalid. */ } else if ( ( c == 'd' ) || ( c == 'e' ) ) { if ( !expon && numer ) { expon = 1; numer = 0; iscon = 1; } else { valid = 0; } /* Or if it is a sign, so long as it is in the exponent field and is the first sign with no previous numerals in the same field. Otherwise it is invalid (unless numerals have been encountered, in which case it marks the end of the constant). */ } else if ( ( c == '+' ) || ( c == '-' ) ) { if ( expon && !sign && !numer ) { sign = 1; iscon = 1; } else if ( !numer ) { valid = 0; } } /* Increment the character count if the next character may be part of the constant, or if it was invalid (it will then form part of the error message). */ if ( iscon || !valid ) ( *iend )++; } /* Finally, check that the last field contained a numeral. */ valid = ( valid && numer ); /* If the constant appears valid, allocate a temporary string to hold it. */ if ( valid ) { str = astMalloc( (size_t) ( *iend - istart + 2 ) ); if ( astOK ) { /* Copy the constant's characters, changing 'd' to 'e' so that "astSscanf" will recognise it as an exponent character. */ for ( i = istart; i <= *iend; i++ ) { str[ i - istart ] = ( exprs[ i ] == 'd' ) ? 'e' : exprs[ i ]; } str[ *iend - istart + 1 ] = '\0'; /* Attempt to read the constant as a double, noting how many values are read and how many characters consumed. */ n = astSscanf( str, "%lf%n", con, &nc ); /* Check that one value was read and all the characters consumed. If not, then the constant's syntax is invalid. */ if ( ( n != 1 ) || ( nc < ( *iend - istart + 1 ) ) ) valid = 0; } /* Free the temporary string. */ str = astFree( str ); } /* If the constant syntax is invalid, and no other error has occurred, then report an error. */ if ( astOK && !valid ) { astError( AST__CONIN, "%s(%s): Invalid constant syntax in the expression " "\"%.*s\".", status, method, class, *iend + 1, exprs ); } /* If an error occurred, reset the output values. */ if ( !astOK ) { *iend = -1; *con = 0.0; } } } static void ParseName( const char *exprs, int istart, int *iend, int *status ) { /* * Name: * ParseName * Purpose: * Parse a name. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ParseName( const char *exprs, int istart, int *iend, int *status ) * Class Membership: * MathMap member function. * Description: * This routine parses an expression, looking for a name starting at the * character with index "istart" in the string "exprs". If it identifies * a name successfully, "*iend" will return the index of the final name * character in "exprs". A name must begin with an alphabetic character * and subsequently contain only alphanumeric characters or underscores. * * If the expression does not contain a name at the specified location, * "*iend" is set to -1. No error results. * * The expression should not contain embedded white space. * Parameters: * exprs * Pointer to a null-terminated string containing the expression * to be parsed. * istart * Index of the first character in "exprs" to be considered by this * function. * iend * Pointer to an int in which to return the index in "exprs" of the * final character which forms part of the name. If no name is * found, a value of -1 is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char c; /* Single character from expression */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise. */ *iend = -1; /* Check the first character is valid for a name (alphabetic). */ if ( isalpha( exprs[ istart ] ) ) { /* If so, loop to inspect each subsequent character until one is found which is not part of a name (not alphanumeric or underscore). */ for ( *iend = istart; ( c = exprs[ *iend + 1 ] ); ( *iend )++ ) { if ( !( isalnum( c ) || ( c == '_' ) ) ) break; } } } static void ParseVariable( const char *method, const char *class, const char *exprs, int istart, int nvar, const char *var[], int *ivar, int *iend, int *status ) { /* * Name: * ParseVariable * Purpose: * Parse a variable name. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ParseVariable( const char *method, const char *class, * const char *exprs, int istart, int nvar, * const char *var[], int *ivar, int *iend, int *status ) * Class Membership: * MathMap member function. * Description: * This routine parses an expression, looking for a recognised variable * name starting at the character with index "istart" in the string * "exprs". If it identifies a variable name successfully, "*ivar" will * return a value identifying it and "*iend" will return the index of the * final variable name character in "exprs". To be recognised, a name * must begin with an alphabetic character and subsequently contain only * alphanumeric characters or underscores. It must also appear in the * list of defined variable names supplied to this function. * * If the expression does not contain a name at the specified location, * "*ivar" and "*iend" are set to -1 and no error results. However, if * the expression contains a name but it is not in the list of defined * variable names supplied, then an error is reported. * * This function is case sensitive. The expression should not contain * embedded white space. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * exprs * Pointer to a null-terminated string containing the expression * to be parsed. * istart * Index of the first character in "exprs" to be considered by this * function. * nvar * The number of defined variable names. * var * An array of pointers (with "nvar" elements) to null-terminated * strings. Each of these should contain a variable name to be * recognised. These strings are case sensitive and should contain * no white space. * ivar * Pointer to an int in which to return the index in "vars" of the * variable name found. If no variable name is found, a value of -1 * is returned. * iend * Pointer to an int in which to return the index in "exprs" of the * final character which forms part of the variable name. If no variable * name is found, a value of -1 is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int found; /* Variable name recognised? */ int nc; /* Number of characters in variable name */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise. */ *ivar = -1; *iend = -1; /* Determine if the characters in the expression starting at index "istart" constitute a valid name. */ ParseName( exprs, istart, iend, status ); /* If so, calculate the length of the name. */ if ( *iend >= istart ) { nc = *iend - istart + 1; /* Loop to compare the name with the list of variable names supplied. */ found = 0; for ( *ivar = 0; *ivar < nvar; ( *ivar )++ ) { found = ( nc == (int) strlen( var[ *ivar ] ) ) && !strncmp( exprs + istart, var[ *ivar ], (size_t) nc ); /* Break if the name is recognised. */ if ( found ) break; } /* If it was not recognised, then report an error and reset the output values. */ if ( !found ) { astError( AST__UDVOF, "%s(%s): Undefined variable or function in the expression " "\"%.*s\".", status, method, class, *iend + 1, exprs ); *ivar = -1; *iend = -1; } } } static double Poisson( Rcontext *context, double mean, int *status ) { /* * Name: * Poisson * Purpose: * Produce a pseudo-random sample from a Poisson distribution. * Type: * Private function. * Synopsis: * #include "mathmap.h" * double Poisson( Rcontext *context, double mean, int *status ) * Class Membership: * MathMap member function. * Description: * On each invocation, this function returns a pseudo-random sample drawn * from a Poisson distribution with a specified mean. A combination of * methods is used, depending on the value of the mean. The algorithm is * based on that given by Press et al. (Numerical Recipes), but * re-implemented and extended. * Parameters: * context * Pointer to an Rcontext structure which holds the random number * generator's context between invocations. * mean * The mean of the Poisson distribution, which should not be * negative. * status * Pointer to the inherited status variable. * Returned Value: * A sample (which will only take integer values) from the Poisson * distribution, or AST__BAD if the mean supplied is negative. * Notes: * - The sequence of numbers returned is determined by the "seed" * value in the Rcontext structure supplied. * - If the seed value is changed, the "active" flag must also be cleared * so that this function can re-initiallise the Rcontext structure before * generating the next pseudo-random number. The "active" flag should * also be clear to force initialisation the first time an Rcontext * structure is used. * - This function does not perform error checking and does not generate * errors. It will execute even if the global error status is set. */ /* Local Constants: */ const double small = 9.3; /* "Small" distribution mean value */ /* Local Variables: */ double pfract; /* Probability of accepting sample */ double product; /* Product of random samples */ double ran; /* Sample from Lorentzian distribution */ double result; /* Result value to return */ static double beta; /* Constant for forming acceptance ratio */ static double huge; /* Large mean where std. dev. is negligible */ static double last_mean; /* Value of "mean" on last invocation */ static double log_mean; /* Logarithm of "mean" */ static double pi; /* Value of pi */ static double ranmax; /* Maximum safe value of "ran" */ static double root_2mean; /* sqrt( 2.0 * mean ) */ static double sqrt_point9; /* Square root of 0.9 */ static double thresh; /* Threshold for product of samples */ static int init = 0; /* Local initialisation performed? */ LOCK_MUTEX6 /* If initialisation has not yet been performed, then perform it now. */ if ( !init ) { /* Initialise the mean value from the previous invocation. */ last_mean = -1.0; /* Calculate simple constants. */ pi = acos( -1.0 ); sqrt_point9 = sqrt( 0.9 ); /* Calculate the value of the distribution mean for which the smallest representable deviation from the mean permitted by the machine precision is one thousand standard deviations. */ huge = pow( 1.0e3 / DBL_EPSILON, 2.0 ); /* Calculate the largest value such that (0.9+(sqrt_point9*ranmax)*(sqrt_point9*ranmax)) doesn't overflow, allowing a small margin for rounding error. */ ranmax = ( sqrt( DBL_MAX - 0.9 ) / sqrt( 0.9 ) ) * ( 1.0 - 4.0 * DBL_EPSILON ); /* Note that initialisation has been performed. */ init = 1; } /* If the distribution mean is less than zero, then return a bad result. */ if ( mean < 0.0 ) { result = AST__BAD; /* If the mean is zero, then the result can only be zero. */ } else if ( mean == 0.0 ) { result = 0.0; /* Otherwise, if the mean is sufficiently small, we can use the direct method of summing a series of exponentially distributed random samples and counting the number which occur before the mean is exceeded. This is equivalent to multiplying a series of uniformly distributed samples and counting the number which occur before the product becomes less then an equivalent threshold. */ } else if ( mean <= small ) { /* If the mean has changed since the last invocation, store the new mean and calculate a new threshold. */ if ( mean != last_mean ) { last_mean = mean; thresh = exp( -mean ); } /* Initialise the product and the result. */ product = 1.0; result = -1.0; /* Multiply the random samples, counting the number needed to reach the threshold. */ do { product *= Rand( context, status ); result += 1.0; } while ( product > thresh ); /* Otherwise, if the distribution mean is large (but not huge), we must use an indirect rejection method. */ } else if ( mean <= huge ) { /* If the mean has changed since the last invocation, then re-calculate the constants required below. Note that because of the restrictions we have placed on "mean", these calculations are safe against overflow. */ if ( mean != last_mean ) { last_mean = mean; log_mean = log( mean ); root_2mean = sqrt( 2.0 * mean ); beta = mean * log_mean - LogGamma( mean + 1.0, status ); } /* Loop until a suitable random sample has been generated. */ do { do { /* First transform a sample from a uniform distribution to obtain a sample from a Lorentzian distribution. Check that the result is not so large as to cause overflow later. Also check for overflow in the maths library. If necessary, obtain a new sample. */ do { errno = 0; ran = tan( pi * Rand( context, status ) ); } while ( ( ran > ranmax ) || ( ( errno == ERANGE ) && ( ( ( ran >= 0.0 ) ? ran : -ran ) == HUGE_VAL ) ) ); /* If OK, scale the sample and add a constant so that the sample's distribution approximates the Poisson distribution we require. Overflow is prevented by the check on "ran" above, together with the restricted value of "mean". */ result = ran * root_2mean + mean; /* If the result is less than zero (where the Poisson distribution has value zero), then obtain a new sample. */ } while ( result < 0.0 ); /* Round down to an integer, so that the sample is valid for a Poisson distribution. */ result = floor( result ); /* Calculate the ratio between the required Poisson distribution and the Lorentzian from which we have sampled (the factor of 0.9 prevents this exceeding 1.0, and overflow is again prevented by the checks performed above). */ ran *= sqrt_point9; pfract = ( 0.9 + ran * ran ) * exp( result * log_mean - LogGamma( result + 1.0, status ) - beta ); /* Accept the sample with this fractional probability, otherwise obtain a new sample. */ } while ( Rand( context, status ) > pfract ); /* If the mean is huge, the relative standard deviation will be negligible compared to the machine precision. In such cases, the probability of getting a result that differs from the mean is effectively zero, so we can simply return the mean. */ } else { result = mean; } UNLOCK_MUTEX6 /* Return the result. */ return result; } static double Rand( Rcontext *context, int *status ) { /* * Name: * Rand * Purpose: * Produce a uniformly distributed pseudo-random number. * Type: * Private function. * Synopsis: * #include "mathmap.h" * double Rand( Rcontext *context, int *status ) * Class Membership: * MathMap member function. * Description: * On each invocation, this function returns a pseudo-random number * uniformly distributed in the range 0.0 to 1.0 (inclusive). The * underlying algorithm is that used by the "ran2" function of Press et * al. (Numerical Recipes), which has a long period and good statistical * properties. This independent implementation returns double precision * values. * Parameters: * context * Pointer to an Rcontext structure which holds the random number * generator's context between invocations. * status * Pointer to the inherited status variable. * Notes: * - The sequence of numbers returned is determined by the "seed" * value in the Rcontext structure supplied. * - If the seed value is changed, the "active" flag must also be cleared * so that this function can re-initiallise the Rcontext structure before * generating the next pseudo-random number. The "active" flag should * also be clear to force initialisation the first time an Rcontext * structure is used. * - This function does not perform error checking and does not generate * errors. It will execute even if the global error status is set. */ /* Local Constants: */ const long int a1 = 40014L; /* Random number generator constants... */ const long int a2 = 40692L; const long int m1 = 2147483563L; const long int m2 = 2147483399L; const long int q1 = 53668L; const long int q2 = 52774L; const long int r1 = 12211L; const long int r2 = 3791L; const int ntab = /* Size of shuffle table */ AST_MATHMAP_RAND_CONTEXT_NTAB_; const int nwarm = 8; /* Number of warm-up iterations */ /* Local Variables: */ double result; /* Result value to return */ double scale; /* Scale factor for random integers */ double sum; /* Sum for forming normalisation constant */ int dbits; /* Approximate bits in double mantissa */ int irand; /* Loop counter for random integers */ int itab; /* Loop counter for shuffle table */ int lbits; /* Approximate bits used by generators */ long int seed; /* Random number seed */ long int tmp; /* Temporary variable */ static double norm; /* Normalisation constant */ static double scale0; /* Scale decrement for successive integers */ static int init = 0; /* Local initialisation performed? */ static int nrand; /* Number of random integers to use */ /* If the random number generator context is not active, then initialise it. */ if ( !context->active ) { /* First, perform local initialisation for this function, if not already done. */ LOCK_MUTEX4 if ( !init ) { /* Obtain the approximate number of bits used by the random integer generator from the value "m1". */ (void) frexp( (double) m1, &lbits ); /* Obtain the approximate number of bits used by the mantissa of the double value we want to produce, allowing for the (unlikely) possibility that the mantissa's radix isn't 2. */ dbits = (int) ceil( (double) DBL_MANT_DIG * log( (double) FLT_RADIX ) / log( 2.0 ) ); /* Hence determine how many random integers we need to combine to produce each double value, so that all the mantissa's bits will be used. */ nrand = ( dbits + lbits - 1 ) / lbits; /* Calculate the scale factor by which each successive random integer's contribution to the result is reduced so as to generate progressively less significant bits. */ scale0 = 1.0 / (double) ( m1 - 1L ); /* Loop to sum the maximum contributions from each random integer (assuming that each takes the largest possible value, of "m1-1", from which we will later subtract 1). This produces the normalisation factor by which the result must be scaled so as to lie between 0.0 and 1.0 (inclusive). */ sum = 0.0; scale = 1.0; for ( irand = 0; irand < nrand; irand++ ) { scale *= scale0; sum += scale; } norm = 1.0 / ( sum * (double) ( m1 - 2L ) ); /* Note that local initialisation has been done. */ init = 1; } UNLOCK_MUTEX4 /* Obtain the seed value, enforcing positivity. */ seed = (long int) context->seed; if ( seed < 1 ) seed = seed + LONG_MAX; if ( seed < 1 ) seed = LONG_MAX; /* Initialise the random number generators with this seed. */ context->rand1 = context->rand2 = seed; /* Now loop to initialise the shuffle table with an initial set of random values. We generate more values than required in order to "warm up" the generator before recording values in the table. */ for ( itab = ntab + nwarm - 1; itab >= 0; itab-- ) { /* Repeatedly update "rand1" from the expression "(rand1*a1)%m1" while avoiding overflow. */ tmp = context->rand1 / q1; context->rand1 = a1 * ( context->rand1 - tmp * q1 ) - tmp * r1; if ( context->rand1 < 0L ) context->rand1 += m1; /* After warming up, start recording values in the table. */ if ( itab < ntab ) context->table[ itab ] = context->rand1; } /* Record the last entry in the table as the "previous" random integer. */ context->random_int = context->table[ 0 ]; /* Note the random number generator context is active. */ context->active = 1; } /* Generate a random value. */ /* ------------------------ */ /* Initialise. */ result = 0.0; /* Loop to generate sufficient random integers to combine into a double value. */ scale = norm; for ( irand = 0; irand < nrand; irand++ ) { /* Update the first generator "rand1" from the expression "(a1*rand1)%m1" while avoiding overflow. */ tmp = context->rand1 / q1; context->rand1 = a1 * ( context->rand1 - tmp * q1 ) - tmp * r1; if ( context->rand1 < 0L ) context->rand1 += m1; /* Similarly, update the second generator "rand2" from the expression "(a2*rand2)%m2". */ tmp = context->rand2 / q2; context->rand2 = a2 * ( context->rand2 - tmp * q2 ) - tmp * r2; if ( context->rand2 < 0L ) context->rand2 += m2; /* Use the previous random integer to generate an index into the shuffle table. */ itab = (int) ( context->random_int / ( 1L + ( m1 - 1L ) / (long int) ntab ) ); /* The algorithm left by RFWS seems to have a bug that "itab" can sometimes be outside the range of [0.,ntab-1] causing the context->table array to be addressed out of bounds. To avoid this, use the following sticking plaster, since I'm not sure what the correct fix is. */ if( itab < 0 ) itab = -itab; itab = itab % ntab; /* Extract the table entry and replace it with a new random value from the first generator "rand1". This is the Bays-Durham shuffle. */ context->random_int = context->table[ itab ]; context->table[ itab ] = context->rand1; /* Combine the extracted value with the latest value from the second generator "rand2". */ context->random_int -= context->rand2; if ( context->random_int < 1L ) context->random_int += m1 - 1L; /* Update the scale factor to apply to the resulting random integer and accumulate its contribution to the result. */ scale *= scale0; result += scale * (double) ( context->random_int - 1L ); } /* Return the result. */ return result; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a MathMap. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * MathMap member function (extends the astSetAttrib method inherited from * the Mapping class). * Description: * This function assigns an attribute value for a MathMap, the attribute * and its value being specified by means of a string of the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in lower * case with no white space present. The value to the right of the "=" * should be a suitable textual representation of the value to be assigned * and this will be interpreted according to the attribute's data type. * White space surrounding the value is only significant for string * attributes. * Parameters: * this * Pointer to the MathMap. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. * Returned Value: * void */ /* Local Vaiables: */ AstMathMap *this; /* Pointer to the MathMap structure */ int ival; /* Integer attribute value */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) this_object; /* Obtain the length of the setting string. */ len = strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* Seed. */ /* ----- */ if ( nc = 0, ( 1 == astSscanf( setting, "seed= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetSeed( this, ival ); /* SimpFI. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "simpfi= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetSimpFI( this, ival ); /* SimpIF. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "simpif= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetSimpIF( this, ival ); /* Pass any unrecognised setting to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a MathMap. * Type: * Private function. * Synopsis: * #include "mathmap.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * MathMap member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a MathMap's attributes. * Parameters: * this * Pointer to the MathMap. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstMathMap *this; /* Pointer to the MathMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) this_object; /* Check the attribute name and test the appropriate attribute. */ /* Seed. */ /* ----- */ if ( !strcmp( attrib, "seed" ) ) { result = astTestSeed( this ); /* SimpFI. */ /* ------- */ } else if ( !strcmp( attrib, "simpfi" ) ) { result = astTestSimpFI( this ); /* SimpIF. */ /* ------- */ } else if ( !strcmp( attrib, "simpif" ) ) { result = astTestSimpIF( this ); /* If the attribute is not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *map, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a MathMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "mathmap.h" * AstPointSet *Transform( AstMapping *map, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * MathMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a MathMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required coordinate * transformation. * Parameters: * map * Pointer to the MathMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the MathMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstMathMap *this; /* Pointer to MathMap to be applied */ AstPointSet *result; /* Pointer to output PointSet */ double **data_ptr; /* Array of pointers to coordinate data */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *work; /* Workspace for intermediate results */ int idata; /* Loop counter for data pointer elements */ int ifun; /* Loop counter for functions */ int ncoord_in; /* Number of coordinates per input point */ int ncoord_out; /* Number of coordinates per output point */ int ndata; /* Number of data pointer elements filled */ int nfun; /* Number of functions to evaluate */ int npoint; /* Number of points */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ work = NULL; /* Obtain a pointer to the MathMap. */ this = (AstMathMap *) map; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( map, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the transformation needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input and output PointSets and obtain pointers for accessing the input and output coordinate values. */ ncoord_in = astGetNcoord( in ); ncoord_out = astGetNcoord( result ); npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse transformation, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( this ) ) forward = !forward; /* Obtain the number of transformation functions that must be evaluated to perform the transformation. This will include any that produce intermediate results from which the final results are calculated. */ nfun = forward ? this->nfwd : this->ninv; /* If intermediate results are to be calculated, then allocate workspace to hold them (each intermediate result being a vector of "npoint" double values). */ if ( nfun > ncoord_out ) { work = astMalloc( sizeof( double) * (size_t) ( npoint * ( nfun - ncoord_out ) ) ); } /* Also allocate space for an array to hold pointers to the input data, intermediate results and output data. */ data_ptr = astMalloc( sizeof( double * ) * (size_t) ( ncoord_in + nfun ) ); /* We now set up the "data_ptr" array to locate the data to be processed. */ if ( astOK ) { /* The first elements of this array point at the input data vectors. */ ndata = 0; for ( idata = 0; idata < ncoord_in; idata++ ) { data_ptr[ ndata++ ] = ptr_in[ idata ]; } /* The following elements point at successive vectors within the workspace array (if allocated). These vectors will act first as output arrays for intermediate results, and then as input arrays for subsequent calculations which use these results. */ for ( idata = 0; idata < ( nfun - ncoord_out ); idata++ ) { data_ptr[ ndata++ ] = work + ( idata * npoint ); } /* The final elements point at the output coordinate data arrays into which the final results will be written. */ for ( idata = 0; idata < ncoord_out; idata++ ) { data_ptr[ ndata++ ] = ptr_out[ idata ]; } /* Perform coordinate transformation. */ /* ---------------------------------- */ /* Loop to evaluate each transformation function in turn. */ for ( ifun = 0; ifun < nfun; ifun++ ) { /* Invoke the function that evaluates compiled expressions. Pass the appropriate code and constants arrays, depending on the direction of coordinate transformation, together with the required stack size. The output array is the vector located by successive elements of the "data_ptr" array (skipping the input data elements), while the function has access to all previous elements of the "data_ptr" array to locate the required input data. */ EvaluateFunction( &this->rcontext, npoint, (const double **) data_ptr, forward ? this->fwdcode[ ifun ] : this->invcode[ ifun ], forward ? this->fwdcon[ ifun ] : this->invcon[ ifun ], forward ? this->fwdstack : this->invstack, data_ptr[ ifun + ncoord_in ], status ); } } /* Free the array of data pointers and any workspace allocated for intermediate results. */ data_ptr = astFree( data_ptr ); if ( nfun > ncoord_out ) work = astFree( work ); /* If an error occurred, then return a NULL pointer. If no output PointSet was supplied, also delete any new one that may have been created. */ if ( !astOK ) { result = ( result == out ) ? NULL : astDelete( result ); } /* Return a pointer to the output PointSet. */ return result; } static void ValidateSymbol( const char *method, const char *class, const char *exprs, int iend, int sym, int *lpar, int **argcount, int **opensym, int *ncon, double **con, int *status ) { /* * Name: * ValidateSymbol * Purpose: * Validate a symbol in an expression. * Type: * Private function. * Synopsis: * #include "mathmap.h" * void ValidateSymbol( const char *method, const char *class, * const char *exprs, int iend, int sym, int *lpar, * int **argcount, int **opensym, int *ncon, * double **con, int *status ) * Class Membership: * MathMap member function. * Description: * This function validates an identified standard symbol during * compilation of an expression. Its main task is to keep track of the * level of parenthesis in the expression and to count the number of * arguments supplied to functions at each level of parenthesis (for * nested function calls). On this basis it is able to interpret and * accept or reject symbols which represent function calls, parentheses * and delimiters. Other symbols are accepted automatically. * Parameters: * method * Pointer to a constant null-terminated character string * containing the name of the method that invoked this function. * This method name is used solely for constructing error messages. * class * Pointer to a constant null-terminated character string containing the * class name of the Object being processed. This name is used solely * for constructing error messages. * exprs * Pointer to a null-terminated string containing the expression * being parsed. This is only used for constructing error messages. * iend * Index in "exprs" of the last character belonging to the most * recently identified symbol. This is only used for constructing error * messages. * sym * Index in the static "symbol" array of the most recently identified * symbol in the expression. This is the symbol to be verified. * lpar * Pointer to an int which holds the current level of parenthesis. On * the first invocation, this should be zero. The returned value should * be passed to subsequent invocations. * argcount * Address of a pointer to a dynamically allocated array of int in * which argument count information is maintained for each level of * parenthesis (e.g. for nested function calls). On the first invocation, * "*argcount" should be NULL. This function will allocate the required * space as needed and update this pointer. The returned pointer value * should be passed to subsequent invocations. * * The allocated space must be freed by the caller (using astFree) when * no longer required. * opensym * Address of a pointer to a dynamically allocated array of int, in which * information is maintained about the functions associated with each * level of parenthesis (e.g. for nested function calls). On the first * invocation, "*opensym" should be NULL. This function will allocate the * required space as needed and update this pointer. The returned pointer * value should be passed to subsequent invocations. * * The allocated space must be freed by the caller (using astFree) when * no longer required. * ncon * Pointer to an int which holds a count of the constants associated * with the expression (and determines the size of the "*con" array). * This function will update the count to reflect any new constants * appended to the "*con" array and the returned value should be passed * to subsequent invocations. * con * Address of a pointer to a dynamically allocated array of double, in * which the constants associated with the expression being parsed are * accumulated. On entry, "*con" should point at a dynamic array with * at least "*ncon" elements containing existing constants (or may be * NULL if no constants have yet been stored). This function will * allocate the required space as needed and update this pointer (and * "*ncon") appropriately. The returned pointer value should be passed * to subsequent invocations. * * The allocated space must be freed by the caller (using astFree) when * no longer required. * status * Pointer to the inherited status variable. * Notes: * - The dynamically allocated arrays normally returned by this function * will be freed and NULL pointers will be returned if this function is * invoked with the global error status set, or if it should fail for any * reason. */ /* Check the global error status, but do not return at this point because dynamic arrays may require freeing. */ if ( astOK ) { /* Check if the symbol is a comma. */ if ( ( symbol[ sym ].text[ 0 ] == ',' ) && ( symbol[ sym ].text[ 1 ] == '\0' ) ) { /* A comma is only used to delimit function arguments. If the current level of parenthesis is zero, or the symbol which opened the current level of parenthesis was not a function call (indicated by an argument count of zero at the current level of parenthesis), then report an error. */ if ( ( *lpar <= 0 ) || ( ( *argcount )[ *lpar - 1 ] == 0 ) ) { astError( AST__COMIN, "%s(%s): Spurious comma encountered in the expression " "\"%.*s\".", status, method, class, iend + 1, exprs ); /* If a comma is valid, then increment the argument count at the current level of parenthesis. */ } else { ( *argcount )[ *lpar - 1 ]++; } /* If the symbol is not a comma, check if it increases the current level of parenthesis. */ } else if ( symbol[ sym ].parincrement > 0 ) { /* Increase the size of the arrays which hold parenthesis level information and check for errors. */ *argcount = astGrow( *argcount, *lpar + 1, sizeof( int ) ); *opensym = astGrow( *opensym, *lpar + 1, sizeof( int ) ); if ( astOK ) { /* Increment the level of parenthesis and initialise the argument count at the new level. This count is set to zero if the symbol which opens the parenthesis level is not a function call (indicated by a zero "nargs" entry in the symbol data), and it subsequently remains at zero. If the symbol is a function call, the argument count is initially set to 1 and increments whenever a comma is encountered at this parenthesis level. */ ( *argcount )[ ++( *lpar ) - 1 ] = ( symbol[ sym ].nargs != 0 ); /* Remember the symbol which opened this parenthesis level. */ ( *opensym )[ *lpar - 1 ] = sym; } /* Check if the symbol decreases the current parenthesis level. */ } else if ( symbol[ sym ].parincrement < 0 ) { /* Ensure that the parenthesis level is not already at zero. If it is, then there is a missing left parenthesis in the expression being compiled, so report an error. */ if ( *lpar == 0 ) { astError( AST__MLPAR, "%s(%s): Missing left parenthesis in the expression " "\"%.*s\".", status, method, class, iend + 1, exprs ); /* If the parenthesis level is valid and the symbol which opened this level of parenthesis was a function call with a fixed number of arguments (indicated by a positive "nargs" entry in the symbol data), then we must check the number of function arguments which have been encountered. */ } else if ( symbol[ ( *opensym )[ *lpar - 1 ] ].nargs > 0 ) { /* Report an error if the number of arguments is wrong. */ if ( ( *argcount )[ *lpar - 1 ] != symbol[ ( *opensym )[ *lpar - 1 ] ].nargs ) { astError( AST__WRNFA, "%s(%s): Wrong number of function arguments in the " "expression \"%.*s\".", status, method, class, iend + 1, exprs ); /* If the number of arguments is valid, decrement the parenthesis level. */ } else { ( *lpar )--; } /* If the symbol which opened this level of parenthesis was a function call with a variable number of arguments (indicated by a negative "nargs" entry in the symbol data), then we must check and process the number of function arguments. */ } else if ( symbol[ ( *opensym )[ *lpar - 1 ] ].nargs < 0 ) { /* Check that the minimum required number of arguments have been supplied. Report an error if they have not. */ if ( ( *argcount )[ *lpar - 1 ] < ( -symbol[ ( *opensym )[ *lpar - 1 ] ].nargs ) ) { astError( AST__WRNFA, "%s(%s): Insufficient function arguments in the " "expression \"%.*s\".", status, method, class, iend + 1, exprs ); /* If the number of arguments is valid, increase the size of the constants array and check for errors. */ } else { *con = astGrow( *con, *ncon + 1, sizeof( double ) ); if ( astOK ) { /* Append the argument count to the end of the array of constants and decrement the parenthesis level. */ ( *con )[ ( *ncon )++ ] = (double) ( *argcount )[ --( *lpar ) ]; } } /* Finally, if the symbol which opened this level of parenthesis was not a function call ("nargs" entry in the symbol data is zero), then decrement the parenthesis level. In this case there is no need to check the argument count, because it will not have been incremented. */ } else { ( *lpar )--; } } } /* If an error occurred (or the global error status was set on entry), then reset the parenthesis level and free any memory which may have been allocated. */ if ( !astOK ) { *lpar = 0; if ( *argcount ) *argcount = astFree( *argcount ); if ( *opensym ) *opensym = astFree( *opensym ); if ( *con ) *con = astFree( *con ); } } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* *att++ * Name: * Seed * Purpose: * Random number seed for a MathMap. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute, which may take any integer value, determines the * sequence of random numbers produced by the random number functions in * MathMap expressions. It is set to an unpredictable default value when * a MathMap is created, so that by default each MathMap uses a different * set of random numbers. * * If required, you may set this Seed attribute to a value of your * choosing in order to produce repeatable behaviour from the random * number functions. You may also enquire the Seed value (e.g. if an * initially unpredictable value has been used) and then use it to * reproduce the resulting sequence of random numbers, either from the * same MathMap or from another one. * * Clearing the Seed attribute gives it a new unpredictable default * value. * Applicability: * MathMap * All MathMaps have this attribute. *att-- */ /* Clear the Seed value by setting it to a new unpredictable value produced by DefaultSeed and clearing the "seed_set" flag in the MathMap's random number generator context. Also clear the "active" flag, so that the generator will be re-initialised to use this seed when it is next invoked. */ astMAKE_CLEAR(MathMap,Seed,rcontext.seed,( this->rcontext.seed_set = 0, this->rcontext.active = 0, DefaultSeed( &this->rcontext, status ) )) /* Return the "seed" value from the random number generator context. */ astMAKE_GET(MathMap,Seed,int,0,this->rcontext.seed) /* Store the new seed value in the MathMap's random number generator context and set the context's "seed_set" flag. Also clear the "active" flag, so that the generator will be re-initialised to use this seed when it is next invoked. */ astMAKE_SET(MathMap,Seed,int,rcontext.seed,( this->rcontext.seed_set = 1, this->rcontext.active = 0, value )) /* Test the "seed_set" flag in the random number generator context. */ astMAKE_TEST(MathMap,Seed,( this->rcontext.seed_set )) /* *att++ * Name: * SimpFI * Purpose: * Forward-inverse MathMap pairs simplify? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: c This attribute should be set to a non-zero value if applying a c MathMap's forward transformation, followed immediately by the matching c inverse transformation will always restore the original set of c coordinates. It indicates that AST may replace such a sequence of c operations by an identity Mapping (a UnitMap) if it is encountered c while simplifying a compound Mapping (e.g. using astSimplify). f This attribute should be set to a non-zero value if applying a f MathMap's forward transformation, followed immediately by the matching f inverse transformation will always restore the original set of f coordinates. It indicates that AST may replace such a sequence of f operations by an identity Mapping (a UnitMap) if it is encountered f while simplifying a compound Mapping (e.g. using AST_SIMPLIFY). * * By default, the SimpFI attribute is zero, so that AST will not perform * this simplification unless you have set SimpFI to indicate that it is * safe to do so. * Applicability: * MathMap * All MathMaps have this attribute. * Notes: * - For simplification to occur, the two MathMaps must be in series and * be identical (with textually identical transformation * functions). Functional equivalence is not sufficient. * - The consent of both MathMaps is required before simplification can * take place. If either has a SimpFI value of zero, then simplification * will not occur. * - The SimpFI attribute controls simplification only in the case where * a MathMap's forward transformation is followed by the matching inverse * transformation. It does not apply if an inverse transformation is * followed by a forward transformation. This latter case is controlled * by the SimpIF attribute. c - The "forward" and "inverse" transformations referred to are those c defined when the MathMap is created (corresponding to the "fwd" and c "inv" parameters of its constructor function). If the MathMap is c inverted (i.e. its Invert attribute is non-zero), then the role of the c SimpFI and SimpIF attributes will be interchanged. f - The "forward" and "inverse" transformations referred to are those f defined when the MathMap is created (corresponding to the FWD and f INV arguments of its constructor function). If the MathMap is f inverted (i.e. its Invert attribute is non-zero), then the role of the f SimpFI and SimpIF attributes will be interchanged. *att-- */ /* Clear the SimpFI value by setting it to -INT_MAX. */ astMAKE_CLEAR(MathMap,SimpFI,simp_fi,-INT_MAX) /* Supply a default of 0 if no SimpFI value has been set. */ astMAKE_GET(MathMap,SimpFI,int,0,( ( this->simp_fi != -INT_MAX ) ? this->simp_fi : 0 )) /* Set a SimpFI value of 1 if any non-zero value is supplied. */ astMAKE_SET(MathMap,SimpFI,int,simp_fi,( value != 0 )) /* The SimpFI value is set if it is not -INT_MAX. */ astMAKE_TEST(MathMap,SimpFI,( this->simp_fi != -INT_MAX )) /* *att++ * Name: * SimpIF * Purpose: * Inverse-forward MathMap pairs simplify? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: c This attribute should be set to a non-zero value if applying a c MathMap's inverse transformation, followed immediately by the matching c forward transformation will always restore the original set of c coordinates. It indicates that AST may replace such a sequence of c operations by an identity Mapping (a UnitMap) if it is encountered c while simplifying a compound Mapping (e.g. using astSimplify). f This attribute should be set to a non-zero value if applying a f MathMap's inverse transformation, followed immediately by the matching f forward transformation will always restore the original set of f coordinates. It indicates that AST may replace such a sequence of f operations by an identity Mapping (a UnitMap) if it is encountered f while simplifying a compound Mapping (e.g. using AST_SIMPLIFY). * * By default, the SimpIF attribute is zero, so that AST will not perform * this simplification unless you have set SimpIF to indicate that it is * safe to do so. * Applicability: * MathMap * All MathMaps have this attribute. * Notes: * - For simplification to occur, the two MathMaps must be in series and * be identical (with textually identical transformation * functions). Functional equivalence is not sufficient. * - The consent of both MathMaps is required before simplification can * take place. If either has a SimpIF value of zero, then simplification * will not occur. * - The SimpIF attribute controls simplification only in the case where * a MathMap's inverse transformation is followed by the matching forward * transformation. It does not apply if a forward transformation is * followed by an inverse transformation. This latter case is controlled * by the SimpFI attribute. c - The "forward" and "inverse" transformations referred to are those c defined when the MathMap is created (corresponding to the "fwd" and c "inv" parameters of its constructor function). If the MathMap is c inverted (i.e. its Invert attribute is non-zero), then the role of the c SimpFI and SimpIF attributes will be interchanged. f - The "forward" and "inverse" transformations referred to are those f defined when the MathMap is created (corresponding to the FWD and f INV arguments of its constructor function). If the MathMap is f inverted (i.e. its Invert attribute is non-zero), then the role of the f SimpFI and SimpIF attributes will be interchanged. *att-- */ /* Clear the SimpIF value by setting it to -INT_MAX. */ astMAKE_CLEAR(MathMap,SimpIF,simp_if,-INT_MAX) /* Supply a default of 0 if no SimpIF value has been set. */ astMAKE_GET(MathMap,SimpIF,int,0,( ( this->simp_if != -INT_MAX ) ? this->simp_if : 0 )) /* Set a SimpIF value of 1 if any non-zero value is supplied. */ astMAKE_SET(MathMap,SimpIF,int,simp_if,( value != 0 )) /* The SimpIF value is set if it is not -INT_MAX. */ astMAKE_TEST(MathMap,SimpIF,( this->simp_if != -INT_MAX )) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for MathMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for MathMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy. */ /* Local Variables: */ AstMathMap *in; /* Pointer to input MathMap */ AstMathMap *out; /* Pointer to output MathMap */ int ifun; /* Loop counter for functions */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output MathMaps. */ in = (AstMathMap *) objin; out = (AstMathMap *) objout; /* For safety, first clear any references to the input memory from the output MathMap. */ out->fwdfun = NULL; out->invfun = NULL; out->fwdcode = NULL; out->invcode = NULL; out->fwdcon = NULL; out->invcon = NULL; /* Now allocate and initialise each of the output pointer arrays required. */ if ( in->fwdfun ) { MALLOC_POINTER_ARRAY( out->fwdfun, char *, out->nfwd ) } if ( in->invfun ) { MALLOC_POINTER_ARRAY( out->invfun, char *, out->ninv ) } if ( in->fwdcode ) { MALLOC_POINTER_ARRAY( out->fwdcode, int *, out->nfwd ) } if ( in->invcode ) { MALLOC_POINTER_ARRAY( out->invcode, int *, out->ninv ) } if ( in->fwdcon ) { MALLOC_POINTER_ARRAY( out->fwdcon, double *, out->nfwd ) } if ( in->invcon ) { MALLOC_POINTER_ARRAY( out->invcon, double *, out->ninv ) } /* If OK, loop to make copies of the data (where available) associated with each forward transformation function, storing pointers to the copy in the output pointer arrays allocated above. */ if ( astOK ) { for ( ifun = 0; ifun < out->nfwd; ifun++ ) { if ( in->fwdfun && in->fwdfun[ ifun ] ) { out->fwdfun[ ifun ] = astStore( NULL, in->fwdfun[ ifun ], astSizeOf( in->fwdfun[ ifun ] ) ); } if ( in->fwdcode && in->fwdcode[ ifun ] ) { out->fwdcode[ ifun ] = astStore( NULL, in->fwdcode[ ifun ], astSizeOf( in->fwdcode[ ifun ] ) ); } if ( in->fwdcon && in->fwdcon[ ifun ] ) { out->fwdcon[ ifun ] = astStore( NULL, in->fwdcon[ ifun ], astSizeOf( in->fwdcon[ ifun ] ) ); } if ( !astOK ) break; } } /* Repeat this process for the inverse transformation functions. */ if ( astOK ) { for ( ifun = 0; ifun < out->ninv; ifun++ ) { if ( in->invfun && in->invfun[ ifun ] ) { out->invfun[ ifun ] = astStore( NULL, in->invfun[ ifun ], astSizeOf( in->invfun[ ifun ] ) ); } if ( in->invcode && in->invcode[ ifun ] ) { out->invcode[ ifun ] = astStore( NULL, in->invcode[ ifun ], astSizeOf( in->invcode[ ifun ] ) ); } if ( in->invcon && in->invcon[ ifun ] ) { out->invcon[ ifun ] = astStore( NULL, in->invcon[ ifun ], astSizeOf( in->invcon[ ifun ] ) ); } if ( !astOK ) break; } } /* If an error occurred, clean up by freeing all output memory allocated above. */ if ( !astOK ) { FREE_POINTER_ARRAY( out->fwdfun, out->nfwd ) FREE_POINTER_ARRAY( out->invfun, out->ninv ) FREE_POINTER_ARRAY( out->fwdcode, out->nfwd ) FREE_POINTER_ARRAY( out->invcode, out->ninv ) FREE_POINTER_ARRAY( out->fwdcon, out->nfwd ) FREE_POINTER_ARRAY( out->invcon, out->ninv ) } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for MathMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for MathMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstMathMap *this; /* Pointer to MathMap */ /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) obj; /* Free all memory allocated by the MathMap. */ FREE_POINTER_ARRAY( this->fwdfun, this->nfwd ) FREE_POINTER_ARRAY( this->invfun, this->ninv ) FREE_POINTER_ARRAY( this->fwdcode, this->nfwd ) FREE_POINTER_ARRAY( this->invcode, this->ninv ) FREE_POINTER_ARRAY( this->fwdcon, this->nfwd ) FREE_POINTER_ARRAY( this->invcon, this->ninv ) } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for MathMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the MathMap class to an output Channel. * Parameters: * this * Pointer to the MathMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Constants: */ #define COMMENT_LEN 150 /* Maximum length of a comment string */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstMathMap *this; /* Pointer to the MathMap structure */ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword strings */ int ifun; /* Loop counter for functions */ int invert; /* MathMap inverted? */ int ival; /* Integer attribute value */ int nin; /* True number of input coordinates */ int nout; /* True number of output coordinates */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the MathMap structure. */ this = (AstMathMap *) this_object; /* Determine if the MathMap is inverted and obtain the "true" number of input and output coordinates by un-doing the effects of any inversion. */ invert = astGetInvert( this ); nin = !invert ? astGetNin( this ) : astGetNout( this ); nout = !invert ? astGetNout( this ) : astGetNin( this ); /* Write out values representing the instance variables for the MathMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Number of forward transformation functions. */ /* ------------------------------------------- */ /* We regard this value as set if it differs from the number of output coordinates for the MathMap. */ set = ( this->nfwd != nout ); astWriteInt( channel, "Nfwd", set, 0, this->nfwd, "Number of forward transformation functions" ); /* Forward transformation functions. */ /* --------------------------------- */ /* Loop to write out each forward transformation function, generating a suitable keyword and comment for each one. */ for ( ifun = 0; ifun < this->nfwd; ifun++ ) { (void) sprintf( key, "Fwd%d", ifun + 1 ); (void) sprintf( comment, "Forward function %d", ifun + 1 ); astWriteString( channel, key, 1, 1, this->fwdfun[ ifun ], comment ); } /* Number of inverse transformation functions. */ /* ------------------------------------------- */ /* We regard this value as set if it differs from the number of input coordinates for the MathMap. */ set = ( this->ninv != nin ); astWriteInt( channel, "Ninv", set, 0, this->ninv, "Number of inverse transformation functions" ); /* Inverse transformation functions. */ /* --------------------------------- */ /* Similarly, loop to write out each inverse transformation function. */ for ( ifun = 0; ifun < this->ninv; ifun++ ) { (void) sprintf( key, "Inv%d", ifun + 1 ); (void) sprintf( comment, "Inverse function %d", ifun + 1 ); astWriteString( channel, key, 1, 1, this->invfun[ ifun ], comment ); } /* SimpFI. */ /* ------- */ /* Write out the forward-inverse simplification flag. */ set = TestSimpFI( this, status ); ival = set ? GetSimpFI( this, status ) : astGetSimpFI( this ); astWriteInt( channel, "SimpFI", set, 0, ival, ival ? "Forward-inverse pairs may simplify" : "Forward-inverse pairs do not simplify" ); /* SimpIF. */ /* ------- */ /* Write out the inverse-forward simplification flag. */ set = TestSimpIF( this, status ); ival = set ? GetSimpIF( this, status ) : astGetSimpIF( this ); astWriteInt( channel, "SimpIF", set, 0, ival, ival ? "Inverse-forward pairs may simplify" : "Inverse-forward pairs do not simplify" ); /* Seed. */ /* ----- */ /* Write out any random number seed value which is set. Prefix this with a separate flag which indicates if the seed has been set. */ set = TestSeed( this, status ); ival = set ? GetSeed( this, status ) : astGetSeed( this ); astWriteInt( channel, "Seeded", set, 0, set, set? "Explicit random number seed set" : "No random number seed set" ); astWriteInt( channel, "Seed", set, 0, ival, set ? "Random number seed value" : "Default random number seed used" ); /* Undefine macros local to this function. */ #undef COMMENT_LEN #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAMathMap and astCheckMathMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(MathMap,Mapping) astMAKE_CHECK(MathMap) AstMathMap *astMathMap_( int nin, int nout, int nfwd, const char *fwd[], int ninv, const char *inv[], const char *options, int *status, ...) { /* *+ * Name: * astMathMap * Purpose: * Create a MathMap. * Type: * Protected function. * Synopsis: * #include "mathmap.h" * AstMathMap *astMathMap( int nin, int nout, * int nfwd, const char *fwd[], * int ninv, const char *inv[], * const char *options, ..., int *status ) * Class Membership: * MathMap constructor. * Description: * This function creates a new MathMap and optionally initialises its * attributes. * Parameters: * nin * Number of input variables for the MathMap. * nout * Number of output variables for the MathMap. * nfwd * The number of forward transformation functions being supplied. * This must be at least equal to "nout". * fwd * Pointer to an array, with "nfwd" elements, of pointers to null * terminated strings which contain each of the forward transformation * functions. * ninv * The number of inverse transformation functions being supplied. * This must be at least equal to "nin". * inv * Pointer to an array, with "ninv" elements, of pointers to null * terminated strings which contain each of the inverse transformation * functions. * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new MathMap. The syntax used is the same as * for the astSet method and may include "printf" format * specifiers identified by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then * an optional list of arguments may follow it in order to * supply values to be substituted for these specifiers. The * rules for supplying these are identical to those for the * astSet method (and for the C "printf" function). * Returned Value: * A pointer to the new MathMap. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic MathMap constructor which is * available via the protected interface to the MathMap class. A * public interface is provided by the astMathMapId_ function. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMathMap *new; /* Pointer to new MathMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the MathMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitMathMap( NULL, sizeof( AstMathMap ), !class_init, &class_vtab, "MathMap", nin, nout, nfwd, fwd, ninv, inv ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new MathMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new MathMap. */ return new; } AstMathMap *astMathMapId_( int nin, int nout, int nfwd, const char *fwd[], int ninv, const char *inv[], const char *options, ... ) { /* *++ * Name: c astMathMap f AST_MATHMAP * Purpose: * Create a MathMap. * Type: * Public function. * Synopsis: c #include "mathmap.h" c AstMathMap *astMathMap( int nin, int nout, c int nfwd, const char *fwd[], c int ninv, const char *inv[], c const char *options, ... ) f RESULT = AST_MATHMAP( NIN, NOUT, NFWD, FWD, NINV, INV, OPTIONS, STATUS ) * Class Membership: * MathMap constructor. * Description: * This function creates a new MathMap and optionally initialises its * attributes. * c A MathMap is a Mapping which allows you to specify a set of forward c and/or inverse transformation functions using arithmetic operations c and mathematical functions similar to those available in C. The c MathMap interprets these functions at run-time, whenever its forward c or inverse transformation is required. Because the functions are not c compiled in the normal sense (unlike an IntraMap), they may be used to c describe coordinate transformations in a transportable manner. A c MathMap therefore provides a flexible way of defining new types of c Mapping whose descriptions may be stored as part of a dataset and c interpreted by other programs. f A MathMap is a Mapping which allows you to specify a set of forward f and/or inverse transformation functions using arithmetic operations f and mathematical functions similar to those available in Fortran. The f MathMap interprets these functions at run-time, whenever its forward f or inverse transformation is required. Because the functions are not f compiled in the normal sense (unlike an IntraMap), they may be used to f describe coordinate transformations in a transportable manner. A f MathMap therefore provides a flexible way of defining new types of f Mapping whose descriptions may be stored as part of a dataset and f interpreted by other programs. * Parameters: c nin f NIN = INTEGER * Number of input variables for the MathMap. This determines the * value of its Nin attribute. c nout f NOUT = INTEGER * Number of output variables for the MathMap. This determines the * value of its Nout attribute. c nfwd f NFWD = INTEGER * The number of forward transformation functions being supplied. c This must be at least equal to "nout", but may be increased to f This must be at least equal to NOUT, but may be increased to * accommodate any additional expressions which define intermediate * variables for the forward transformation (see the "Calculating * Intermediate Values" section below). c fwd f FWD = CHARACTER * ( * )( NFWD ) c An array (with "nfwd" elements) of pointers to null terminated strings c which contain the expressions defining the forward transformation. f An array which contains the expressions defining the forward f transformation. * The syntax of these expressions is described below. c ninv f NINV = INTEGER * The number of inverse transformation functions being supplied. c This must be at least equal to "nin", but may be increased to f This must be at least equal to NIN, but may be increased to * accommodate any additional expressions which define intermediate * variables for the inverse transformation (see the "Calculating * Intermediate Values" section below). c inv f INV = CHARACTER * ( * )( NINV ) c An array (with "ninv" elements) of pointers to null terminated strings c which contain the expressions defining the inverse transformation. f An array which contains the expressions defining the inverse f transformation. * The syntax of these expressions is described below. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new MathMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. c If no initialisation is required, a zero-length string may be c supplied. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new MathMap. The syntax used is identical to that for the f AST_SET routine. If no initialisation is required, a blank f value may be supplied. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astMathMap() f AST_MATHMAP = INTEGER * A pointer to the new MathMap. * Defining Transformation Functions: c A MathMap's transformation functions are supplied as a set of c expressions in an array of character strings. Normally you would c supply the same number of expressions for the forward transformation, c via the "fwd" parameter, as there are output variables (given by the c MathMap's Nout attribute). For instance, if Nout is 2 you might use: c - "r = sqrt( x * x + y * y )" c - "theta = atan2( y, x )" c c which defines a transformation from Cartesian to polar c coordinates. Here, the variables that appear on the left of each c expression ("r" and "theta") provide names for the output variables c and those that appear on the right ("x" and "y") are references to c input variables. f A MathMap's transformation functions are supplied as a set of f expressions in an array of character strings. Normally you would f supply the same number of expressions for the forward transformation, f via the FWD argument, as there are output variables (given by the f MathMap's Nout attribute). For instance, if Nout is 2 you might use: f - 'R = SQRT( X * X + Y * Y )' f - 'THETA = ATAN2( Y, X )' f f which defines a transformation from Cartesian to polar f coordinates. Here, the variables that appear on the left of each f expression (R and THETA) provide names for the output variables and f those that appear on the right (X and Y) are references to input f variables. * c To complement this, you must also supply expressions for the inverse c transformation via the "inv" parameter. In this case, the number of c expressions given would normally match the number of MathMap input c coordinates (given by the Nin attribute). If Nin is 2, you might use: c - "x = r * cos( theta )" c - "y = r * sin( theta )" c c which expresses the transformation from polar to Cartesian c coordinates. Note that here the input variables ("x" and "y") are c named on the left of each expression, and the output variables ("r" c and "theta") are referenced on the right. f To complement this, you must also supply expressions for the inverse f transformation via the INV argument. In this case, the number of f expressions given would normally match the number of MathMap input f coordinates (given by the Nin attribute). If Nin is 2, you might use: f - 'X = R * COS( THETA )' f - 'Y = R * SIN( THETA )' f f which expresses the transformation from polar to Cartesian f coordinates. Note that here the input variables (X and Y) are named on f the left of each expression, and the output variables (R and THETA) f are referenced on the right. * * Normally, you cannot refer to a variable on the right of an expression * unless it is named on the left of an expression in the complementary * set of functions. Therefore both sets of functions (forward and * inverse) must be formulated using the same consistent set of variable * names. This means that if you wish to leave one of the transformations * undefined, you must supply dummy expressions which simply name each of * the output (or input) variables. For example, you might use: c - "x" c - "y" f - 'X' f - 'Y' * * for the inverse transformation above, which serves to name the input * variables but without defining an inverse transformation. * Calculating Intermediate Values: c It is sometimes useful to calculate intermediate values and then to c use these in the final expressions for the output (or input) c variables. This may be done by supplying additional expressions for c the forward (or inverse) transformation functions. For instance, the c following array of five expressions describes 2-dimensional pin-cushion c distortion: c - "r = sqrt( xin * xin + yin * yin )" c - "rout = r * ( 1 + 0.1 * r * r )" c - "theta = atan2( yin, xin )" c - "xout = rout * cos( theta )" c - "yout = rout * sin( theta )" f It is sometimes useful to calculate intermediate values and then to f use these in the final expressions for the output (or input) f variables. This may be done by supplying additional expressions for f the forward (or inverse) transformation functions. For instance, the f following array of five expressions describes 2-dimensional pin-cushion f distortion: f - 'R = SQRT( XIN * XIN + YIN * YIN )' f - 'ROUT = R * ( 1 + 0.1 * R * R )' f - 'THETA = ATAN2( YIN, XIN )', f - 'XOUT = ROUT * COS( THETA )' f - 'YOUT = ROUT * SIN( THETA )' * c Here, we first calculate three intermediate results ("r", "rout" c and "theta") and then use these to calculate the final results ("xout" c and "yout"). The MathMap knows that only the final two results c constitute values for the output variables because its Nout attribute c is set to 2. You may define as many intermediate variables in this c way as you choose. Having defined a variable, you may then refer to it c on the right of any subsequent expressions. f Here, we first calculate three intermediate results (R, ROUT f and THETA) and then use these to calculate the final results (XOUT f and YOUT). The MathMap knows that only the final two results f constitute values for the output variables because its Nout attribute f is set to 2. You may define as many intermediate variables in this f way as you choose. Having defined a variable, you may then refer to it f on the right of any subsequent expressions. * c Note that when defining the inverse transformation you may only refer c to the output variables "xout" and "yout". The intermediate variables c "r", "rout" and "theta" (above) are private to the forward c transformation and may not be referenced by the inverse c transformation. The inverse transformation may, however, define its c own private intermediate variables. f Note that when defining the inverse transformation you may only refer f to the output variables XOUT and YOUT. The intermediate variables R, f ROUT and THETA (above) are private to the forward transformation and f may not be referenced by the inverse transformation. The inverse f transformation may, however, define its own private intermediate f variables. * Expression Syntax: c The expressions given for the forward and inverse transformations c closely follow the syntax of the C programming language (with some c extensions for compatibility with Fortran). They may contain c references to variables and literal constants, together with c arithmetic, boolean, relational and bitwise operators, and function c invocations. A set of symbolic constants is also available. Each of c these is described in detail below. Parentheses may be used to c over-ride the normal order of evaluation. There is no built-in limit c to the length of expressions and they are insensitive to case or the c presence of additional white space. f The expressions given for the forward and inverse transformations f closely follow the syntax of Fortran (with some extensions for f compatibility with the C language). They may contain references to f variables and literal constants, together with arithmetic, logical, f relational and bitwise operators, and function invocations. A set of f symbolic constants is also available. Each of these is described in f detail below. Parentheses may be used to over-ride the normal order of f evaluation. There is no built-in limit to the length of expressions f and they are insensitive to case or the presence of additional white f space. * Variables: * Variable names must begin with an alphabetic character and may contain * only alphabetic characters, digits, and the underscore character * "_". There is no built-in limit to the length of variable names. * Literal Constants: c Literal constants, such as "0", "1", "0.007" or "2.505e-16" may appear c in expressions, with the decimal point and exponent being optional (a c "D" may also be used as an exponent character for compatibility with c Fortran). A unary minus "-" may be used as a prefix. f Literal constants, such as "0", "1", "0.007" or "2.505E-16" may appear f in expressions, with the decimal point and exponent being optional (a f "D" may also be used as an exponent character). A unary minus "-" may f be used as a prefix. * Arithmetic Precision: * All arithmetic is floating point, performed in double precision. * Propagation of Missing Data: * Unless indicated otherwise, if any argument of a function or operator * has the value AST__BAD (indicating missing data), then the result of * that function or operation is also AST__BAD, so that such values are * propagated automatically through all operations performed by MathMap * transformations. The special value AST__BAD can be represented in * expressions by the symbolic constant "". * * A result (i.e. equal to AST__BAD) is also produced in response * to any numerical error (such as division by zero or numerical * overflow), or if an invalid argument value is provided to a function * or operator. * Arithmetic Operators: * The following arithmetic operators are available: c - x1 + x2: Sum of "x1" and "x2". f - X1 + X2: Sum of X1 and X2. c - x1 - x2: Difference of "x1" and "x2". f - X1 - X2: Difference of X1 and X2. c - x1 * x2: Product of "x1" and "x1". f - X1 * X2: Product of X1 and X2. c - x1 / x2: Ratio of "x1" and "x2". f - X1 / X2: Ratio of X1 and X2. c - x1 ** x2: "x1" raised to the power of "x2". f - X1 ** X2: X1 raised to the power of X2. c - + x: Unary plus, has no effect on its argument. f - + X: Unary plus, has no effect on its argument. c - - x: Unary minus, negates its argument. f - - X: Unary minus, negates its argument. c Boolean Operators: f Logical Operators: c Boolean values are represented using zero to indicate false and c non-zero to indicate true. In addition, the value AST__BAD is taken to c mean "unknown". The values returned by boolean operators may therefore c be 0, 1 or AST__BAD. Where appropriate, "tri-state" logic is c implemented. For example, "a||b" may evaluate to 1 if "a" is non-zero, c even if "b" has the value AST__BAD. This is because the result of the c operation would not be affected by the value of "b", so long as "a" is c non-zero. f Logical values are represented using zero to indicate .FALSE. and f non-zero to indicate .TRUE.. In addition, the value AST__BAD is taken to f mean "unknown". The values returned by logical operators may therefore f be 0, 1 or AST__BAD. Where appropriate, "tri-state" logic is f implemented. For example, A.OR.B may evaluate to 1 if A is non-zero, f even if B has the value AST__BAD. This is because the result of the f operation would not be affected by the value of B, so long as A is f non-zero. * c The following boolean operators are available: f The following logical operators are available: c - x1 && x2: Boolean AND between "x1" and "x2", returning 1 if both "x1" c and "x2" are non-zero, and 0 otherwise. This operator implements c tri-state logic. (The synonym ".and." is also provided for compatibility c with Fortran.) f - X1 .AND. X2: Logical AND between X1 and X2, returning 1 if both X1 f and X2 are non-zero, and 0 otherwise. This operator implements f tri-state logic. (The synonym "&&" is also provided for compatibility f with C.) c - x1 || x2: Boolean OR between "x1" and "x2", returning 1 if either "x1" c or "x2" are non-zero, and 0 otherwise. This operator implements c tri-state logic. (The synonym ".or." is also provided for compatibility c with Fortran.) f - X1 .OR. X2: Logical OR between X1 and X2, returning 1 if either X1 f or X2 are non-zero, and 0 otherwise. This operator implements f tri-state logic. (The synonym "||" is also provided for compatibility f with C.) c - x1 ^^ x2: Boolean exclusive OR (XOR) between "x1" and "x2", returning c 1 if exactly one of "x1" and "x2" is non-zero, and 0 otherwise. Tri-state c logic is not used with this operator. (The synonyms ".neqv." and ".xor." c are also provided for compatibility with Fortran, although the second c of these is not standard.) f - X1 .NEQV. X2: Logical exclusive OR (XOR) between X1 and X2, f returning 1 if exactly one of X1 and X2 is non-zero, and 0 f otherwise. Tri-state logic is not used with this operator. (The f synonym ".XOR." is also provided, although this is not standard f Fortran. In addition, the C-like synonym "^^" may be used, although f this is also not standard.) c - x1 .eqv. x2: This is provided only for compatibility with Fortran c and tests whether the boolean states of "x1" and "x2" (i.e. true/false) c are equal. It is the negative of the exclusive OR (XOR) function. c Tri-state logic is not used with this operator. f - X1 .EQV. X2: Tests whether the logical states of X1 and X2 f (i.e. .TRUE./.FALSE.) are equal. It is the negative of the exclusive OR f (XOR) function. Tri-state logic is not used with this operator. c - ! x: Boolean unary NOT operation, returning 1 if "x" is zero, and c 0 otherwise. (The synonym ".not." is also provided for compatibility c with Fortran.) f - .NOT. X: Logical unary NOT operation, returning 1 if X is zero, and f 0 otherwise. (The synonym "!" is also provided for compatibility with f C.) * Relational Operators: c Relational operators return the boolean result (0 or 1) of comparing c the values of two floating point values for equality or inequality. The c value AST__BAD may also be returned if either argument is . f Relational operators return the logical result (0 or 1) of comparing f the values of two floating point values for equality or inequality. The f value AST__BAD may also be returned if either argument is . * * The following relational operators are available: c - x1 == x2: Tests whether "x1" equals "x1". (The synonym ".eq." is c also provided for compatibility with Fortran.) f - X1 .EQ. X2: Tests whether X1 equals X2. (The synonym "==" is also f provided for compatibility with C.) c - x1 != x2: Tests whether "x1" is unequal to "x2". (The synonym ".ne." c is also provided for compatibility with Fortran.) f - X1 .NE. X2: Tests whether X1 is unequal to X2. (The synonym "!=" is f also provided for compatibility with C.) c - x1 > x2: Tests whether "x1" is greater than "x2". (The synonym c ".gt." is also provided for compatibility with Fortran.) f - X1 .GT. X2: Tests whether X1 is greater than X2. (The synonym ">" is f also provided for compatibility with C.) c - x1 >= x2: Tests whether "x1" is greater than or equal to "x2". (The c synonym ".ge." is also provided for compatibility with Fortran.) f - X1 .GE. X2: Tests whether X1 is greater than or equal to X2. (The f synonym ">=" is also provided for compatibility with C.) c - x1 < x2: Tests whether "x1" is less than "x2". (The synonym ".lt." c is also provided for compatibility with Fortran.) f - X1 .LT. X2: Tests whether X1 is less than X2. (The synonym "<" is also f provided for compatibility with C.) c - x1 <= x2: Tests whether "x1" is less than or equal to "x2". (The c synonym ".le." is also provided for compatibility with Fortran.) f - X1 .LE. X2: Tests whether X1 is less than or equal to X2. (The synonym f "<=" is also provided for compatibility with C.) * c Note that relational operators cannot usefully be used to compare c values with the value (representing missing data), because the c result is always . The isbad() function should be used instead. f Note that relational operators cannot usefully be used to compare f values with the value (representing missing data), because the f result is always . The ISBAD() function should be used instead. f f Note, also, that because logical operators can operate on floating f point values, care must be taken to use parentheses in some cases f where they would not normally be required in Fortran. For example, f the expresssion: f - .NOT. A .EQ. B f f must be written: f - .NOT. ( A .EQ. B ) f f to prevent the .NOT. operator from associating with the variable A. * Bitwise Operators: c The bitwise operators provided by C are often useful when operating on c raw data (e.g. from instruments), so they are also provided for use in c MathMap expressions. In this case, however, the values on which they c operate are floating point values rather than pure integers. In order c to produce results which match the pure integer case, the operands are c regarded as fixed point binary numbers (i.e. with the binary c equivalent of a decimal point) with negative numbers represented using c twos-complement notation. For integer values, the resulting bit c pattern corresponds to that of the equivalent signed integer (digits c to the right of the point being zero). Operations on the bits c representing the fractional part are also possible, however. f Bitwise operators are often useful when operating on raw data f (e.g. from instruments), so they are provided for use in MathMap f expressions. In this case, however, the values on which they operate f are floating point values rather than the more usual pure integers. In f order to produce results which match the pure integer case, the f operands are regarded as fixed point binary numbers (i.e. with the f binary equivalent of a decimal point) with negative numbers f represented using twos-complement notation. For integer values, the f resulting bit pattern corresponds to that of the equivalent signed f integer (digits to the right of the point being zero). Operations on f the bits representing the fractional part are also possible, however. * * The following bitwise operators are available: c - x1 >> x2: Rightward bit shift. The integer value of "x2" is taken c (rounding towards zero) and the bits representing "x1" are then c shifted this number of places to the right (or to the left if the c number of places is negative). This is equivalent to dividing "x1" by c the corresponding power of 2. f - X1 >> X2: Rightward bit shift. The integer value of X2 is taken f (rounding towards zero) and the bits representing X1 are then f shifted this number of places to the right (or to the left if the f number of places is negative). This is equivalent to dividing X1 by f the corresponding power of 2. c - x1 << x2: Leftward bit shift. The integer value of "x2" is taken c (rounding towards zero), and the bits representing "x1" are then c shifted this number of places to the left (or to the right if the c number of places is negative). This is equivalent to multiplying "x1" c by the corresponding power of 2. f - X1 << X2: Leftward bit shift. The integer value of X2 is taken f (rounding towards zero), and the bits representing X1 are then f shifted this number of places to the left (or to the right if the f number of places is negative). This is equivalent to multiplying X1 f by the corresponding power of 2. c - x1 & x2: Bitwise AND between the bits of "x1" and those of "x2" c (equivalent to a boolean AND applied at each bit position in turn). f - X1 & X2: Bitwise AND between the bits of X1 and those of X2 f (equivalent to a logical AND applied at each bit position in turn). c - x1 | x2: Bitwise OR between the bits of "x1" and those of "x2" c (equivalent to a boolean OR applied at each bit position in turn). f - X1 | X2: Bitwise OR between the bits of X1 and those of X2 f (equivalent to a logical OR applied at each bit position in turn). c - x1 ^ x2: Bitwise exclusive OR (XOR) between the bits of "x1" and c those of "x2" (equivalent to a boolean XOR applied at each bit c position in turn). f - X1 ^ X2: Bitwise exclusive OR (XOR) between the bits of X1 and f those of X2 (equivalent to a logical XOR applied at each bit f position in turn). * c Note that no bit inversion operator ("~" in C) is provided. This is c because inverting the bits of a twos-complement fixed point binary c number is equivalent to simply negating it. This differs from the c pure integer case because bits to the right of the binary point are c also inverted. To invert only those bits to the left of the binary c point, use a bitwise exclusive OR with the value -1 (i.e. "x^-1"). f Note that no bit inversion operator is provided. This is f because inverting the bits of a twos-complement fixed point binary f number is equivalent to simply negating it. This differs from the f pure integer case because bits to the right of the binary point are f also inverted. To invert only those bits to the left of the binary f point, use a bitwise exclusive OR with the value -1 (i.e. X^-1). * Functions: * The following functions are available: c - abs(x): Absolute value of "x" (sign removal), same as fabs(x). f - ABS(X): Absolute value of X (sign removal), same as FABS(X). c - acos(x): Inverse cosine of "x", in radians. f - ACOS(X): Inverse cosine of X, in radians. c - acosd(x): Inverse cosine of "x", in degrees. f - ACOSD(X): Inverse cosine of X, in degrees. c - acosh(x): Inverse hyperbolic cosine of "x". f - ACOSH(X): Inverse hyperbolic cosine of X. c - acoth(x): Inverse hyperbolic cotangent of "x". f - ACOTH(X): Inverse hyperbolic cotangent of X. c - acsch(x): Inverse hyperbolic cosecant of "x". f - ACSCH(X): Inverse hyperbolic cosecant of X. c - aint(x): Integer part of "x" (round towards zero), same as int(x). f - AINT(X): Integer part of X (round towards zero), same as INT(X). c - asech(x): Inverse hyperbolic secant of "x". f - ASECH(X): Inverse hyperbolic secant of X. c - asin(x): Inverse sine of "x", in radians. f - ASIN(X): Inverse sine of X, in radians. c - asind(x): Inverse sine of "x", in degrees. f - ASIND(X): Inverse sine of X, in degrees. c - asinh(x): Inverse hyperbolic sine of "x". f - ASINH(X): Inverse hyperbolic sine of X. c - atan(x): Inverse tangent of "x", in radians. f - ATAN(X): Inverse tangent of X, in radians. c - atand(x): Inverse tangent of "x", in degrees. f - ATAND(X): Inverse tangent of X, in degrees. c - atanh(x): Inverse hyperbolic tangent of "x". f - ATANH(X): Inverse hyperbolic tangent of X. c - atan2(x1, x2): Inverse tangent of "x1/x2", in radians. f - ATAN2(X1, X2): Inverse tangent of X1/X2, in radians. c - atan2d(x1, x2): Inverse tangent of "x1/x2", in degrees. f - ATAN2D(X1, X2): Inverse tangent of X1/X2, in degrees. c - ceil(x): Smallest integer value not less then "x" (round towards c plus infinity). f - CEIL(X): Smallest integer value not less then X (round towards f plus infinity). c - cos(x): Cosine of "x" in radians. f - COS(X): Cosine of X in radians. c - cosd(x): Cosine of "x" in degrees. f - COSD(X): Cosine of X in degrees. c - cosh(x): Hyperbolic cosine of "x". f - COSH(X): Hyperbolic cosine of X. c - coth(x): Hyperbolic cotangent of "x". f - COTH(X): Hyperbolic cotangent of X. c - csch(x): Hyperbolic cosecant of "x". f - CSCH(X): Hyperbolic cosecant of X. c - dim(x1, x2): Returns "x1-x2" if "x1" is greater than "x2", otherwise 0. f - DIM(X1, X2): Returns X1-X2 if X1 is greater than X2, otherwise 0. c - exp(x): Exponential function of "x". f - EXP(X): Exponential function of X. c - fabs(x): Absolute value of "x" (sign removal), same as abs(x). f - FABS(X): Absolute value of X (sign removal), same as ABS(X). c - floor(x): Largest integer not greater than "x" (round towards c minus infinity). f - FLOOR(X): Largest integer not greater than X (round towards f minus infinity). c - fmod(x1, x2): Remainder when "x1" is divided by "x2", same as c mod(x1, x2). f - FMOD(X1, X2): Remainder when X1 is divided by X2, same as f MOD(X1, X2). c - gauss(x1, x2): Random sample from a Gaussian distribution with mean c "x1" and standard deviation "x2". f - GAUSS(X1, X2): Random sample from a Gaussian distribution with mean f X1 and standard deviation X2. c - int(x): Integer part of "x" (round towards zero), same as aint(x). f - INT(X): Integer part of X (round towards zero), same as AINT(X). c - isbad(x): Returns 1 if "x" has the value (AST__BAD), otherwise 0. f - ISBAD(X): Returns 1 if X has the value (AST__BAD), otherwise 0. c - log(x): Natural logarithm of "x". f - LOG(X): Natural logarithm of X. c - log10(x): Logarithm of "x" to base 10. f - LOG10(X): Logarithm of X to base 10. c - max(x1, x2, ...): Maximum of two or more values. f - MAX(X1, X2, ...): Maximum of two or more values. c - min(x1, x2, ...): Minimum of two or more values. f - MIN(X1, X2, ...): Minimum of two or more values. c - mod(x1, x2): Remainder when "x1" is divided by "x2", same as c fmod(x1, x2). f - MOD(X1, X2): Remainder when X1 is divided by X2, same as f FMOD(X1, X2). c - nint(x): Nearest integer to "x" (round to nearest). f - NINT(X): Nearest integer to X (round to nearest). c - poisson(x): Random integer-valued sample from a Poisson c distribution with mean "x". f - POISSON(X): Random integer-valued sample from a Poisson f distribution with mean X. c - pow(x1, x2): "x1" raised to the power of "x2". f - POW(X1, X2): X1 raised to the power of X2. c - qif(x1, x2, x3): Returns "x2" if "x1" is true, and "x3" otherwise. f - QIF(x1, x2, x3): Returns X2 if X1 is true, and X3 otherwise. c - rand(x1, x2): Random sample from a uniform distribution in the c range "x1" to "x2" inclusive. f - RAND(X1, X2): Random sample from a uniform distribution in the f range X1 to X2 inclusive. c - sech(x): Hyperbolic secant of "x". f - SECH(X): Hyperbolic secant of X. c - sign(x1, x2): Absolute value of "x1" with the sign of "x2" c (transfer of sign). f - SIGN(X1, X2): Absolute value of X1 with the sign of X2 f (transfer of sign). c - sin(x): Sine of "x" in radians. f - SIN(X): Sine of X in radians. c - sinc(x): Sinc function of "x" [= "sin(x)/x"]. f - SINC(X): Sinc function of X [= SIN(X)/X]. c - sind(x): Sine of "x" in degrees. f - SIND(X): Sine of X in degrees. c - sinh(x): Hyperbolic sine of "x". f - SINH(X): Hyperbolic sine of X. c - sqr(x): Square of "x" (= "x*x"). f - SQR(X): Square of X (= X*X). c - sqrt(x): Square root of "x". f - SQRT(X): Square root of X. c - tan(x): Tangent of "x" in radians. f - TAN(X): Tangent of X in radians. c - tand(x): Tangent of "x" in degrees. f - TAND(X): Tangent of X in degrees. c - tanh(x): Hyperbolic tangent of "x". f - TANH(X): Hyperbolic tangent of X. * Symbolic Constants: * The following symbolic constants are available (the enclosing "<>" * brackets must be included): c - : The "bad" value (AST__BAD) used to flag missing data. Note c that you cannot usefully compare values with this constant because the c result is always . The isbad() function should be used instead. f - : The "bad" value (AST__BAD) used to flag missing data. Note f that you cannot usefully compare values with this constant because the f result is always . The ISBAD() function should be used instead. c - : Number of decimal digits of precision available in a c floating point (double) value. f - : Number of decimal digits of precision available in a f floating point (double precision) value. * - : Base of natural logarithms. * - : Smallest positive number such that 1.0+ is * distinguishable from unity. c - : The number of base digits stored in the c mantissa of a floating point (double) value. f - : The number of base digits stored in the f mantissa of a floating point (double precision) value. c - : Maximum representable floating point (double) value. f - : Maximum representable floating point (double precision) value. c - : Maximum integer such that 10 raised to that power c can be represented as a floating point (double) value. f - : Maximum integer such that 10 raised to that power f can be represented as a floating point (double precision) value. c - : Maximum integer such that raised to that c power minus 1 can be represented as a floating point (double) value. f - : Maximum integer such that raised to that f power minus 1 can be represented as a floating point (double precision) f value. c - : Smallest positive number which can be represented as a c normalised floating point (double) value. f - : Smallest positive number which can be represented as a f normalised floating point (double precision) value. c - : Minimum negative integer such that 10 raised to that c power can be represented as a normalised floating point (double) value. f - : Minimum negative integer such that 10 raised to that f power can be represented as a normalised floating point (double f precision) value. c - : Minimum negative integer such that raised to c that power minus 1 can be represented as a normalised floating point c (double) value. f - : Minimum negative integer such that raised to f that power minus 1 can be represented as a normalised floating point f (double precision) value. * - : Ratio of the circumference of a circle to its diameter. c - : The radix (number base) used to represent the mantissa of c floating point (double) values. f - : The radix (number base) used to represent the mantissa of f floating point (double precision) values. * - : The mode used for rounding floating point results after * addition. Possible values include: -1 (indeterminate), 0 (toward * zero), 1 (to nearest), 2 (toward plus infinity) and 3 (toward minus * infinity). Other values indicate machine-dependent behaviour. * Evaluation Precedence and Associativity: * Items appearing in expressions are evaluated in the following order * (highest precedence first): * - Constants and variables * - Function arguments and parenthesised expressions * - Function invocations * - Unary + - ! .not. * - ** * - * / * - + - * - << >> * - < .lt. <= .le. > .gt. >= .ge. * - == .eq. != .ne. * - & * - ^ * - | * - && .and. * - ^^ * - || .or * - .eqv. .neqv. .xor. * * All operators associate from left-to-right, except for unary +, * unary -, !, .not. and ** which associate from right-to-left. * Notes: * - The sequence of numbers produced by the random number functions * available within a MathMap is normally unpredictable and different for * each MathMap. However, this behaviour may be controlled by means of * the MathMap's Seed attribute. c - Normally, compound Mappings (CmpMaps) which involve MathMaps will c not be subject to simplification (e.g. using astSimplify) because AST c cannot know how different MathMaps will interact. However, in the c special case where a MathMap occurs in series with its own inverse, c then simplification may be possible. Whether simplification does, in c fact, occur under these circumstances is controlled by the MathMap's c SimpFI and SimpIF attributes. f - Normally, compound Mappings (CmpMaps) which involve MathMaps will f not be subject to simplification (e.g. using AST_SIMPLIFY) because AST f cannot know how different MathMaps will interact. However, in the f special case where a MathMap occurs in series with its own inverse, f then simplification may be possible. Whether simplification does, in f fact, occur under these circumstances is controlled by the MathMap's f SimpFI and SimpIF attributes. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astMathMap constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astMathMap_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - The variable argument list also prevents this function from * invoking astMathMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMathMap *new; /* Pointer to new MathMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise the MathMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitMathMap( NULL, sizeof( AstMathMap ), !class_init, &class_vtab, "MathMap", nin, nout, nfwd, fwd, ninv, inv ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new MathMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new MathMap. */ return astMakeId( new ); } AstMathMap *astInitMathMap_( void *mem, size_t size, int init, AstMathMapVtab *vtab, const char *name, int nin, int nout, int nfwd, const char *fwd[], int ninv, const char *inv[], int *status ) { /* *+ * Name: * astInitMathMap * Purpose: * Initialise a MathMap. * Type: * Protected function. * Synopsis: * #include "mathmap.h" * AstMathMap *astInitMathMap_( void *mem, size_t size, int init, * AstMathMapVtab *vtab, const char *name, * int nin, int nout, * int nfwd, const char *fwd[], * int ninv, const char *inv[] ) * Class Membership: * MathMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new MathMap object. It allocates memory (if necessary) to accommodate * the MathMap plus any additional data associated with the derived class. * It then initialises a MathMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a MathMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the MathMap is to be initialised. * This must be of sufficient size to accommodate the MathMap data * (sizeof(MathMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the MathMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the MathMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the MathMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new MathMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * nin * Number of input variables for the MathMap. * nout * Number of output variables for the MathMap. * nfwd * The number of forward transformation functions being supplied. * This must be at least equal to "nout". * fwd * Pointer to an array, with "nfwd" elements, of pointers to null * terminated strings which contain each of the forward transformation * functions. * ninv * The number of inverse transformation functions being supplied. * This must be at least equal to "nin". * inv * Pointer to an array, with "ninv" elements, of pointers to null * terminated strings which contain each of the inverse transformation * functions. * Returned Value: * A pointer to the new MathMap. * Notes: * - This function does not attempt to ensure that the forward and inverse * transformations performed by the resulting MathMap are consistent in any * way. * - This function makes a copy of the contents of the strings supplied. * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstMathMap *new; /* Pointer to new MathMap */ char **fwdfun; /* Array of cleaned forward functions */ char **invfun; /* Array of cleaned inverse functions */ double **fwdcon; /* Constants for forward functions */ double **invcon; /* Constants for inverse functions */ int **fwdcode; /* Code for forward functions */ int **invcode; /* Code for inverse functions */ int fwdstack; /* Stack size for forward functions */ int invstack; /* Stack size for inverse functions */ /* Initialise. */ new = NULL; /* Check the global status. */ if ( !astOK ) return new; /* If necessary, initialise the virtual function table. */ if ( init ) astInitMathMapVtab( vtab, name ); /* Check the numbers of input and output variables for validity, reporting an error if necessary. */ if ( nin < 1 ) { astError( AST__BADNI, "astInitMathMap(%s): Bad number of input coordinates (%d).", status, name, nin ); astError( AST__BADNI, "This number should be one or more." , status); } else if ( nout < 1 ) { astError( AST__BADNO, "astInitMathMap(%s): Bad number of output coordinates (%d).", status, name, nout ); astError( AST__BADNI, "This number should be one or more." , status); /* Check that sufficient number of forward and inverse transformation functions have been supplied and report an error if necessary. */ } else if ( nfwd < nout ) { astError( AST__INNTF, "astInitMathMap(%s): Too few forward transformation functions " "given (%d).", status, name, nfwd ); astError( astStatus, "At least %d forward transformation functions must be " "supplied. ", status, nout ); } else if ( ninv < nin ) { astError( AST__INNTF, "astInitMathMap(%s): Too few inverse transformation functions " "given (%d).", status, name, ninv ); astError( astStatus, "At least %d inverse transformation functions must be " "supplied. ", status, nin ); /* Of OK, clean the forward and inverse functions provided. This makes a lower-case copy with white space removed. */ } else { CleanFunctions( nfwd, fwd, &fwdfun, status ); CleanFunctions( ninv, inv, &invfun, status ); /* Compile the cleaned functions. From the returned pointers (if successful), we can now tell which transformations (forward and/or inverse) are defined. */ CompileMapping( "astInitMathMap", name, nin, nout, nfwd, (const char **) fwdfun, ninv, (const char **) invfun, &fwdcode, &invcode, &fwdcon, &invcon, &fwdstack, &invstack, status ); /* Initialise a Mapping structure (the parent class) as the first component within the MathMap structure, allocating memory if necessary. Specify that the Mapping should be defined in the required directions. */ new = (AstMathMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, nin, nout, ( fwdcode != NULL ), ( invcode != NULL ) ); /* If an error has occurred, free all the memory which may have been allocated by the cleaning and compilation steps above. */ if ( !astOK ) { FREE_POINTER_ARRAY( fwdfun, nfwd ) FREE_POINTER_ARRAY( invfun, ninv ) FREE_POINTER_ARRAY( fwdcode, nfwd ) FREE_POINTER_ARRAY( invcode, ninv ) FREE_POINTER_ARRAY( fwdcon, nfwd ) FREE_POINTER_ARRAY( invcon, ninv ) } /* Initialise the MathMap data. */ /* ---------------------------- */ /* Store pointers to the compiled function information, together with other MathMap data. */ if ( new ) { new->fwdfun = fwdfun; new->invfun = invfun; new->fwdcode = fwdcode; new->invcode = invcode; new->fwdcon = fwdcon; new->invcon = invcon; new->fwdstack = fwdstack; new->invstack = invstack; new->nfwd = nfwd; new->ninv = ninv; new->simp_fi = -INT_MAX; new->simp_if = -INT_MAX; /* Initialise the random number generator context associated with the MathMap, using an unpredictable default seed value. */ new->rcontext.active = 0; new->rcontext.random_int = 0; new->rcontext.seed_set = 0; new->rcontext.seed = DefaultSeed( &new->rcontext, status ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new object. */ return new; } AstMathMap *astLoadMathMap_( void *mem, size_t size, AstMathMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadMathMap * Purpose: * Load a MathMap. * Type: * Protected function. * Synopsis: * #include "mathmap.h" * AstMathMap *astLoadMathMap( void *mem, size_t size, * AstMathMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * MathMap loader. * Description: * This function is provided to load a new MathMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * MathMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a MathMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the MathMap is to be * loaded. This must be of sufficient size to accommodate the * MathMap data (sizeof(MathMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the MathMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the MathMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstMathMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new MathMap. If this is NULL, a pointer * to the (static) virtual function table for the MathMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "MathMap" is used instead. * Returned Value: * A pointer to the new MathMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Constants: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstMathMap *new; /* Pointer to the new MathMap */ char key[ KEY_LEN + 1 ]; /* Buffer for keyword strings */ int ifun; /* Loop counter for functions */ int invert; /* Invert attribute value */ int nin; /* True number of input coordinates */ int nout; /* True number of output coordinates */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this MathMap. In this case the MathMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstMathMap ); vtab = &class_vtab; name = "MathMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitMathMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built MathMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "MathMap" ); /* Determine if the MathMap is inverted and obtain the "true" number of input and output coordinates by un-doing the effects of any inversion. */ invert = astGetInvert( new ); nin = invert ? astGetNout( new ) : astGetNin( new ); nout = invert ? astGetNin( new ) : astGetNout( new ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Numbers of transformation functions. */ /* ------------------------------------ */ /* Read the numbers of forward and inverse transformation functions, supplying appropriate defaults. */ new->nfwd = astReadInt( channel, "nfwd", nout ); new->ninv = astReadInt( channel, "ninv", nin ); if ( astOK ) { /* Allocate memory for the MathMap's transformation function arrays. */ MALLOC_POINTER_ARRAY( new->fwdfun, char *, new->nfwd ) MALLOC_POINTER_ARRAY( new->invfun, char *, new->ninv ) if ( astOK ) { /* Forward transformation functions. */ /* --------------------------------- */ /* Create a keyword for each forward transformation function and read the function's value as a string. */ for ( ifun = 0; ifun < new->nfwd; ifun++ ) { (void) sprintf( key, "fwd%d", ifun + 1 ); new->fwdfun[ ifun ] = astReadString( channel, key, "" ); } /* Inverse transformation functions. */ /* --------------------------------- */ /* Repeat this process for the inverse transformation functions. */ for ( ifun = 0; ifun < new->ninv; ifun++ ) { (void) sprintf( key, "inv%d", ifun + 1 ); new->invfun[ ifun ] = astReadString( channel, key, "" ); } /* Forward-inverse simplification flag. */ /* ------------------------------------ */ new->simp_fi = astReadInt( channel, "simpfi", -INT_MAX ); if ( TestSimpFI( new, status ) ) SetSimpFI( new, new->simp_fi, status ); /* Inverse-forward simplification flag. */ /* ------------------------------------ */ new->simp_if = astReadInt( channel, "simpif", -INT_MAX ); if ( TestSimpIF( new, status ) ) SetSimpIF( new, new->simp_if, status ); /* Random number context. */ /* ---------------------- */ /* Initialise the random number generator context. */ new->rcontext.active = 0; new->rcontext.random_int = 0; /* Read the flag that determines if the Seed value is set, and the Seed value itself. */ new->rcontext.seed_set = astReadInt( channel, "seeded", 0 ); if ( TestSeed( new, status ) ) { new->rcontext.seed = astReadInt( channel, "seed", 0 ); SetSeed( new, new->rcontext.seed, status ); /* Supply an unpredictable default Seed value if necessary. */ } else { new->rcontext.seed = DefaultSeed( &new->rcontext, status ); } /* Compile the MathMap's transformation functions. */ CompileMapping( "astLoadMathMap", name, nin, nout, new->nfwd, (const char **) new->fwdfun, new->ninv, (const char **) new->invfun, &new->fwdcode, &new->invcode, &new->fwdcon, &new->invcon, &new->fwdstack, &new->invstack, status ); } /* If an error occurred, clean up by deleting the new MathMap. */ if ( !astOK ) new = astDelete( new ); } } /* Return the new MathMap pointer. */ return new; /* Undefine macros local to this function. */ #undef KEY_LEN } ./ast-7.3.3/f77.h.in0000644000175000017500000011766612262533650012344 0ustar olesoles/* *+ * Name: * f77.h and cnf.h * Purpose: * C - FORTRAN interace macros and prototypes * Language: * C (part ANSI, part not) * Type of Module: * C include file * Description: * For historical reasons two files, F77.h and cnf.h are required * but the have now been combined and for new code, only one is * necessary. * * This file defines the macros needed to write C functions that are * designed to be called from FORTRAN programs, and to do so in a * portable way. Arguments are normally passed by reference from a * FORTRAN program, and so the F77 macros arrange for a pointer to * all arguments to be available. This requires no work on most * machines, but will actually generate the pointers on a machine * that passes FORTRAN arguments by value. * Notes: * - Macros are provided to handle the conversion of logical data * values between the way that FORTRAN represents a value and the * way that C represents it. * - Macros are provided to convert variables between the FORTRAN and * C method of representing them. In most cases there is no * conversion required, the macros just arrange for a pointer to * the FORTRAN variable to be set appropriately. The possibility that * FORTRAN and C might use different ways of representing integer * and floating point values is considered remote, the macros are * really only there for completeness and to assist in the automatic * generation of C interfaces. * - For character variables the macros convert between * the FORTRAN method of representing them (fixed length, blank * filled strings) and the C method (variable length, null * terminated strings) using calls to the CNF functions. * Implementation Deficiencies: * - The macros support the K&R style of function definition, but * this file may not work with all K&R compilers as it contains * "#if defined" statements. These could be replaced with #ifdef's * if necessary. This has not been done as is would make the code * less clear and the need for support for K&R sytle definitions * should disappear as ANSI compilers become the default. * Copyright: * Copyright (C) 1991, 1993 Science & Engineering Research Council. * Copyright (C) 2006 Particle Physics and Astronomy Research Council. * Copyright (C) 2007,2008 Science and 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 General Public License as * published by the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * PMA: Peter Allan (Starlink, RAL) * AJC: Alan Chipperfield (Starlink, RAL) * TIMJ: Tim Jenness (JAC) * PWD: Peter W. Draper (JAC, Durham University) * {enter_new_authors_here} * History: * 23-MAY-1991 (PMA): * Original version. * 19-JUN-1991 (PMA): * Removed VMS versions of IM(EX)PORT_LOGICAL macros that tried * to convert data representations. * 24-JUN-1991 (PMA): * Changed the names of IMPORT macros to GENPTR. * Removed the EXPORT macros. * 27-JUN-1991 (PMA): * Modified DECstation specific stuff to allow use of the c89 * compiler. * 8-JUL-1991 (PMA): * Added macros to call FORTRAN from C. * 16-OCT-1991 (PMA): * Remove type_ARRAY2 definitions. * Remove the length argument from CHARACTER_ARRAY and the * dimension specifier from GENPTR_type_ARRAY. * Add extra brackets to F77_ISFALSE and F77_ISTRUE. * 25-OCT-1991 (PMA): * Changed "if defined(sun4)" to "if defined(sun)" * 2-JUN-1992 (PMA): * Changed "if defined(mips)" to "if defined(ultrix)" to prevent * those definitions being used on a Silicon Graphics machine. * 11-JUN-1992 (PMA): * Changed "if defined(ultrix)" back to "if defined(mips)" so that * it still works on OSF/1 on a DECstation. * Add support for general non-ANSI compilers, but not basic K&R * ones. * 12-JUN-1992 (PMA): * Change declaration of dummy scalar arguments to be const * pointers. Change declaration of dummy array arguments to be * const pointers. * 5-JAN-1993 (PMA): * Changed "if defined(mips)" so that it will recognise a * DECstation running Ultrix or OSF/1, but not a Silicon Graphics * workstation. * Change the definition of F77_BYTE_TYPE to add "signed". * Redefine this on VMS where signed is invalid syntax. * Add new types of UBYTE and UWORD. * 8-JAN-1993 (PMA): * Fix bug in the definition of CHARACTER_RETURN_VALUE. There was * an extraneous space. * Add a macro F77_POINTER_TYPE and use it to define POINTER. * 13-JAN-1993 (PMA): * Start to add support for K&R function definitions. These are * done on a per machine basis. * 16-APR-1993 (PMA): * Change the definition of F77_POINTER_TYPE from int to unsigned * int. * 7-MAY-1993 (PMA): * Change from using a null comment as a token concatenation * operator to using the internal macro _f77_x on non-ANSI * systems. * 10-MAY-1993 (PMA): * Finish adding K&R support. This will form version 2.0 of F77. * 10-MAY-1993 (PMA): * Add support for Alpha OSF/1. * 9-JUL-1993 (PMA): * Add further POINTER macros: POINTER_ARRAY, * GENPTR_POINTER_ARRAY, DECLARE_POINTER, DECLARE_POINTER_ARRAY, * POINTER_ARG, POINTER_ARRAY_ARG, F77_POINTER_FUNCTION, * KR_POINTER_ARRAY. * 24-AUG-1993 (PMA): * Add const to the VMS definitions of CHARACTER and CHARACTER_ARRAY. * 3-NOV-1993 (PMA): * Remove K&R stuff to a separate file. * Released on Unix as version 2.0 of CNF. * 11-NOV-1993 (PMA): * Return to using the null comment to concatenate text on non-ANSI * systems as _f77_x caused problems with the c89 -common flag on * DECstations. * 23-JAN-1996 (AJC): * Add SUBROUTINE, type_FUNCTION, SUBROUTINE_ARG, * type_FUNCTION_ARG, GENPTR_SUBROUTINE and GENPTR_type_FUNCTION * required for passed subroutine and function name. * 29-JAN-1996 (AJC): * Add the dynamic CHARACTER_ macros * and CHARACTER_ARG_TYPE * 22-FEB-1996 (AJC): * Add CHARACTER_RETURN_ARG * 23-MAY-1996 (AJC): * Add DECLARE_CHARACTER_ARRAY_DYN * F77_CREATE_CHARACTER_ARRAY * F77_CHARACTER_ARG_TYPE * 14-JUN-1996 (AJC): * Add DECLARE_LOGICAL_ARRAY_DYN * F77_CREATE_LOGICAL_ARRAY * 21-JUN-1996 (AJC): * Add cast to _ARRAY_ARGs to allow multidimensional arrays * 17-MAR-1998 (AJC): * Add DECLARE, CREATE and FREE dynamic array macros for all types * Changed CREATE_CHARACTER_ARRAY and CREATE_LOGICAL_ARRAY to use * number of elements rather than dimensions. * Add IMPORT, EXPORT and ASSOC macros * 22-JUL-1998 (AJC): * Combined F77.h and cnf.h * 23-SEP-1998 (AJC): * Input strings for cnf -> const char * * Input int arrays for cnf -> const int * * 4-NOV-1998 (AJC): * Bring cnf prototypes in line with .c routines * 8-FEB-1999 (AJC): * Added cnf_mem stuff * 9-FEB-1999 (AJC): * Use cnf_cptr/fptr for IMPORT/EXPORT_POINTER * 16-FEB-1999 (AJC): * Added missing cnf_fptr prototype * 23-JUN-1999 (AJC): * Change cnf_name to cnfName * and add macros for cnf_name * 1-DEC-1999 (AJC): * Add define cnf_free * 7-JAN-2000 (AJC): * Correct omission of F77_ASSOC_UBYTE_ARRAY * Correct F77_EXPORT_UWORD_ARRAY * 25-AUG-2005 (TIMJ): * Add cnfInitRTL * 23-FEB-2006 (TIMJ): * Add cnfRealloc * Use starMalloc rather than malloc in F77_CREATE_POINTER_ARRAY * (since it needs to match what goes on in cnfFree) * 21-JUN-2006 (PWD): * Changed to use a different return type for REAL functions. This * effects g77 under 64-bit, when the f2c bindings expect the return * value of a REAL function to be a double, not a float. * 25-SEP-2006 (PWD): * Introduced F77_CREATE_IMPORT_CHARACTER. Match length of * F77_CREATE_CHARACTER to result from cnfCref. * 13-JUL-2007 (PWD): * Parameterise the type of Fortran character string lengths. Can * be long. * 7-OCT-2008 (TIMJ): * Initialise pointers. * 11-MAY-2011 (DSB): * Added F77_LOCK * {enter_further_changes_here} * * Bugs: * {note_any_bugs_here} *- ------------------------------------------------------------------------------ */ #if !defined(CNF_MACROS) #define CNF_MACROS #include #include /* This initial sections defines values for all macros. These are the */ /* values that are generally appropriate to an ANSI C compiler on Unix. */ /* For macros that have different values on other systems, the macros */ /* should be undefined and then redefined in the system specific sections. */ /* At the end of this section, some macros are redefined if the compiler */ /* is non-ANSI. */ #if defined(__STDC__) || defined(VMS) #define CNF_CONST const #else #define CNF_CONST #endif /* ----- Macros common to calling C from FORTRAN and FORTRAN from C ---- */ /* --- External Names --- */ /* Macro to define the name of a Fortran routine or common block. This */ /* ends in an underscore on many Unix systems. */ #define F77_EXTERNAL_NAME(X) X ## _ /* --- Logical Values --- */ /* Define the values that are used to represent the logical values TRUE */ /* and FALSE in Fortran. */ #define F77_TRUE 1 #define F77_FALSE 0 /* Define macros that evaluate to C logical values, given a FORTRAN */ /* logical value. */ #define F77_ISTRUE(X) ( X ) #define F77_ISFALSE(X) ( !( X ) ) /* --- Common Blocks --- */ /* Macros used in referring to FORTRAN common blocks. */ #define F77_BLANK_COMMON @BLANK_COMMON_SYMBOL@ #define F77_NAMED_COMMON(B) F77_EXTERNAL_NAME(B) /* ------------------ Calling C from FORTRAN --------------------------- */ /* --- Data Types --- */ /* Define macros for all the Fortran data types (except COMPLEX, which is */ /* not handled by this package). */ #define F77_INTEGER_TYPE int #define F77_REAL_TYPE float #define F77_REAL_FUNCTION_TYPE @REAL_FUNCTION_TYPE@ #define F77_DOUBLE_TYPE double #define F77_LOGICAL_TYPE int #define F77_CHARACTER_TYPE char #define F77_BYTE_TYPE signed char #define F77_WORD_TYPE short int #define F77_UBYTE_TYPE unsigned char #define F77_UWORD_TYPE unsigned short int /* Define macros for the type of a CHARACTER and CHARACTER_ARRAY argument */ #define F77_CHARACTER_ARG_TYPE char #define F77_CHARACTER_ARRAY_ARG_TYPE char /* Define a macro to use when passing arguments that STARLINK FORTRAN */ /* treats as a pointer. From the point of view of C, this type should be */ /* (void *), but it is declared as type unsigned int as we actually pass */ /* an INTEGER from the FORTRAN routine. The distinction is important for */ /* architectures where the size of an INTEGER is not the same as the size */ /* of a pointer. */ #define F77_POINTER_TYPE unsigned int /* --- Subroutine Names --- */ /* This declares that the C function returns a value of void. */ #define F77_SUBROUTINE(X) void F77_EXTERNAL_NAME(X) /* --- Function Names --- */ /* Macros to define the types and names of functions that return values. */ /* Due the the different ways that function return values could be */ /* implemented, it is better not to use functions, but to stick to using */ /* subroutines. */ /* Character functions are implemented, but in a way that cannot be */ /* guaranteed to be portable although it will work on VMS, SunOS, Ultrix */ /* and DEC OSF/1. It would be better to return the character value as a */ /* subroutine argument where possible, rather than use a character */ /* function. */ #define F77_INTEGER_FUNCTION(X) F77_INTEGER_TYPE F77_EXTERNAL_NAME(X) #define F77_REAL_FUNCTION(X) F77_REAL_FUNCTION_TYPE F77_EXTERNAL_NAME(X) #define F77_DOUBLE_FUNCTION(X) F77_DOUBLE_TYPE F77_EXTERNAL_NAME(X) #define F77_LOGICAL_FUNCTION(X) F77_LOGICAL_TYPE F77_EXTERNAL_NAME(X) #define F77_CHARACTER_FUNCTION(X) void F77_EXTERNAL_NAME(X) #define F77_BYTE_FUNCTION(X) F77_BYTE_TYPE F77_EXTERNAL_NAME(X) #define F77_WORD_FUNCTION(X) F77_WORD_TYPE F77_EXTERNAL_NAME(X) #define F77_UBYTE_FUNCTION(X) F77_UBYTE_TYPE F77_EXTERNAL_NAME(X) #define F77_UWORD_FUNCTION(X) F77_UWORD_TYPE F77_EXTERNAL_NAME(X) #define F77_POINTER_FUNCTION(X) F77_POINTER_TYPE F77_EXTERNAL_NAME(X) /* --- Character return value for a function --- */ #define CHARACTER_RETURN_VALUE(X) CHARACTER(X) TRAIL(X) #define CHARACTER_RETURN_ARG(X) CHARACTER_ARG(X) TRAIL_ARG(X) /* --- Dummy Arguments --- */ /* Macros for defining subroutine arguments. All these macros take a */ /* single argument; the name of the parameter. On most systems, a numeric */ /* argument is passed as a pointer. */ #define INTEGER(X) F77_INTEGER_TYPE *CNF_CONST X #define REAL(X) F77_REAL_TYPE *CNF_CONST X #define DOUBLE(X) F77_DOUBLE_TYPE *CNF_CONST X #define LOGICAL(X) F77_LOGICAL_TYPE *CNF_CONST X #define BYTE(X) F77_BYTE_TYPE *CNF_CONST X #define WORD(X) F77_WORD_TYPE *CNF_CONST X #define UBYTE(X) F77_UBYTE_TYPE *CNF_CONST X #define UWORD(X) F77_UWORD_TYPE *CNF_CONST X /* Pointer arguments. Define a pointer type for passing pointer values */ /* between subroutines. */ #define POINTER(X) F77_POINTER_TYPE *CNF_CONST X /* EXTERNAL arguments. Define a passed subroutine or function name */ #define SUBROUTINE(X) void (*X)() #define INTEGER_FUNCTION(X) F77_INTEGER_TYPE (*X)() #define REAL_FUNCTION(X) F77_REAL_TYPE (*X)() #define DOUBLE_FUNCTION(X) F77_DOUBLE_TYPE (*X)() #define LOGICAL_FUNCTION(X) F77_LOGICAL_TYPE (*X)() #define CHARACTER_FUNCTION(X) F77_CHARACTER_TYPE (*X)() #define BYTE_FUNCTION(X) F77_BYTE_TYPE (*X)() #define WORD_FUNCTION(X) F77_WORD_TYPE (*X)() #define UBYTE_FUNCTION(X) F77_UBYTE_TYPE (*X)() #define UWORD_FUNCTION(X) F77_UWORD_TYPE (*X)() #define POINTER_FUNCTION(X) F77_POINTER_TYPE (*X)() /* Array arguments. */ #define INTEGER_ARRAY(X) F77_INTEGER_TYPE *CNF_CONST X #define REAL_ARRAY(X) F77_REAL_TYPE *CNF_CONST X #define DOUBLE_ARRAY(X) F77_DOUBLE_TYPE *CNF_CONST X #define LOGICAL_ARRAY(X) F77_LOGICAL_TYPE *CNF_CONST X #define BYTE_ARRAY(X) F77_BYTE_TYPE *CNF_CONST X #define WORD_ARRAY(X) F77_WORD_TYPE *CNF_CONST X #define UBYTE_ARRAY(X) F77_UBYTE_TYPE *CNF_CONST X #define UWORD_ARRAY(X) F77_UWORD_TYPE *CNF_CONST X #define POINTER_ARRAY(X) F77_POINTER_TYPE *CNF_CONST X /* Macros to handle character arguments. */ /* Character arguments can be passed in many ways. The purpose of these */ /* macros and the GENPTR_CHARACTER macro (defined in the next section) is */ /* to generate a pointer to a character variable called ARG and an integer */ /* ARG_length containing the length of ARG. If these two variables are */ /* available directly from the argument list of the routine, then the */ /* GENPTR_CHARACTER macro is null, otherwise it works on intermediate */ /* variables. */ #define CHARACTER(X) F77_CHARACTER_TYPE *CNF_CONST X #define TRAIL(X) ,@TRAIL_TYPE@ X ## _length #define CHARACTER_ARRAY(X) F77_CHARACTER_TYPE *CNF_CONST X /* --- Getting Pointers to Arguments --- */ /* Macros that ensure that a pointer to each argument is available for the */ /* programmer to use. Usually this means that these macros are null. On */ /* VMS, a pointer to a character variable has to be generated. If a */ /* particular machine were to pass arguments by reference, rather than by */ /* value, then these macros would construct the appropriate pointers. */ #define GENPTR_INTEGER(X) #define GENPTR_REAL(X) #define GENPTR_DOUBLE(X) #define GENPTR_CHARACTER(X) #define GENPTR_LOGICAL(X) #define GENPTR_BYTE(X) #define GENPTR_WORD(X) #define GENPTR_UBYTE(X) #define GENPTR_UWORD(X) #define GENPTR_POINTER(X) #define GENPTR_INTEGER_ARRAY(X) #define GENPTR_REAL_ARRAY(X) #define GENPTR_DOUBLE_ARRAY(X) #define GENPTR_CHARACTER_ARRAY(X) #define GENPTR_LOGICAL_ARRAY(X) #define GENPTR_BYTE_ARRAY(X) #define GENPTR_WORD_ARRAY(X) #define GENPTR_UBYTE_ARRAY(X) #define GENPTR_UWORD_ARRAY(X) #define GENPTR_POINTER_ARRAY(X) #define GENPTR_SUBROUTINE(X) #define GENPTR_INTEGER_FUNCTION(X) #define GENPTR_REAL_FUNCTION(X) #define GENPTR_DOUBLE_FUNCTION(X) #define GENPTR_CHARACTER_FUNCTION(X) #define GENPTR_LOGICAL_FUNCTION(X) #define GENPTR_BYTE_FUNCTION(X) #define GENPTR_WORD_FUNCTION(X) #define GENPTR_UBYTE_FUNCTION(X) #define GENPTR_UWORD_FUNCTION(X) #define GENPTR_POINTER_FUNCTION(X) /* ------------------ Calling FORTRAN from C --------------------------- */ /* --- Declare variables --- */ #define DECLARE_INTEGER(X) F77_INTEGER_TYPE X #define DECLARE_REAL(X) F77_REAL_TYPE X #define DECLARE_DOUBLE(X) F77_DOUBLE_TYPE X #define DECLARE_LOGICAL(X) F77_LOGICAL_TYPE X #define DECLARE_BYTE(X) F77_BYTE_TYPE X #define DECLARE_WORD(X) F77_WORD_TYPE X #define DECLARE_UBYTE(X) F77_UBYTE_TYPE X #define DECLARE_UWORD(X) F77_UWORD_TYPE X #define DECLARE_POINTER(X) F77_POINTER_TYPE X #define DECLARE_CHARACTER(X,L) F77_CHARACTER_TYPE X[L]; \ const int X##_length = L /* --- Declare arrays --- */ #define DECLARE_INTEGER_ARRAY(X,D) F77_INTEGER_TYPE X[D] #define DECLARE_REAL_ARRAY(X,D) F77_REAL_TYPE X[D] #define DECLARE_DOUBLE_ARRAY(X,D) F77_DOUBLE_TYPE X[D] #define DECLARE_LOGICAL_ARRAY(X,D) F77_LOGICAL_TYPE X[D] #define DECLARE_BYTE_ARRAY(X,D) F77_BYTE_TYPE X[D] #define DECLARE_WORD_ARRAY(X,D) F77_WORD_TYPE X[D] #define DECLARE_UBYTE_ARRAY(X,D) F77_UBYTE_TYPE X[D] #define DECLARE_UWORD_ARRAY(X,D) F77_UWORD_TYPE X[D] #define DECLARE_POINTER_ARRAY(X,D) F77_POINTER_TYPE X[D] #define DECLARE_CHARACTER_ARRAY(X,L,D) F77_CHARACTER_TYPE X[D][L]; \ const int X##_length = L /* --- Declare and construct dynamic CHARACTER arguments --- */ #define DECLARE_CHARACTER_DYN(X) F77_CHARACTER_TYPE *X = NULL;\ int X##_length = 0 #define F77_CREATE_CHARACTER(X,L) X=cnfCref(L);\ X##_length = (L>0?L:1) /* Declare Dynamic Fortran arrays */ #define DECLARE_INTEGER_ARRAY_DYN(X) F77_INTEGER_TYPE *X = NULL #define DECLARE_REAL_ARRAY_DYN(X) F77_REAL_TYPE *X = NULL #define DECLARE_DOUBLE_ARRAY_DYN(X) F77_DOUBLE_TYPE *X = NULL #define DECLARE_LOGICAL_ARRAY_DYN(X) F77_LOGICAL_TYPE *X = NULL #define DECLARE_BYTE_ARRAY_DYN(X) F77_BYTE_TYPE *X = NULL #define DECLARE_WORD_ARRAY_DYN(X) F77_WORD_TYPE *X = NULL #define DECLARE_UBYTE_ARRAY_DYN(X) F77_UBYTE_TYPE *X = NULL #define DECLARE_UWORD_ARRAY_DYN(X) F77_UWORD_TYPE *X = NULL #define DECLARE_POINTER_ARRAY_DYN(X) F77_POINTER_TYPE *X = NULL #define DECLARE_CHARACTER_ARRAY_DYN(X) F77_CHARACTER_TYPE *X = NULL;\ int X##_length = 0 /* Create arrays dynamic Fortran arrays for those types which require */ /* Separate space for Fortran and C arrays */ /* Character and logical are already defined */ /* For most types there is nothing to do */ #define F77_CREATE_CHARACTER_ARRAY(X,L,N) \ {int f77dims[1];f77dims[0]=N;X=cnfCrefa(L,1,f77dims);X##_length=L;} #define F77_CREATE_CHARACTER_ARRAY_M(X,L,N,D) X=cnfCrefa(L,N,D);\ X##_length = L #define F77_CREATE_LOGICAL_ARRAY(X,N) \ {int f77dims[1];f77dims[0]=N;X=cnfCrela(1,f77dims);} #define F77_CREATE_LOGICAL_ARRAY_M(X,N,D) X=cnfCrela(N,D) #define F77_CREATE_INTEGER_ARRAY(X,N) #define F77_CREATE_REAL_ARRAY(X,N) #define F77_CREATE_DOUBLE_ARRAY(X,N) #define F77_CREATE_BYTE_ARRAY(X,N) #define F77_CREATE_UBYTE_ARRAY(X,N) #define F77_CREATE_WORD_ARRAY(X,N) #define F77_CREATE_UWORD_ARRAY(X,N) #define F77_CREATE_POINTER_ARRAY(X,N)\ X=(F77_POINTER_TYPE *) malloc(N*sizeof(F77_POINTER_TYPE)) /* Associate Fortran arrays with C arrays */ /* These macros ensure that there is space somewhere for the Fortran */ /* array. They are complemetary to the CREATE_type_ARRAY macros */ #define F77_ASSOC_CHARACTER_ARRAY(F,C) #define F77_ASSOC_LOGICAL_ARRAY(F,C) #define F77_ASSOC_INTEGER_ARRAY(F,C) F=C #define F77_ASSOC_REAL_ARRAY(F,C) F=C #define F77_ASSOC_DOUBLE_ARRAY(F,C) F=C #define F77_ASSOC_BYTE_ARRAY(F,C) F=C #define F77_ASSOC_UBYTE_ARRAY(F,C) F=C #define F77_ASSOC_WORD_ARRAY(F,C) F=C #define F77_ASSOC_UWORD_ARRAY(F,C) F=C #define F77_ASSOC_POINTER_ARRAY(F,C) /* Free created dynamic arrays */ /* Character and logical are already defined */ /* For most types there is nothing to do */ #define F77_FREE_INTEGER(X) #define F77_FREE_REAL(X) #define F77_FREE_DOUBLE(X) #define F77_FREE_BYTE(X) #define F77_FREE_UBYTE(X) #define F77_FREE_WORD(X) #define F77_FREE_UWORD(X) #define F77_FREE_POINTER(X) cnfFree((void *)X); #define F77_FREE_CHARACTER(X) cnfFreef( X ) #define F77_FREE_LOGICAL(X) cnfFree( (char *)X ) /* --- IMPORT and EXPORT of values --- */ /* Export C variables to Fortran variables */ #define F77_EXPORT_CHARACTER(C,F,L) cnfExprt(C,F,L) #define F77_EXPORT_DOUBLE(C,F) F=C #define F77_EXPORT_INTEGER(C,F) F=C #define F77_EXPORT_LOGICAL(C,F) F=C?F77_TRUE:F77_FALSE #define F77_EXPORT_REAL(C,F) F=C #define F77_EXPORT_BYTE(C,F) F=C #define F77_EXPORT_WORD(C,F) F=C #define F77_EXPORT_UBYTE(C,F) F=C #define F77_EXPORT_UWORD(C,F) F=C #define F77_EXPORT_POINTER(C,F) F=cnfFptr(C) #define F77_EXPORT_LOCATOR(C,F) cnfExpch(C,F,DAT__SZLOC) /* Allow for character strings to be NULL, protects strlen. Note this * does not allow lengths to differ. */ #define F77_CREATE_EXPORT_CHARACTER(C,F) \ if (C) { \ F77_CREATE_CHARACTER(F,strlen(C)); \ F77_EXPORT_CHARACTER(C,F,F##_length); \ } else { \ F77_CREATE_CHARACTER(F,1); \ F77_EXPORT_CHARACTER(" ",F,F##_length); \ } /* Export C arrays to Fortran */ /* Arrays are assumed to be 1-d so just the number of elements is given */ /* This may be OK for n-d arrays also */ /* CHARACTER arrays may be represented in C as arrays of arrays of char or */ /* as arrays of pointers to char (the _P variant) */ #define F77_EXPORT_CHARACTER_ARRAY(C,LC,F,LF,N) \ {int f77dims[1];f77dims[0]=N;cnfExprta(C,LC,F,LF,1,f77dims);} #define F77_EXPORT_CHARACTER_ARRAY_P(C,F,LF,N) \ {int f77dims[1];f77dims[0]=N;cnfExprtap(C,F,LF,1,f77dims);} #define F77_EXPORT_DOUBLE_ARRAY(C,F,N) F=(F77_DOUBLE_TYPE *)C #define F77_EXPORT_INTEGER_ARRAY(C,F,N) F=(F77_INTEGER_TYPE *)C #define F77_EXPORT_LOGICAL_ARRAY(C,F,N) \ {int f77dims[1];f77dims[0]=N;cnfExpla(C,F,1,f77dims);} #define F77_EXPORT_REAL_ARRAY(C,F,N) F=(F77_REAL_TYPE *)C #define F77_EXPORT_BYTE_ARRAY(C,F,N) F=(F77_BYTE_TYPE *)C #define F77_EXPORT_WORD_ARRAY(C,F,N) F=(F77_WORD_TYPE *)C #define F77_EXPORT_UBYTE_ARRAY(C,F,N) F=(F77_UBYTE_TYPE *)C #define F77_EXPORT_UWORD_ARRAY(C,F,N) F=(F77_UWORD_TYPE * )C #define F77_EXPORT_POINTER_ARRAY(C,F,N) \ {int f77i;for (f77i=0;f77i #endif #undef F77_CHARACTER_ARG_TYPE #define F77_CHARACTER_ARG_TYPE struct dsc$descriptor_s #undef F77_CHARACTER_ARRAY_ARG_TYPE #define F77_CHARACTER_ARRAY_ARG_TYPE struct dsc$descriptor_a #undef CHARACTER #define CHARACTER(X) F77_CHARACTER_ARG_TYPE *CNF_CONST X/**/_arg #undef TRAIL #define TRAIL(X) #undef CHARACTER_ARRAY #define CHARACTER_ARRAY(X) F77_CHARACTER_ARRAY_ARG_TYPE *CNF_CONST X/**/_arg #undef GENPTR_CHARACTER #define GENPTR_CHARACTER(X) \ F77_CHARACTER_TYPE *X = X/**/_arg->dsc$a_pointer; \ int X/**/_length = X/**/_arg->dsc$w_length; #undef GENPTR_CHARACTER_ARRAY #define GENPTR_CHARACTER_ARRAY(X) GENPTR_CHARACTER(X) /* --- Logical Values --- */ #undef F77_TRUE #define F77_TRUE -1 #undef F77_ISTRUE #define F77_ISTRUE(X) ( (X)&1 ) #undef F77_ISFALSE #define F77_ISFALSE(X) ( ! ( (X)&1 ) ) /* --- Common Blocks --- */ #undef F77_BLANK_COMMON #define F77_BLANK_COMMON $BLANK /* --- Declare Variables --- */ #undef DECLARE_CHARACTER #define DECLARE_CHARACTER(X,L) \ F77_CHARACTER_TYPE X[L]; const int X/**/_length = L; \ F77_CHARACTER_ARG_TYPE X/**/_descr = \ { L, DSC$K_DTYPE_T, DSC$K_CLASS_S, X }; \ F77_CHARACTER_ARG_TYPE *X/**/_arg = &X/**/_descr #undef DECLARE_CHARACTER_ARRAY #define DECLARE_CHARACTER_ARRAY(X,L,D) \ F77_CHARACTER_TYPE X[D][L]; const int X/**/_length = L; \ F77_CHARACTER_ARRAY_ARG_TYPE X/**/_descr = \ { L, DSC$K_DTYPE_T, DSC$K_CLASS_S, X }; \ F77_CHARACTER_ARRAY_ARG_TYPE *X/**/_arg = &X/**/_descr /* --- The dynamic allocation of character arguments --- */ #undef DECLARE_CHARACTER_DYN #define DECLARE_CHARACTER_DYN(X) int X/**/_length;\ F77_CHARACTER_ARG_TYPE *X/**/_arg;\ F77_CHARACTER_TYPE *X #undef DECLARE_CHARACTER_ARRAY_DYN #define DECLARE_CHARACTER_ARRAY_DYN(X) int X/**/_length;\ F77_CHARACTER_ARRAY_ARG_TYPE *X/**/_arg;\ F77_CHARACTER_TYPE *X #undef F77_CREATE_CHARACTER #define F77_CREATE_CHARACTER(X,L) X/**/_arg = cnfCref(L);\ X = X/**/_arg->dsc$a_pointer; \ X/**/_length = X/**/_arg->dsc$w_length #undef F77_CREATE_CHARACTER_ARRAY #define F77_CREATE_CHARACTER_ARRAY(X,L,N) \ {int f77dims[1];f77dims[0]=N;X/**/_arg=cnfCrefa(L,1,f77dims);X/**/_length=L;} #define F77_CREATE_CHARACTER_ARRAY_M(X,L,N,D) X/**/_arg = cnfCrefa(L,N,D);\ X = X/**/_arg->dsc$a_pointer; \ X/**/_length = X/**/_arg->dsc$w_length #undef F77_FREE_CHARACTER #define F77_FREE_CHARACTER(X) cnfFreef( X/**/_arg ) /* --- Pass arguments to a FORTRAN routine --- */ #undef CHARACTER_ARG #define CHARACTER_ARG(X) X/**/_arg #undef CHARACTER_ARRAY_ARG #define CHARACTER_ARRAY_ARG(X) X/**/_arg #undef TRAIL_ARG #define TRAIL_ARG(X) #endif /* VMS */ /* ----------------------------------------------------------------------- */ /*-------------------------- | DECstation Ultrix (cc) | | DECstation Ultrix (c89) | | DECstation OSF/1 | | Alpha OSF/1 | --------------------------*/ /* Do this complicated set of definitions as a single #if cannot be */ /* continued across multiple lines. */ #if defined(mips) && defined(ultrix) #define _dec_unix 1 #endif #if defined(__mips) && defined(__ultrix) #define _dec_unix 1 #endif #if defined(__mips__) && defined(__osf__) #define _dec_unix 1 #endif #if defined(__alpha) && defined(__osf__) #define _dec_unix 1 #endif #if _dec_unix /* The macros for Ultrix are the same as the standard ones except for ones */ /* dealing with logical values. The ANSI definitions work with the c89 */ /* compiler, and the non ANSI definitions work with the cc compiler. */ /* The same applies to DEC OSF/1, except that its cc compiler is ANSI */ /* compliant. */ /* --- Logical Values --- */ /* Redefine macros that evaluate to a C logical value, given a FORTRAN */ /* logical value. These definitions are only valid when used with the DEC */ /* FORTRAN for RISC compiler. If you are using the earlier FORTRAN for */ /* RISC compiler from MIPS, then these macros should be deleted. */ #undef F77_TRUE #define F77_TRUE -1 #undef F77_ISTRUE #define F77_ISTRUE(X) ( (X)&1 ) #undef F77_ISFALSE #define F77_ISFALSE(X) ( ! ( (X)&1 ) ) #endif /* DEC Unix */ /* *+ * Name: * cnf.h * Purpose: * Function prototypes for cnf routines * Language: * ANSI C * Type of Module: * C include file * Description: * These are the prototype definitions for the functions in the CNF * library. They are used used in mixing C and FORTRAN programs. * Copyright: * Copyright (C) 1991 Science & Engineering Research Council * Authors: * PMA: Peter Allan (Starlink, RAL) * AJC: Alan Chipperfield (Starlink, RAL) * {enter_new_authors_here} * History: * 23-MAY-1991 (PMA): * Original version. * 12-JAN-1996 (AJC): * Add cnf_cref and cnf_freef * 14-JUN-1996 (AJC): * Add cnf_crefa, imprta, exprta * crela, impla, expla * 18-JUL-1996 (AJC): * Add impch and expch * 17-MAR-1998 (AJC): * Add imprtap and exprtap * {enter_changes_here} * Bugs: * {note_any_bugs_here} *- ------------------------------------------------------------------------------ */ void cnfInitRTL( int, char** ); void *cnfCalloc( size_t, size_t ); void cnfCopyf( const char *source_f, int source_len, char *dest_f, int dest_len ); void *cnfCptr( F77_POINTER_TYPE ); char *cnfCreat( int length ); F77_CHARACTER_ARG_TYPE *cnfCref( int length ); F77_CHARACTER_ARG_TYPE *cnfCrefa( int length, int ndims, const int *dims ); char *cnfCreib( const char *source_f, int source_len ); char *cnfCreim( const char *source_f, int source_len ); F77_LOGICAL_TYPE *cnfCrela( int ndims, const int *dims ); void cnfExpch( const char *source_c, char *dest_f, int nchars ); void cnfExpla( const int *source_c, F77_LOGICAL_TYPE *dest_f, int ndims, const int *dims ); void cnfExpn( const char *source_c, int max, char *dest_f, int dest_len ); void cnfExprt( const char *source_c, char *dest_f, int dest_len ); void cnfExprta( const char *source_c, int source_len, char *dest_f, int dest_len, int ndims, const int *dims ); void cnfExprtap( char *const *source_c, char *dest_f, int dest_len, int ndims, const int *dims ); F77_POINTER_TYPE cnfFptr( void *cpointer ); void cnfFree( void * ); void cnfFreef( F77_CHARACTER_ARG_TYPE *temp ); void cnfImpb( const char *source_f, int source_len, char *dest_c ); void cnfImpbn( const char *source_f, int source_len, int max, char *dest_c ); void cnfImpch( const char *source_f, int nchars, char *dest_c ); void cnfImpla( const F77_LOGICAL_TYPE *source_f, int *dest_c, int ndims, const int *dims ); void cnfImpn( const char *source_f, int source_len, int max, char *dest_c ); void cnfImprt( const char *source_f, int source_len, char *dest_c ); void cnfImprta( const char *source_f, int source_len, char *dest_c, int dest_len, int ndims, const int *dims ); void cnfImprtap( const char *source_f, int source_len, char *const *dest_c, int dest_len, int ndims, const int *dims ); int cnfLenc( const char *source_c ); int cnfLenf( const char *source_f, int source_len ); void *cnfMalloc( size_t ); void *cnfRealloc( void *, size_t ); int cnfRegp( void * ); void cnfUregp( void * ); void cnfLock( void ); void cnfUnlock( void ); #endif #ifndef CNF_OLD_DEFINED #define CNF_OLD_DEFINED /* Define old names to be new names */ #define cnf_calloc cnfCalloc #define cnf_copyf cnfCopyf #define cnf_cptr cnfCptr #define cnf_creat cnfCreat #define cnf_cref cnfCref #define cnf_crefa cnfCrefa #define cnf_creib cnfCreib #define cnf_creim cnfCreim #define cnf_crela cnfCrela #define cnf_expch cnfExpch #define cnf_expla cnfExpla #define cnf_expn cnfExpn #define cnf_exprt cnfExprt #define cnf_exprta cnfExprta #define cnf_exprtap cnfExprtap #define cnf_fptr cnfFptr #define cnf_free cnfFree #define cnf_freef cnfFreef #define cnf_impb cnfImpb #define cnf_impbn cnfImpbn #define cnf_impch cnfImpch #define cnf_impla cnfImpla #define cnf_impn cnfImpn #define cnf_imprt cnfImprt #define cnf_imprta cnfImprta #define cnf_imprtap cnfImprtap #define cnf_lenc cnfLenc #define cnf_lenf cnfLenf #define cnf_malloc cnfMalloc #define cnf_regp cnfRegp #define cnf_uregp cnfUregp #endif /* CNF_MACROS */ ./ast-7.3.3/fpermmap.c0000644000175000017500000000663412262533650013126 0ustar olesoles/* *+ * Name: * fpermmap.c * Purpose: * Define a FORTRAN 77 interface to the AST PermMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the PermMap class. * Routines Defined: * AST_ISAPERMMAP * AST_PERMMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 26-SEP-1996 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "permmap.h" /* C interface to the PermMap class */ F77_LOGICAL_FUNCTION(ast_isapermmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAPERMMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAPermMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_permmap)( INTEGER(NIN), INTEGER_ARRAY(INPERM), INTEGER(NOUT), INTEGER_ARRAY(OUTPERM), DOUBLE_ARRAY(CONSTANT), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NIN) GENPTR_INTEGER_ARRAY(INPERM) GENPTR_INTEGER(NOUT) GENPTR_INTEGER_ARRAY(OUTPERM) GENPTR_DOUBLE_ARRAY(CONSTANT) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_PERMMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astPermMap( *NIN, INPERM, *NOUT, OUTPERM, CONSTANT, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/object.h.in0000644000175000017500000017126112262533650013176 0ustar olesoles#if !defined( OBJECT_INCLUDED ) /* Include this file only once */ #define OBJECT_INCLUDED /* *++ * Name: * object.h * Type: * C include file. * Purpose: * Define the interface to the Object class. * Invocation: * #include "object.h" * Description: * This include file defines the interface to the Object class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * The Object class is the base class from which all other classes * in the AST library are derived. This class provides all the * basic Object behaviour and Object manipulation facilities * required throughout the library. There is no Object constructor, * however, as Objects on their own are not of much use. * Inheritance: * The Object base class does not inherit from any other class. * Attributes Over-Ridden: * None. * New Attributes Defined: * Class (string) * This is a read-only attribute containing the name of the * class to which an Object belongs. * ID (string) * An identification string which may be used to identify the * Object (e.g.) in debugging output, or when stored in an * external medium such as a data file. There is no restriction * on the string's contents. The default is an empty string. * Ident (string) * Like ID, this is an identification string which may be used * to identify the Object. Unlike ID, Ident is transferred when an * Object is copied. * UseDefs (int) * Should default values be used for unset attributes? * Nobject (integer) * This is a read-only attribute which gives the total number of * Objects currently in existence in the same class as the * Object given. It does not include Objects which belong to * derived (more specialised) classes. This value is mainly * intended for debugging, as it can be used to show whether * Objects which should have been deleted have, in fact, been * deleted. * ObjSize (int) * The in-memory size of the Object in bytes. * RefCount (integer) * This is a read-only Attribute which gives the "reference * count" (the number of active pointers) associated with an * Object. It is modified whenever pointers are created or * annulled (by astClone or astAnnul/astEnd for example) and * includes the initial pointer issued when the Object was * created. If the reference count for an Object falls to zero * as the result of annulling a pointer to it, then the Object * will be deleted. * Methods Over-Ridden: * None. * New Methods Defined: * Public: * astAnnul * Annul a pointer to an Object. * astClear * Clear attribute values for an Object. * astClone * Clone a pointer to an Object. * astCopy * Copy an Object. * astDelete * Delete an Object. * astExempt * Exempt an Object pointer from AST context handling * astExport * Export an Object pointer to an outer context. * astGet, where = C, D, F, I, L * Get an attribute value for an Object. * astImport * Import an Object pointer into the current context. * astSame * Return true if two pointers refer to the same object. * astSet * Set attribute values for an Object. * astSet, where = C, D, F, I, L * Set an attribute value for an Object. * astShow * Display a textual representation of an Object on standard output. * astTest * Test if an attribute value is set for an Object. * astTune * Get or set the value of a global AST tuning parameter. * * Protected: * astAnnulId * Annul an external ID for an Object (for use from protected code * which must handle external IDs). * astClearAttrib * Clear the value of a specified attribute for an Object. * astClearID * Clear the value of the ID attribute for an Object. * astClearIdent * Clear the value of the Ident attribute for an Object. * astCast * Return a deep copy of an object, cast into an instance of a * parent class. * astDump * Write an Object to a Channel. * astEqual * Are two Objects equivalent? * astGetAttrib * Get the value of a specified attribute for an Object. * astGetClass (deprecated synonym astClass) * Obtain the value of the Class attribute for an Object. * astGetID * Obtain the value of the ID attribute for an Object. * astGetIdent * Obtain the value of the Ident attribute for an Object. * astGetNobject * Obtain the value of the Nobject attribute for an Object. * astGetRefCount * Obtain the value of the RefCount attribute for an Object. * astSetAttrib * Set the value of a specified attribute for an Object. * astSetCopy * Declare a copy constructor for an Object. * astSetDelete * Declare a destructor for an Object. * astSetDump * Declare a dump function for an Object. * astSetVtab * Chaneg the virtual function table associated with an Object. * astSetID * Set the value of the ID attribute for an Object. * astSetIdent * Set the value of the Ident attribute for an Object. * astTestAttrib * Test if a specified attribute value is set for an Object. * astTestID * Test whether the ID attribute for an Object is set. * astTestIdent * Test whether the Ident attribute for an Object is set. * astVSet * Set values for an Object's attributes. * Other Class Functions: * Public: * astBegin * Begin a new AST context. * astEnd * End an AST context. * astIsAObject * Test class membership. * astVersion * Returns the AST library version number. * astEscapes * Remove escape sequences from returned text strings? * astP2I * Retrieve an int from a pointer. * astI2P * Pack an int into a pointer. * * Protected: * astCheckObject * Validate class membership. * astInitObject * Initialise an Object. * astInitObjectVtab * Initialise the virtual function table for the Object class. * astLoadObject * Load an Object. * astMakeId * Issue an identifier for an Object. * astMakePointer * Obtain a true C pointer from an Object identifier. * Macros: * Public: * AST__NULL * Null Object pointer value. * AST__VMAJOR * The AST library major version number. * AST__VMINOR * The AST library minor version number. * AST__RELEASE * The AST library release number. * * Protected: * astEQUAL * Compare two doubles for equality. * astMAX * Return maximum of two values. * astMIN * Return minimum of two values. * astMAKE_CHECK * Implement the astCheck_ function for a class. * astMAKE_CLEAR * Implement a method to clear an attribute value for a class. * astMAKE_GET * Implement a method to get an attribute value for a class. * astMAKE_ISA * Implement the astIsA_ function for a class. * astMAKE_SET * Implement a method to set an attribute value for a class. * astMAKE_TEST * Implement a method to test if an attribute has been set for a * class. * astMEMBER * Locate a member function. * Type Definitions: * Public: * AstObject * Object type. * * Protected: * AstObjectVtab * Object virtual function table type. * Feature Test Macros: * AST_CHECK_CLASS * If the AST_CHECK_CLASS macro is defined, then Object class * checking is enabled for all internal function invocations * within the AST library. Otherwise, this checking is * omitted. This macro should normally be defined as a compiler * option during library development and debugging, but left * undefined for software releases, so as to improve * peformance. Class checking by the AST public interface is not * affected by this macro. * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * astFORTRAN77 * If the astFORTRAN77 macro is defined, reporting of error * context information is suppressed. This is necessary when * implementing foreign language interfaces to the AST library, as * otherwise the file names and line numbers given would refer * to the interface implementation rather than the user's own * code. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2010 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 30-JAN-1996 (RFWS): * Original version. * 19-APR-1996 (RFWS): * Added macros for implementing attribute access methods. * 3-JUL-1996 (RFWS): * Added new definitions to support the external interface. * 10-SEP-1996 (RFWS): * Added loader and related facilities. * 30-MAY-1997 (RFWS): * Add the ID attribute. * 14-JUL-1997 (RFWS): * Add astExempt function. * 20-JAN-1998 (RFWS): * Make the astClear and astVSet methods virtual. * 15-SEP-1999 (RFWS): * Made the astAnnulId function accessible to protected code. * 3-APR-2001 (DSB): * Added Ident attribute. * 8-JAN-2003 (DSB): * Added protected astInitObjectVtab method. * 30-APR-2003 (DSB): * Added macros AST__VMAJOR, AST__VMINOR and AST__RELEASE. * Added astVersion function. * 7-FEB-2004 (DSB): * Added astEscapes function. * 11-MAR-2005 (DSB): * Added UseDefs attribute. * 7-FEB-2006 (DSB): * Added astTune function. * 14-FEB-2006 (DSB): * Added ObjSize attribute. * 23-FEB-2006 (DSB): * Moved AST__TUNULL from this file to memory.h. * 10-MAY-2006 (DSB): * Added astEQUAL, astMAX and astMIN. * 26-MAY-2006 (DSB): * Make all system includes unconditional, so that makeh is not * confused when creating ast.h. * 22-JUN-2007 (DSB): * - Make astVSet return a pointer to dynamic memory holding the * expanded setting string. * - Add ast astSetVtab and astCast. * 22-APR-2008 (DSB): * Added astSame. * 7-APR-2010 (DSB): * Added astHasAttribute. *-- */ /* Include files. */ /* ============== */ /* Configuration results. */ /* ---------------------- */ #if HAVE_CONFIG_H #include #endif /* Interface definitions. */ /* ---------------------- */ #include "error.h" /* Error reporting facilities */ #include "version.h" /* Version number macros */ /* C header files. */ /* --------------- */ #include #include #include #include #if defined(THREAD_SAFE) #include #endif /* Macros. */ /* ======= */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Set to "1" (yes) or "0" (no) to indicate if AST was build with threads support. */ #define AST__THREADSAFE @THREADS@ #if defined(astCLASS ) #define AST__GETATTRIB_BUFF_LEN 50 /* Length of string returned by GetAttrib. */ #define AST__ASTGETC_MAX_STRINGS 50 /* Number of string values to buffer within astGetC */ /* Values supplied to astManageLock */ #define AST__LOCK 1 /* Lock the object */ #define AST__UNLOCK 2 /* Unlock the object */ #define AST__CHECKLOCK 3 /* Check if the object is locked */ /* Values returned by astThread */ #define AST__UNLOCKED 1 /* Object is unlocked */ #define AST__RUNNING 2 /* Object is locked by the running thread */ #define AST__OTHER 3 /* Object is locked by another thread */ #endif /* Value that indicates that two classes are not in direct line from each other. */ #if defined(astCLASS ) #define AST__COUSIN -1000000 #endif /* *+ * Name: * astINVOKE * Type: * Protected macro. * Purpose: * Invoke an AST function. * Synopsis: * #include "object.h" * astINVOKE(rettype,function) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an invocation of an AST function, together * with any additional actions required to support it. The actual * expansion depends on whether the macro is expanded in internal * code (astCLASS defined) or external code (astCLASS undefined) * and it therefore hides the differences between these two * interfaces. * Parameters: * rettype * A character to indicate the type of result returned by the function: * * V * The function returns a value (including void or a pointer * value, but excluding an Object pointer). astINVOKE will * return the value unchanged. * O * The function returns an Object pointer. astINVOKE will * convert it to an Object identifier if necessary. * F * The function returns a function pointer. astINVOKE will * return it unchanged. This is typically used when the * function has a variable argument list. In this case the * function name is passed to astINVOKE without its argument * list and a pointer to the function is returned which can * then be supplied with an argument list. This avoids the * need to define a macro with a variable number of arguments * (which isn't allowed). * function * A normal invocation of the function returning the required * result. In the case of a variable argument list, the * argument list should be omitted so that the function is not * invoked but a function pointer is returned that may then be * used to invoke it. * Examples: * #define astGetNobject(this) \ * astINVOKE(V,astGetNobject_(astCheckObject(this))) * Defines a macro to invoke the astGetNobject_ function which * returns an int. * #define astClone(this) \ * astINVOKE(O,astClone_(astCheckObject(this))) * Defines a macro to invoke the astClone_ function which * returns an Object pointer. * #define astSet astINVOKE(F,astSet_) * Defines a macro to invoke the astSet_ function which has a * variable argument list and returns void. The macro result is * a pointer to the astSet_ function. This function must perform * its own argument validation, as (e.g) astCheckObject cannot * be invoked on its arguments via a macro. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* Define astINVOKE, which records the current file and line number (in case of error) using astAt, and then invokes the function supplied as an argument of the astRetV_, astRetO_ or astRetF_ macro. Suppress reporting of the file and line number from internal code and from foreign language interfaces by not using astAt in these cases. */ #if defined(astCLASS) || defined(astFORTRAN77) #define astINVOKE(rettype,function) astRet##rettype##_(function) #else #define astINVOKE(rettype,function) \ astERROR_INVOKE(astRet##rettype##_(function)) #endif /* astRetF_ and astRetV_ currently do nothing. */ #define astRetF_(x) (x) #define astRetV_(x) (x) /* However, astRetO_ converts a pointer to an ID if necessary. */ #if defined(astCLASS) #define astRetO_(x) ((void *)(x)) #else #define astRetO_(x) ((void *)astMakeId_((AstObject *)(x),STATUS_PTR)) #endif /* *+ * Name: * astINVOKE_CHECK * astINVOKE_ISA * Type: * Protected macros. * Purpose: * Invoke the astCheck_ and astIsA_ functions. * Synopsis: * #include "object.h" * astINVOKE_CHECK(class,this,force) * astINVOKE_ISA(class,this) * Class Membership: * Defined by the Object class. * Description: * These macros expand to invocations of the standard * astCheck_ and astIsA_ functions for a class. * Parameters: * class * The name (not the type) of the class for which the function * is to be invoked. * this * The "this" argument (the Object pointer) to be passed to the * function. * force * Type checking takes time, and so can be disabled within the * protected context in order to save time. Setting "force" to * zero causes the astINVOKE_CHECK macro to skip the class check * in a protected context (it assumes that AST "knows what it is * doing"). Setting "force" to a non-zero value forces the class * check even in a protected context. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* For the public interface (and also internally if AST_CHECK_CLASS is defined), define astINVOKE_CHECK to invoke the astCheck function. */ #if !defined(astCLASS) || defined(AST_CHECK_CLASS) #define astINVOKE_CHECK(class,this,force) \ astCheck##class##_((Ast##class *)astEnsurePointer_(this),astGetStatusPtr) /* For the internal interface, astINVOKE_CHECK omits the astCheck function (unless AST_CHECK_CLASS is defined). */ #else #define astINVOKE_CHECK(class,this,force) ( (force) ? \ ( astCheck##class##_((Ast##class *)astEnsurePointer_(this),astGetStatusPtr) ) : \ ( (Ast##class *) astEnsurePointer_(this) ) ) #endif /* Define astINVOKE_ISA to invoke the astIsA function. */ #if defined(astCLASS) /* Protected */ #define astINVOKE_ISA(class,this) \ astIsA##class##_((const Ast##class *)(this),status) #else /* Public */ #define astINVOKE_ISA(class,this) \ astINVOKE(V,astIsA##class##_((const Ast##class *)astEnsurePointer_(this),astGetStatusPtr)) #endif /* The astEnsurePointer_ macro ensures a true C pointer, converting from an ID if necessary. */ #if defined(astCLASS) /* Protected */ #define astEnsurePointer_(x) ((void *)(x)) #else /* Public */ #define astEnsurePointer_(x) ((void *)astCheckLock_(astMakePointer_((AstObject *)(x),STATUS_PTR),STATUS_PTR)) #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_CHECK * Type: * Protected macro. * Purpose: * Implement the astCheck_ function for a class. * Synopsis: * #include "object.h" * astMAKE_CHECK(class) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of the public astCheck_ * function (q.v.) which validates membership of a specified class. * Parameters: * class * The name (not the type) of the class whose membership is to be * validated. * Notes: * - This macro is provided so that class definitions can easiy * implement the astCheck_ function, which is essentially the same * for each class apart for a change of name. * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ #ifndef MEM_DEBUG /* Define the macro. */ #define astMAKE_CHECK(class) \ \ /* Declare the function (see the object.c file for a prologue). */ \ Ast##class *astCheck##class##_( Ast##class *this, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return this; \ \ /* Check if the object is a class member. */ \ if ( !astIsA##class( this ) ) { \ \ /* If not, but the pointer was valid (which means it identifies an Object \ of some sort), then report more information about why this Object is \ unsuitable. */ \ if ( astOK ) { \ astError( AST__OBJIN, "Pointer to " #class " required, but pointer " \ "to %s given.", status, astGetClass( this ) ); \ } \ } \ \ /* Return the pointer value supplied. */ \ return this; \ } /* Define the macro with memory debugging facilities. */ #else #define astMAKE_CHECK(class) \ \ /* Declare the function (see the object.c file for a prologue). */ \ Ast##class *astCheck##class##_( Ast##class *this, int *status ) { \ \ char buf[100]; \ \ /* Check the inherited error status. */ \ if ( !astOK ) return this; \ \ /* Check if the object is a class member. */ \ if ( !astIsA##class( this ) ) { \ \ /* If not, but the pointer was valid (which means it identifies an Object \ of some sort), then report more information about why this Object is \ unsuitable. */ \ if ( astOK ) { \ astError( AST__OBJIN, "Pointer to " #class " required, but pointer " \ "to %s given.", status, astGetClass( this ) ); \ }\ \ } else { \ \ /* Call the astMemoryUse function to report it if the memory block is \ being watched. */ \ sprintf( buf, "checked (refcnt: %d)", astGetRefCount_( (AstObject *) this, status ) ); \ astMemoryUse( this, buf ); \ } \ \ /* Return the pointer value supplied. */ \ return this; \ } #endif #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_CLEAR * Purpose: * Implement a method to clear an attribute value for a class. * Type: * Protected macro. * Synopsis: * #include "object.h" * astMAKE_CLEAR(class,attribute,component,assign) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Clear( Ast *this ) * * and an external interface function of the form: * * void astClear_( Ast *this ) * * which implement a method for clearing a specified attribute value for * a class. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attribute * The name of the attribute to be cleared, as it appears in the function * name (e.g. Label in "astClearLabel"). * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to assign to the component * to clear its value. * Examples: * astMAKE_CLEAR(MyStuff,Flag,flag,-1) * Implements the astClearFlag method for the MyStuff class which * operates by setting the "flag" structure component to -1 to indicate * that it has no value. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define astMAKE_CLEAR(class,attribute,component,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Clear##attribute( Ast##class *this, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return; \ \ /* Assign the "clear" value. */ \ this->component = (assign); \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astClear##attribute##_( Ast##class *this, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,class,Clear##attribute))( this, status ); \ } #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_GET * Purpose: * Implement a method to get an attribute value for a class. * Type: * Protected macro. * Synopsis: * #include "object.h" * astMAKE_GET(class,attribute,type,bad_value,assign) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( Ast *this ) * * and an external interface function of the form: * * astGet_( Ast *this ) * * which implement a method for getting a specified attribute value for a * class. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attribute * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. Label in "astGetLabel"). * type * The C type of the attribute. * bad_value * A constant value to return if the inherited error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. * Examples: * astMAKE_GET(MyStuff,Flag,int,0,( this->flag == 1 )) * Implements the astGetFlag method for the MyStuff class which operates * by examining the integer "flag" structure component and comparing it * with the value 1 to see if it is set. A value of 0 is returned if the * method fails to complete successfully. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define astMAKE_GET(class,attribute,type,bad_value,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type Get##attribute( Ast##class *this, int *status ) { \ type result; /* Result to be returned */ \ \ /* Check the inherited error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Assign the result value. */ \ result = (assign); \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ type astGet##attribute##_( Ast##class *this, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,class,Get##attribute))( this, status ); \ } #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_ISA * Type: * Protected macro. * Purpose: * Implement the astIsA_ function for a class. * Synopsis: * #include "object.h" * astMAKE_ISA(class,parent) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of the public * astIsA_ function (q.v.) which checks membership of a * specified class. * Parameters: * class * The name (not the type) of the class whose membership is to be * tested. * parent * The name of the parent class. * Notes: * - This macro is provided so that class definitions can easiy * implement the astIsA_ function, which is essentially the * same for each class apart for a change of name. * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* Define the macro. */ #define astMAKE_ISA(class,parent) \ \ /* Declare the function (see the object.c file for a prologue). */ \ int astIsA##class##_( const Ast##class *this, int *status ) { \ \ /* Local Variables: */ \ int isa = 0; /* Is object a member? */ \ \ /* To test if the object is correctly constructed, we first test if it is a \ member of the parent class. This improves the security of the test by \ checking the object structure from the base Object class downwards \ (without this, the "magic numbers" that identify classes might be \ encountered by accident or we might address parts of the Object which \ don't exist). */ \ if ( astIsA##parent( this ) ) { \ \ /* Obtain the Object's size and check it is adequate for an object of the \ proposed type (this avoids any attempt to access derived class data that \ doesn't exist and therefore lies outside the memory allocated for the \ object). */ \ if ( ( (AstObject *) this )->size >= sizeof( Ast##class ) ) { \ \ /* If OK, see whether the check component in the object's virtual function \ table matches the expected "magic" value. */ \ isa = ( *astMEMBER(this,class,id.check) == &class_check ); \ } \ } \ \ /* Return the result. */ \ return isa; \ } #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_SET * Purpose: * Implement a method to set an attribute value for a class. * Type: * Protected macro. * Synopsis: * #include "object.h" * astMAKE_SET(class,attribute,type,component,assign) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( Ast *this, value ) * * and an external interface function of the form: * * void astSet_( Ast *this, value ) * * which implement a method for setting a specified attribute value for a * class. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attribute * The name of the attribute to be set, as it appears in the function * name (e.g. Label in "astSetLabel"). * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * Examples: * astMAKE_SET(MyStuff,Flag,int,flag,( value != 0 )) * Implements the astSetFlag method for the MyStuff class which operates * by setting the "flag" structure component to 0 or 1 depending on * whether the "value" parameter is non-zero or not. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* Define the macro. */ #define astMAKE_SET(class,attribute,type,component,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Set##attribute( Ast##class *this, type value, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return; \ \ /* Store the new value in the structure component. */ \ this->component = (assign); \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astSet##attribute##_( Ast##class *this, type value, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,class,Set##attribute))( this, value, status ); \ } #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMAKE_TEST * Purpose: * Implement a method to test if an attribute has been set for a class. * Type: * Protected macro. * Synopsis: * #include "object.h" * astMAKE_TEST(class,attribute,assign) * Class Membership: * Defined by the Object class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static int Test( Ast *this ) * * and an external interface function of the form: * * int astTest_( Ast *this ) * * which implement a method for testing if a specified attribute has been * set for a class. * Parameters: * class * The name (not the type) of the class to which the attribute belongs. * attribute * The name of the attribute to be tested, as it appears in the function * name (e.g. Label in "astTestLabel"). * assign * An expression that evaluates to 0 or 1, to be used as the returned * value. * Examples: * astMAKE_TEST(MyStuff,Flag,( this->flag != -1 )) * Implements the astTestFlag method for the MyStuff class which operates * by testing the "flag" structure component to see if it is set to a * value other than -1. * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define astMAKE_TEST(class,attribute,assign) \ \ /* Private member function. */ \ /* ------------------------ */ \ static int Test##attribute( Ast##class *this, int *status ) { \ int result; /* Value to return */ \ \ /* Check the inherited error status. */ \ if ( !astOK ) return 0; \ \ /* Assign the result value. */ \ result = (assign); \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ int astTest##attribute##_( Ast##class *this, int *status ) { \ \ /* Check the inherited error status. */ \ if ( !astOK ) return 0; \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,class,Test##attribute))( this, status ); \ } #endif #if defined(astCLASS) /* Protected */ /* *+ * Name: * astMEMBER * Purpose: * Locate a member function. * Type: * Protected macro. * Synopsis: * #include "object.h" * astMEMBER(this,class,method) * Class Membership: * Defined by the Object class. * Description: * This macro evaluates to the address where the pointer to a * specified Object member function is stored. Typically, this will * be used to obtain a pointer to the member function so that it * can be invoked. It may also be used to assign a new function * pointer so that a derived class can re-define a virtual function * and hence over-ride an inherited method. * Parameters: * this * Pointer to an Object belonging to the class for which the * virtual function is required. This must either be the class * that originally defined the method, or one derived from it. * class * Name of the class that originally defined the method. This * may differ from (i.e. be an ancestor of) the class to which * "this" belongs. * method * Name of the method whose member function is to be located. * Returned Value: * The address where the member function pointer is stored (the * type of the result is determined by the type of the member * function itself). * Examples: * astMEMBER(this,Gnome,astFish) * Returns the address where the pointer to the function that * implements the astFish method for the "this" object is * stored. The Gnome class should be where the astFish method * was first defined (i.e. from where it was inherited by * "this"). * (**astMEMBER(this,Gnome,astFish))( this, arg1, arg2 ); * Invokes the virtual function that implements the astFish * method for object "this" and passes it additional arguments * "arg2" and "arg2". Again, Gnome should be the class that * originally defined the astFish method. * *astMEMBER(this,Gnome,astFish) = myFish; * Stores a pointer to the myFish function so that it replaces * the virtual function that previously implemented the astFish * method for the "this" object. Note that all objects in the * same class as "this" are affected, but objects in class * "class" are not affected (unless it happens to be the class * to which "this" belongs). * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* A subsiduary macro that returns a pointer to the vtab of an object, cast to an AstObjectVtab. */ #define astVTAB(this) (((AstObject*)(this))->vtab) /* Define the macro. This functions by (a) casting the Object pointer to type (AstObject *) and locating the Object's virtual function table (b) casting the table pointer to the correct type (AstClassVtab *) for the class in which the method pointer resides, (c) locating the component holding the member function pointer, and (d) taking its address. */ #define astMEMBER(this,class,method) \ (&((Ast##class##Vtab*)astVTAB(this))->method) #endif /* *+ * Name: * astPROTO_CHECK * astPROTO_ISA * Type: * Protected macros. * Purpose: * Prototype the astCheck_ and astIsA_ functions. * Synopsis: * #include "object.h" * astPROTO_CHECK(class) * astPROTO_ISA(class) * Class Membership: * Defined by the Object class. * Description: * These macros expands to function prototypes for the * astCheck_ and astIsA_ functions (q.v.) which * validate and test for membership of a specified class. * Parameters: * class * The name (not the type) of the class whose membership is to * be validated. * Notes: * - To avoid problems with some compilers, you should not leave * any white space around the macro arguments. *- */ /* Define the macros. */ #define astPROTO_CHECK(class) Ast##class *astCheck##class##_( Ast##class *, int * ); #define astPROTO_ISA(class) int astIsA##class##_( const Ast##class *, int * ); /* Macros which return the maximum and minimum of two values. */ #define astMAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define astMIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Check for equality of floating point values. We cannot compare bad values directly because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define astEQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*astMAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* AST__NULL. */ /* ---------- */ /* Define the AST__NULL macro, which evaluates to a null Object pointer. */ #define AST__NULL (astI2P(0)) #if defined(astCLASS) /* Protected */ /* Test the validy of an attribute value */ /* ------------------------------------- */ /* If the set attribute value is invalid, clear it. These macros should be used in a context in which error reporting has been deferred by calling astReporting( 0 ). */ #define astCLEAN_ATTRIB(attr) \ if( astTest##attr(this) ) { \ astSet##attr( this, astGet##attr( this ) ); \ if( !astOK ) { \ astClearStatus; \ astClear##attr( this ); \ } \ } #define astCLEAN_INDEXED_ATTRIB(attr,index) \ if( astTest##attr(this,index) ) { \ astSet##attr( this, index, astGet##attr( this, index ) ); \ if( !astOK ) { \ astClearStatus; \ astClear##attr( this, index ); \ } \ } #endif #if defined(astCLASS) /* Protected */ #define astSetVtabClassIdentifier(vtab,id_ptr) \ ((AstObjectVtab *)(vtab))->top_id = (id_ptr) #endif /* Type Definitions. */ /* ================= */ /* Object structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstObject { /* Attributes specific to objects in this class. */ unsigned long check; /* Check value to identify Objects */ size_t size; /* Amount of memory used by Object */ struct AstObjectVtab *vtab; /* Pointer to virtual function table */ char dynamic; /* Memory allocated dynamically? */ int ref_count; /* Number of active pointers to the Object */ char *id; /* Pointer to ID string */ char *ident; /* Pointer to Ident string */ char usedefs; /* Use default attribute values? */ int iref; /* Object index (unique within class) */ void *proxy; /* A pointer to an external object that acts as a foreign language proxy for the AST object */ #if defined(THREAD_SAFE) int locker; /* Thread that has locked this Object */ pthread_mutex_t mutex1; /* Guards access to all elements of the Object except for the "locker" and "ref_count" components */ pthread_mutex_t mutex2; /* Guards access to the "locker" and "ref_count" components */ struct AstGlobals *globals; /* Pointer to thread-specific global data */ #endif } AstObject; /* Class identifier structure */ typedef struct AstClassIdentifier { int *check; struct AstClassIdentifier *parent; } AstClassIdentifier; /* Virtual function table. */ /* ----------------------- */ /* The virtual function table makes a forward reference to the AstChannel structure which is not defined until "channel.h" is included (below). Hence make a preliminary definition available now. */ struct AstChannel; /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstObjectVtab { /* A unique identifier for this class. */ AstClassIdentifier id; /* Pointer to the structure that identifies the top-level class described by the whole vtab (of which the AstObjectVtab is just the first, lowest-level, component). */ AstClassIdentifier *top_id; /* Pointer to a dynamically allocated string holding the default attribute values to use when creating new objects. These are read from environment variables of the form "_OPTIONS". */ const char *defaults; /* Properties specific to this class. */ void ( *CleanAttribs )( AstObject *, int * ); AstObject *( *Cast )( AstObject *, AstObject *, int * ); const char *( *GetID )( AstObject *, int * ); const char *( *GetIdent )( AstObject *, int * ); const char *(* GetAttrib)( AstObject *, const char *, int * ); int (* TestAttrib)( AstObject *, const char *, int * ); int (* TestID)( AstObject *, int * ); int (* Same)( AstObject *, AstObject *, int * ); int (* HasAttribute)( AstObject *, const char *, int * ); int (* TestIdent)( AstObject *, int * ); void (* Clear)( AstObject *, const char *, int * ); void (* ClearAttrib)( AstObject *, const char *, int * ); void (* ClearID)( AstObject *, int * ); void (* ClearIdent)( AstObject *, int * ); void (* Dump)( AstObject *, struct AstChannel *, int * ); int (* Equal)( AstObject *, AstObject *, int * ); void (* SetAttrib)( AstObject *, const char *, int * ); void (* SetID)( AstObject *, const char *, int * ); void (* SetIdent)( AstObject *, const char *, int * ); void (* Show)( AstObject *, int * ); void (* VSet)( AstObject *, const char *, char **, va_list, int * ); void (* EnvSet)( AstObject *, int * ); void *(* GetProxy)( AstObject *, int * ); void (* SetProxy)( AstObject *, void *, int * ); int (* GetObjSize)( AstObject *, int * ); int (* TestUseDefs)( AstObject *, int * ); int (* GetUseDefs)( AstObject *, int * ); void (* SetUseDefs)( AstObject *, int, int * ); void (* ClearUseDefs)( AstObject *, int * ); const char *class; /* Pointer to class name string */ void (** delete)( AstObject *, int * ); /* Pointer to array of destructors */ void (** copy)( const AstObject *, AstObject *, int * ); /* Copy constructors */ void (** dump)( AstObject *, struct AstChannel *, int * ); /* Dump functions */ const char **dump_class; /* Dump function class string pointers */ const char **dump_comment; /* Dump function comment string pointers */ int ndelete; /* Number of destructors */ int ncopy; /* Number of copy constructors */ int ndump; /* Number of dump functions */ int nobject; /* Number of active objects in the class */ int nfree; /* No. of entries in "free_list" */ AstObject **free_list; /* List of pointers for freed Objects */ #if defined(THREAD_SAFE) int (* ManageLock)( AstObject *, int, int, AstObject **, int * ); #endif } AstObjectVtab; #endif #if defined(THREAD_SAFE) && defined(astCLASS) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstObjectGlobals { AstObjectVtab Class_Vtab; int Class_Init; int Retain_Esc; int Context_Level; int *Active_Handles; char GetAttrib_Buff[ AST__GETATTRIB_BUFF_LEN + 1 ]; char *AstGetC_Strings[ AST__ASTGETC_MAX_STRINGS ]; int AstGetC_Istr; int AstGetC_Init; int Nvtab; AstObjectVtab **Known_Vtabs; } AstObjectGlobals; #endif /* More include files. */ /* =================== */ /* The interface to the Channel class must be included here (after the type definitions for the Object class) because "channel.h" itself includes this file ("object.h"), although "object.h" refers to the AstChannel structure above. This seems a little strange at first, but is simply analogous to making a forward reference to a structure type when recursively defining a normal C structure (except that here the definitions happen to be in separate include files). */ #include "channel.h" /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Object) /* Validate class membership */ astPROTO_ISA(Object) /* Test class membership */ /* NB. There is no constructor function for this class. */ #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstObject *astInitObject_( void *, size_t, int, AstObjectVtab *, const char *, int * ); /* Vtab Initialiser. */ void astInitObjectVtab_( AstObjectVtab *, const char *, int * ); /* Loader. */ AstObject *astLoadObject_( void *, size_t, AstObjectVtab *, const char *, AstChannel *channel, int * ); #if defined(THREAD_SAFE) void astInitObjectGlobals_( AstObjectGlobals * ); #endif #endif /* Prototypes for other class functions. */ /* ------------------------------------- */ #if !defined(astCLASS) /* Public */ void astBegin_( void ); void astEnd_( int * ); #endif AstObject *astI2P_( int, int * ); AstObject *astMakeId_( AstObject *, int * ); AstObject *astMakePointer_( AstObject *, int * ); AstObject *astMakePointer_NoLockCheck_( AstObject *, int * ); int astP2I_( AstObject *, int * ); int astVersion_( int * ); int astEscapes_( int, int * ); int astTune_( const char *, int, int * ); void astTuneC_( const char *, const char *, char *, int, int * ); /* Prototypes for member functions. */ /* -------------------------------- */ #if defined(astCLASS) /* Protected */ AstObject *astAnnul_( AstObject *, int * ); AstObject *astDelete_( AstObject *, int * ); void astSet_( void *, const char *, int *, ... ); #else /* Public */ AstObject *astDeleteId_( AstObject *, int * ); int astThreadId_( AstObject *, int, int * ); void astExportId_( AstObject *, int * ); void astImportId_( AstObject *, int * ); void astSetId_( void *, const char *, ... )__attribute__((format(printf,2,3))); #endif AstObject *astAnnulId_( AstObject *, int * ); AstObject *astCheckLock_( AstObject *, int * ); AstObject *astClone_( AstObject *, int * ); AstObject *astCopy_( const AstObject *, int * ); AstObject *astFromString_( const char *, int * ); char *astToString_( AstObject *, int * ); const char *astGetC_( AstObject *, const char *, int * ); double astGetD_( AstObject *, const char *, int * ); float astGetF_( AstObject *, const char *, int * ); int astEqual_( AstObject *, AstObject *, int * ); int astGetI_( AstObject *, const char *, int * ); int astHasAttribute_( AstObject *, const char *, int * ); int astSame_( AstObject *, AstObject *, int * ); int astTest_( AstObject *, const char *, int * ); long astGetL_( AstObject *, const char *, int * ); void *astGetProxy_( AstObject *, int * ); void astClear_( AstObject *, const char *, int * ); void astExemptId_( AstObject *, int * ); void astLockId_( AstObject *, int, int * ); void astSetC_( AstObject *, const char *, const char *, int * ); void astSetD_( AstObject *, const char *, double, int * ); void astSetF_( AstObject *, const char *, float, int * ); void astSetI_( AstObject *, const char *, int, int * ); void astSetL_( AstObject *, const char *, long, int * ); void astSetProxy_( AstObject *, void *, int * ); void astShow_( AstObject *, int * ); void astUnlockId_( AstObject *, int, int * ); #if defined(astCLASS) /* Protected */ void astCleanAttribs_( AstObject *, int * ); AstObject *astCast_( AstObject *, AstObject *, int * ); AstObject *astCastCopy_( AstObject *, AstObject *, int * ); #if defined(THREAD_SAFE) int astManageLock_( AstObject *, int, int, AstObject **, int * ); #endif int astGetObjSize_( AstObject *, int * ); int astTestUseDefs_( AstObject *, int * ); int astGetUseDefs_( AstObject *, int * ); void astSetUseDefs_( AstObject *, int, int * ); void astClearUseDefs_( AstObject *, int * ); const char *astGetAttrib_( AstObject *, const char *, int * ); const char *astGetClass_( const AstObject *, int * ); const char *astGetID_( AstObject *, int * ); const char *astGetIdent_( AstObject *, int * ); int astClassCompare_( AstObjectVtab *, AstObjectVtab *, int * ); int astGetNobject_( const AstObject *, int * ); int astGetRefCount_( AstObject *, int * ); int astTestAttrib_( AstObject *, const char *, int * ); int astTestID_( AstObject *, int * ); int astTestIdent_( AstObject *, int * ); void astClearAttrib_( AstObject *, const char *, int * ); void astClearID_( AstObject *, int * ); void astClearIdent_( AstObject *, int * ); void astDump_( AstObject *, AstChannel *, int * ); void astSetAttrib_( AstObject *, const char *, int * ); void astSetCopy_( AstObjectVtab *, void (*)( const AstObject *, AstObject *, int * ), int * ); void astSetDelete_( AstObjectVtab *, void (*)( AstObject *, int * ), int * ); void astSetDump_( AstObjectVtab *, void (*)( AstObject *, AstChannel *, int * ), const char *, const char *, int * ); void astSetVtab_( AstObject *, AstObjectVtab *, int * ); void astSetID_( AstObject *, const char *, int * ); void astSetIdent_( AstObject *, const char *, int * ); void astEnvSet_( AstObject *, int * ); void astVSet_( AstObject *, const char *, char **, va_list, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Check class membership. */ #define astCheckObject(this) astINVOKE_CHECK(Object,this,0) #define astVerifyObject(this) astINVOKE_CHECK(Object,this,1) /* Test class membership. */ #define astIsAObject(this) astINVOKE_ISA(Object,this) /* NB. There is no constructor function for this class. */ #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitObject(mem,size,init,vtab,name) \ astINVOKE(O,astInitObject_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitObjectVtab(vtab,name) astINVOKE(V,astInitObjectVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadObject(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadObject_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to other class functions. */ /* ------------------------------------ */ #if !defined(astCLASS) /* Public */ #define astBegin astBegin_() #define astEnd astINVOKE(V,astEnd_(STATUS_PTR)) #else /* Protected */ #define astMakePointer_NoLockCheck(id) ((void *)astMakePointer_NoLockCheck_((AstObject *)(id),STATUS_PTR)) #endif #define astVersion astVersion_(STATUS_PTR) #define astEscapes(int) astEscapes_(int,STATUS_PTR) #define astTune(name,val) astTune_(name,val,STATUS_PTR) #define astTuneC(name,value,buff,bufflen) astTuneC_(name,value,buff,bufflen,STATUS_PTR) #define astI2P(integer) ((void *)astI2P_(integer,STATUS_PTR)) #define astMakeId(pointer) ((void *)astMakeId_((AstObject *)(pointer),STATUS_PTR)) #define astP2I(pointer) astP2I_((AstObject *)(pointer),STATUS_PTR) #define astMakePointer(id) ((void *)astCheckLock_(astMakePointer_((AstObject *)(id),STATUS_PTR),STATUS_PTR)) #define astToString(this) astINVOKE(V,astToString_(astCheckObject(this),STATUS_PTR)) #define astFromString(string) astINVOKE(O,astFromString_(string,STATUS_PTR)) /* Interfaces to member functions. */ /* ------------------------------- */ /* Here we make use of astCheckObject (et al.) to validate Object pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. In the case of an external caller, it also performs the required conversion from an Object identifier to a true C pointer. */ /* These functions require special treatment for external use because they handle Object identifiers and their resources explicitly, and must therefore be passed identifier values without conversion to C pointers. */ #if defined(astCLASS) || defined(astFORTRAN77) /* Protected or Fotran interface */ #define astAnnulId(this) astINVOKE(O,astAnnulId_((AstObject *)(this),STATUS_PTR)) #endif #if defined(astCLASS) /* Protected only */ #define astAnnul(this) astINVOKE(O,astAnnul_(astCheckObject(this),STATUS_PTR)) #define astDelete(this) astINVOKE(O,astDelete_(astCheckObject(this),STATUS_PTR)) #define astSet astINVOKE(F,astSet_) #else /* Public only */ #define astAnnul(this) astINVOKE(O,astAnnulId_((AstObject *)(this),STATUS_PTR)) #define astDelete(this) astINVOKE(O,astDeleteId_((AstObject *)(this),STATUS_PTR)) #define astExport(this) astINVOKE(V,astExportId_((AstObject *)(this),STATUS_PTR)) #define astImport(this) astINVOKE(V,astImportId_((AstObject *)(this),STATUS_PTR)) #define astSet astINVOKE(F,astSetId_) #define astThread(this,ptr) astINVOKE(V,astThreadId_((AstObject *)(this),ptr,STATUS_PTR)) #endif /* Both.... */ #define astLock(this,wait) astINVOKE(V,astLockId_((AstObject *)(this),wait,STATUS_PTR)) #define astUnlock(this,report) astINVOKE(V,astUnlockId_((AstObject *)(this),report,STATUS_PTR)) #define astEqual(this,that) astINVOKE(V,(((AstObject*)this==(AstObject*)that)||astEqual_(astCheckObject(this),astCheckObject(that),STATUS_PTR))) #define astExempt(this) astINVOKE(V,astExemptId_((AstObject *)(this),STATUS_PTR)) #define astClear(this,attrib) astINVOKE(V,astClear_(astCheckObject(this),attrib,STATUS_PTR)) #define astClone(this) astINVOKE(O,astClone_(astCheckObject(this),STATUS_PTR)) #define astCopy(this) astINVOKE(O,astCopy_(astCheckObject(this),STATUS_PTR)) #define astGetC(this,attrib) astINVOKE(V,astGetC_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetD(this,attrib) astINVOKE(V,astGetD_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetF(this,attrib) astINVOKE(V,astGetF_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetI(this,attrib) \ astINVOKE(V,astGetI_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetL(this,attrib) \ astINVOKE(V,astGetL_(astCheckObject(this),attrib,STATUS_PTR)) #define astSetC(this,attrib,value) \ astINVOKE(V,astSetC_(astCheckObject(this),attrib,value,STATUS_PTR)) #define astSetD(this,attrib,value) \ astINVOKE(V,astSetD_(astCheckObject(this),attrib,value,STATUS_PTR)) #define astSetF(this,attrib,value) \ astINVOKE(V,astSetF_(astCheckObject(this),attrib,value,STATUS_PTR)) #define astSetI(this,attrib,value) \ astINVOKE(V,astSetI_(astCheckObject(this),attrib,value,STATUS_PTR)) #define astSetL(this,attrib,value) \ astINVOKE(V,astSetL_(astCheckObject(this),attrib,value,STATUS_PTR)) #define astShow(this) \ astINVOKE(V,astShow_(astCheckObject(this),STATUS_PTR)) #define astTest(this,attrib) \ astINVOKE(V,astTest_(astCheckObject(this),attrib,STATUS_PTR)) #define astSame(this,that) \ astINVOKE(V,astSame_(astCheckObject(this),astCheckObject(that),STATUS_PTR)) #define astHasAttribute(this,attrib) \ astINVOKE(V,astHasAttribute_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetProxy(this) \ astINVOKE(V,astGetProxy_(astCheckObject(this),STATUS_PTR)) #define astSetProxy(this,proxy) \ astINVOKE(V,astSetProxy_(astCheckObject(this),proxy,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #if defined(THREAD_SAFE) #define astManageLock(this,mode,extra,fail) \ astINVOKE(V,astManageLock_(astCheckObject(this),mode, extra,fail,STATUS_PTR)) #else #define astManageLock(this,mode,extra,fail) #endif #define astCleanAttribs(this) astINVOKE(V,astCleanAttribs_(astCheckObject(this),STATUS_PTR)) #define astGetObjSize(this) astINVOKE(V,astGetObjSize_(astCheckObject(this),STATUS_PTR)) #define astCast(this,obj) astINVOKE(O,astCast_(astCheckObject(this),astCheckObject(obj),STATUS_PTR)) #define astCastCopy(this,obj) astCastCopy_((AstObject*)this,(AstObject*)obj,STATUS_PTR) #define astClearUseDefs(this) astINVOKE(V,astClearUseDefs_(astCheckObject(this),STATUS_PTR)) #define astTestUseDefs(this) astINVOKE(V,astTestUseDefs_(astCheckObject(this),STATUS_PTR)) #define astGetUseDefs(this) astINVOKE(V,astGetUseDefs_(astCheckObject(this),STATUS_PTR)) #define astSetUseDefs(this,val) astINVOKE(V,astSetUseDefs_(astCheckObject(this),val,STATUS_PTR)) #define astClearAttrib(this,attrib) \ astINVOKE(V,astClearAttrib_(astCheckObject(this),attrib,STATUS_PTR)) #define astClearID(this) astINVOKE(V,astClearID_(astCheckObject(this),STATUS_PTR)) #define astClearIdent(this) astINVOKE(V,astClearIdent_(astCheckObject(this),STATUS_PTR)) #define astDump(this,channel) \ astINVOKE(V,astDump_(astCheckObject(this),astCheckChannel(channel),STATUS_PTR)) #define astGetAttrib(this,attrib) \ astINVOKE(V,astGetAttrib_(astCheckObject(this),attrib,STATUS_PTR)) #define astGetClass(this) astINVOKE(V,astGetClass_((const AstObject *)(this),STATUS_PTR)) #define astGetID(this) astINVOKE(V,astGetID_(astCheckObject(this),STATUS_PTR)) #define astGetIdent(this) astINVOKE(V,astGetIdent_(astCheckObject(this),STATUS_PTR)) #define astGetNobject(this) astINVOKE(V,astGetNobject_(astCheckObject(this),STATUS_PTR)) #define astClassCompare(class1,class2) astClassCompare_(class1,class2,STATUS_PTR) #define astGetRefCount(this) astINVOKE(V,astGetRefCount_(astCheckObject(this),STATUS_PTR)) #define astSetAttrib(this,setting) \ astINVOKE(V,astSetAttrib_(astCheckObject(this),setting,STATUS_PTR)) #define astSetCopy(vtab,copy) \ astINVOKE(V,astSetCopy_((AstObjectVtab *)(vtab),copy,STATUS_PTR)) #define astSetDelete(vtab,delete) \ astINVOKE(V,astSetDelete_((AstObjectVtab *)(vtab),delete,STATUS_PTR)) #define astSetDump(vtab,dump,class,comment) \ astINVOKE(V,astSetDump_((AstObjectVtab *)(vtab),dump,class,comment,STATUS_PTR)) #define astSetVtab(object,vtab) \ astINVOKE(V,astSetVtab_((AstObject *)object,(AstObjectVtab *)(vtab),STATUS_PTR)) #define astSetID(this,id) astINVOKE(V,astSetID_(astCheckObject(this),id,STATUS_PTR)) #define astSetIdent(this,id) astINVOKE(V,astSetIdent_(astCheckObject(this),id,STATUS_PTR)) #define astVSet(this,settings,text,args) \ astINVOKE(V,astVSet_(astCheckObject(this),settings,text,args,STATUS_PTR)) #define astEnvSet(this) \ astINVOKE(V,astEnvSet_(astCheckObject(this),STATUS_PTR)) #define astTestAttrib(this,attrib) \ astINVOKE(V,astTestAttrib_(astCheckObject(this),attrib,STATUS_PTR)) #define astTestID(this) astINVOKE(V,astTestID_(astCheckObject(this),STATUS_PTR)) #define astTestIdent(this) astINVOKE(V,astTestIdent_(astCheckObject(this),STATUS_PTR)) /* Deprecated synonym. */ #define astClass(this) astGetClass(this) #endif /* Extra stuff for debuging probnlems with object handles and memory usage */ #ifdef MEM_DEBUG void astWatchHandle_( int ); void astHandleUse_( int, const char *, ... ); void astHandleAlarm_( const char *, va_list ); #define astWatchHandle astWatchHandle_ #define astHandleUse astHandleUse_ #define astHandleAlarm astHandleAlarm_ #else #define astWatchHandle #define astHandleUse #define astHandleAlarm #endif #endif ./ast-7.3.3/stcobsdatalocation.c0000644000175000017500000011151512262533650015172 0ustar olesoles/* *class++ * Name: * StcObsDataLocation * Purpose: * Correspond to the IVOA ObsDataLocation class. * Constructor Function: c astStcObsDataLocation f AST_STCOBSDATALOCATION * Description: * The StcObsDataLocation class is a sub-class of Stc used to describe * the coordinate space occupied by a particular observational dataset. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * * An STC ObsDataLocation element specifies the extent of the * observation within a specified coordinate system, and also specifies * the observatory location within a second coordinate system. * * The AST StcObsDataLocation class inherits from Stc, and therefore * an StcObsDataLocation can be used directly as an Stc. When used * in this way, the StcObsDataLocation describes the location of the * observation (not the observatory). * * Eventually, this class will have a method for returning an Stc * describing the observatory location. However, AST currently does not * include any classes of Frame for describing terrestrial or solar * system positions. Therefore, the provision for returning observatory * location as an Stc is not yet available. However, for terrestrial * observations, the position of the observatory can still be recorded * using the ObsLon and ObsLat attributes of the Frame encapsulated * within the Stc representing the observation location (this assumes * the observatory is located at sea level). * Inheritance: * The StcObsDataLocation class inherits from the Stc class. * Attributes: * The StcObsDataLocation class does not define any new attributes beyond * those which are applicable to all Stcs. * Functions: c The StcObsDataLocation class does not define any new functions beyond those f The StcObsDataLocation class does not define any new routines beyond those * which are applicable to all Stcs. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 25-APR-2005 (DSB): * Original version. * 14-FEB-2006 (DSB): * Override astGetObjSize. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS StcObsDataLocation /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "stc.h" /* Coordinate stcs (parent class) */ #include "channel.h" /* I/O channels */ #include "region.h" /* Regions within coordinate systems */ #include "pointlist.h" /* Points within coordinate systems */ #include "stcobsdatalocation.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(StcObsDataLocation) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(StcObsDataLocation,Class_Init) #define class_vtab astGLOBAL(StcObsDataLocation,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstStcObsDataLocationVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstStcObsDataLocation *astStcObsDataLocationId_( void *, int, AstKeyMap **, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void StcSetObs( AstStcObsDataLocation *, AstPointList *, int * ); static int GetObjSize( AstObject *, int * ); /* Member functions. */ /* ================= */ static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "stcobsdatalocation.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * StcObsDataLocation member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied StcObsDataLocation, * in bytes. * Parameters: * this * Pointer to the StcObsDataLocation. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstStcObsDataLocation *this; /* Pointer to StcObsDataLocation structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the StcObsDataLocation structure. */ this = (AstStcObsDataLocation *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->obs ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } void astInitStcObsDataLocationVtab_( AstStcObsDataLocationVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitStcObsDataLocationVtab * Purpose: * Initialise a virtual function table for a StcObsDataLocation. * Type: * Protected function. * Synopsis: * #include "stcobsdatalocation.h" * void astInitStcObsDataLocationVtab( AstStcObsDataLocationVtab *vtab, const char *name ) * Class Membership: * StcObsDataLocation vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the StcObsDataLocation class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstStcVtab *stc; /* Pointer to Stc component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitStcVtab( (AstStcVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAStcObsDataLocation) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstStcVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; stc = (AstStcVtab *) vtab; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ vtab->StcSetObs = StcSetObs; /* Declare the copy constructor, destructor and class dump functions. */ astSetDump( vtab, Dump, "StcObsDataLocation", "Observation coverage" ); astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static void StcSetObs( AstStcObsDataLocation *this, AstPointList *obs, int *status ) { /* *+ * Name: * astStcSetObs * Purpose: * Set the observatory position within an StcObsDataLocation. * Type: * Protected function. * Synopsis: * #include "region.h" * void astStcSetObs( AstStcObsDataLocation *this, AstPointList *obs ) * Class Membership: * StcObsDataLocation virtual function * Description: * This function stores a clone of the supplied PointList pointer * within the supplied StcObsDataLocation, first annulling any * pointer already stored in the StcObsDataLocation. * Parameters: * this * Pointer to the StcObsDataLocation. * obs * Pointer to a PointList defining the observatory position. NULL * may be supplied in which case any existing observatory position * is removed. *- */ /* Check the global error status. */ if ( !astOK ) return; /* Free any existing obseravtory position PointList. */ if( this->obs ) this->obs = astAnnul( this->obs ); /* Store any supplied pointer. */ if( obs ) this->obs = astClone( obs ); } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for StcObsDataLocation objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for StcObsDataLocation * objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Regions within the StcObsDataLocation. */ /* Local Variables: */ AstStcObsDataLocation *in; /* Pointer to input StcObsDataLocation */ AstStcObsDataLocation *out; /* Pointer to output StcObsDataLocation */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output StcObsDataLocations. */ in = (AstStcObsDataLocation *) objin; out = (AstStcObsDataLocation *) objout; /* For safety, start by clearing any references to the input component Regions, etc, from the output StcObsDataLocation. */ out->obs = NULL; /* Make a copy of the Observatory location */ if( in->obs ) out->obs = astCopy( in->obs ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for StcObsDataLocation objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for StcObsDataLocation objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstStcObsDataLocation *this; /* Pointer to StcObsDataLocation */ /* Obtain a pointer to the StcObsDataLocation structure. */ this = (AstStcObsDataLocation *) obj; /* Annul the pointer to the observatory location Region. */ if( this->obs ) this->obs = astAnnul( this->obs ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for StcObsDataLocation objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the StcObsDataLocation class to an output Channel. * Parameters: * this * Pointer to the StcObsDataLocation whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstStcObsDataLocation *this; /* Pointer to the StcObsDataLocation structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the StcObsDataLocation structure. */ this = (AstStcObsDataLocation *) this_object; /* Write out values representing the instance variables for the StcObsDataLocation class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Observatory position. */ /* --------------------- */ astWriteObject( channel, "ObsLoc", 1, 1, this->obs, "Observatory position" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAStcObsDataLocation and astCheckStcObsDataLocation functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(StcObsDataLocation,Stc) astMAKE_CHECK(StcObsDataLocation) AstStcObsDataLocation *astStcObsDataLocation_( void *region_void, int ncoords, AstKeyMap **coords, const char *options, int *status, ...) { /* *++ * Name: c astStcObsDataLocation f AST_STCOBSDATALOCATION * Purpose: * Create a StcObsDataLocation. * Type: * Public function. * Synopsis: c #include "stcobsdatalocation.h" c AstStcObsDataLocation *astStcObsDataLocation( AstRegion *region, c int ncoords, AstKeyMap *coords[], const char *options, ... ) f RESULT = AST_STCOBSDATALOCATION( REGION, NCOORDS, COORDS, OPTIONS, STATUS ) * Class Membership: * StcObsDataLocation constructor. * Description: * This function creates a new StcObsDataLocation and optionally initialises its * attributes. * * The StcObsDataLocation class is a sub-class of Stc used to describe * the coverage of the datasets contained in some VO resource. * * See http://hea-www.harvard.edu/~arots/nvometa/STC.html * Parameters: c region f REGION = INTEGER (Given) * Pointer to the encapsulated Region. c ncoords f NCOORDS = INTEGER (Given) c The length of the "coords" array. Supply zero if "coords" is NULL. f The length of the COORDS array. Supply zero if COORDS should be f ignored. c coords f COORDS( NCOORDS ) = INTEGER (Given) c Pointer to an array holding "ncoords" AstKeyMap pointers (if "ncoords" f An array holding NCOORDS AstKeyMap pointers (if NCOORDS * is zero, the supplied value is ignored). Each supplied KeyMap * describes the contents of a single STC element, and * should have elements with keys given by constants AST__STCNAME, * AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. Any of these elements may be omitted, but no other * elements should be included. If supplied, the AST__STCNAME element * should be a vector of character string pointers holding the "Name" * item for each axis in the coordinate system represented by c "region". f REGION. * Any other supplied elements should be scalar elements, each holding * a pointer to a Region describing the associated item of ancillary * information (error, resolution, size, pixel size or value). These * Regions should describe a volume within the coordinate system c represented by "region". f represented by REGION. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new StcObsDataLocation. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new StcObsDataLocation. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astStcObsDataLocation() f AST_STCOBSDATALOCATION = INTEGER * A pointer to the new StcObsDataLocation. * Notes: * - A deep copy is taken of the supplied Region. This means that * any subsequent changes made to the encapsulated Region using the * supplied pointer will have no effect on the Stc. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstRegion *region; /* Pointer to Region structure */ AstStcObsDataLocation *new; /* Pointer to new StcObsDataLocation */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain and validate a pointer to the Region structure provided. */ region = astCheckRegion( region_void ); /* Initialise the StcObsDataLocation, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitStcObsDataLocation( NULL, sizeof( AstStcObsDataLocation ), !class_init, &class_vtab, "StcObsDataLocation", region, ncoords, coords ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new StcObsDataLocation's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new StcObsDataLocation. */ return new; } AstStcObsDataLocation *astStcObsDataLocationId_( void *region_void, int ncoords, AstKeyMap **coords, const char *options, ... ) { /* * Name: * astStcObsDataLocationId_ * Purpose: * Create a StcObsDataLocation. * Type: * Private function. * Synopsis: * #include "stcobsdatalocation.h" * AstStcObsDataLocation *astStcObsDataLocationId( AstRegion *region, * int ncoords, AstKeyMap *coords[], const char *options, ..., int *status ) * Class Membership: * StcObsDataLocation constructor. * Description: * This function implements the external (public) interface to the * astStcObsDataLocation constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astStcObsDataLocation_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astStcObsDataLocation_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astStcObsDataLocation_. * status * Pointer to the inherited status variable. * Returned Value: * The ID value associated with the new StcObsDataLocation. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstKeyMap **keymaps; /* Pointer to array of KeyMap pointers */ AstRegion *region; /* Pointer to Region structure */ AstStcObsDataLocation *new; /* Pointer to new StcObsDataLocation */ int icoord; /* Keymap index */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Obtain a Region pointer from the supplied ID and validate the pointer to ensure it identifies a valid Region. */ region = astVerifyRegion( astMakePointer( region_void ) ); /* Obtain pointer from the supplied KeyMap ID's and validate the pointers to ensure it identifies a valid KeyMap. */ keymaps = astMalloc( sizeof( AstKeyMap * )*(size_t) ncoords ); if( keymaps ) { for( icoord = 0; icoord < ncoords; icoord++ ) { keymaps[ icoord ] = astVerifyKeyMap( astMakePointer( coords[ icoord ] ) ); } } /* Initialise the StcObsDataLocation, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitStcObsDataLocation( NULL, sizeof( AstStcObsDataLocation ), !class_init, &class_vtab, "StcObsDataLocation", region, ncoords, keymaps ); /* Free resources. */ keymaps = astFree( keymaps ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new StcObsDataLocation's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new StcObsDataLocation. */ return astMakeId( new ); } AstStcObsDataLocation *astInitStcObsDataLocation_( void *mem, size_t size, int init, AstStcObsDataLocationVtab *vtab, const char *name, AstRegion *region, int ncoords, AstKeyMap **coords, int *status ) { /* *+ * Name: * astInitStcObsDataLocation * Purpose: * Initialise a StcObsDataLocation. * Type: * Protected function. * Synopsis: * #include "stcobsdatalocation.h" * AstStcObsDataLocation *astInitStcObsDataLocation_( void *mem, size_t size, * int init, AstStcObsDataLocationVtab *vtab, * const char *name, AstRegion *region, * int ncoords, AstKeyMap **coords ) * Class Membership: * StcObsDataLocation initialiser. * Description: * This function is provided for use by class implementations to initialise * a new StcObsDataLocation object. It allocates memory (if necessary) to accommodate * the StcObsDataLocation plus any additional data associated with the derived class. * It then initialises a StcObsDataLocation structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a StcObsDataLocation at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the StcObsDataLocation is to be initialised. * This must be of sufficient size to accommodate the StcObsDataLocation data * (sizeof(StcObsDataLocation)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the StcObsDataLocation (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the StcObsDataLocation * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the StcObsDataLocation's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new StcObsDataLocation. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * region * A pointer to the Region encapsulated by the StcObsDataLocation. * ncoords * Number of KeyMap pointers supplied in "coords". Can be zero. * Ignored if "coords" is NULL. * coords * Pointer to an array of "ncoords" KeyMap pointers, or NULL if * "ncoords" is zero. Each KeyMap defines defines a single * element, and should have elements with keys given by constants * AST__STCNAME, AST__STCVALUE, AST__STCERROR, AST__STCRES, AST__STCSIZE, * AST__STCPIXSZ. These elements hold values for the corresponding * components of the STC AstroCoords element. Any of these elements may * be omitted, but no other elements should be included. All supplied * elements should be vector elements, with vector length less than or * equal to the number of axes in the supplied Region. The data type of * all elements should be "double", except for AST__STCNAME which should * be "character string". If no value is available for a given axis, then * AST__BAD (or NULL for the AST__STCNAME element) should be stored in * the vector at the index corresponding to the axis (trailing axes * can be omitted completely from the KeyMap). * Returned Value: * A pointer to the new StcObsDataLocation. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstStcObsDataLocation *new; /* Pointer to new StcObsDataLocation */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitStcObsDataLocationVtab( vtab, name ); /* Initialise a Stc structure (the parent class) as the first component within the StcObsDataLocation structure, allocating memory if necessary. */ new = (AstStcObsDataLocation *) astInitStc( mem, size, 0, (AstStcVtab *) vtab, name, region, ncoords, coords ); /* If succesful, initialise properties of the StcObsDataLocation. */ if( new ) { new->obs = NULL; } /* If an error occurred, clean up by deleting the new StcObsDataLocation. */ if ( !astOK ) new = astDelete( new ); /* Return a pointer to the new StcObsDataLocation. */ return new; } AstStcObsDataLocation *astLoadStcObsDataLocation_( void *mem, size_t size, AstStcObsDataLocationVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadStcObsDataLocation * Purpose: * Load a StcObsDataLocation. * Type: * Protected function. * Synopsis: * #include "stcobsdatalocation.h" * AstStcObsDataLocation *astLoadStcObsDataLocation( void *mem, size_t size, AstStcObsDataLocationVtab *vtab, * const char *name, AstChannel *channel ) * Class Membership: * StcObsDataLocation loader. * Description: * This function is provided to load a new StcObsDataLocation using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * StcObsDataLocation structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a StcObsDataLocation at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the StcObsDataLocation is to be * loaded. This must be of sufficient size to accommodate the * StcObsDataLocation data (sizeof(StcObsDataLocation)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the StcObsDataLocation (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the StcObsDataLocation structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstStcObsDataLocation) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new StcObsDataLocation. If this is NULL, a pointer * to the (static) virtual function table for the StcObsDataLocation class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "StcObsDataLocation" is used instead. * Returned Value: * A pointer to the new StcObsDataLocation. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstStcObsDataLocation *new; /* Pointer to the new StcObsDataLocation */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this StcObsDataLocation. In this case the StcObsDataLocation belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstStcObsDataLocation ); vtab = &class_vtab; name = "StcObsDataLocation"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitStcObsDataLocationVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built StcObsDataLocation. */ new = astLoadStc( mem, size, (AstStcVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "StcObsDataLocation" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Observatory position. */ /* --------------------- */ new->obs = astReadObject( channel, "obsloc", NULL ); /* If an error occurred, clean up by deleting the new StcObsDataLocation. */ if ( !astOK ) new = astDelete( new ); } /* Return the new StcObsDataLocation pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astStcSetObs_( AstStcObsDataLocation *this, AstPointList *obs, int *status ){ if ( !astOK ) return; (**astMEMBER(this,StcObsDataLocation,StcSetObs))( this, obs, status ); } ./ast-7.3.3/grf.h0000644000175000017500000000577512262533650012107 0ustar olesoles#if !defined( GRF_INCLUDED ) /* Include this file only once */ #define GRF_INCLUDED /* *+ * Name: * grf.h * Type: * C include file. * Purpose: * Define the interface to the grf module * Invocation: * #include "grf.h" * Description: * This include file defines the interface to the grf module and * provides the type definitions, function prototypes and macros, etc. * needed to use this module. * Inheritance: * The grf module is not a class and does not inherit. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 27-JUN-1996 (DSB): * Original version. * 25-OCT-1996 (DSB): * Primatives macros defined, extra parameter added to astGAttr. * 17-FEB-2006 (DSB): * Added GRF__ESH and GRF__ESG. *- */ /* Constant Values. */ /* ================ */ /* Values identifying different graphics attributes. */ #define GRF__STYLE 0 #define GRF__WIDTH 1 #define GRF__SIZE 2 #define GRF__FONT 3 #define GRF__COLOUR 4 /* Values identifying different graphics primatives. */ #define GRF__TEXT 0 #define GRF__LINE 1 #define GRF__MARK 2 /* The number of different graphics attributes */ #define GRF__NATTR 5 /* Values identifying capabilities */ #define GRF__ESC 0 #define GRF__MJUST 1 #define GRF__SCALES 2 /* Values identifying types of graphics escape sequence */ #define GRF__ESPER 1 #define GRF__ESSUP 2 #define GRF__ESSUB 3 #define GRF__ESGAP 4 #define GRF__ESBAC 5 #define GRF__ESSIZ 6 #define GRF__ESWID 7 #define GRF__ESFON 8 #define GRF__ESCOL 9 #define GRF__ESSTY 10 #define GRF__ESPOP 11 #define GRF__ESPSH 12 #define GRF__ESH 13 #define GRF__ESG 14 /* Function prototypes. */ /* ==================== */ int astGAttr( int, double, double *, int ); int astGScales( float *, float * ); int astGBBuf( void ); int astGEBuf( void ); int astGFlush( void ); int astGLine( int, const float *, const float * ); int astGMark( int, const float *, const float *, int ); int astGQch( float *, float * ); int astGText( const char *, float, float, const char *, float, float ); int astGTxExt( const char *, float, float, const char *, float, float, float *, float * ); int astGCap( int, int ); #endif ./ast-7.3.3/tranmap.c0000644000175000017500000023776712262533650012776 0ustar olesoles/* *class++ * Name: * TranMap * Purpose: * Mapping with specified forward and inverse transformations. * Constructor Function: c astTranMap f AST_TRANMAP * Description: * A TranMap is a Mapping which combines the forward transformation of * a supplied Mapping with the inverse transformation of another * supplied Mapping, ignoring the un-used transformation in each * Mapping (indeed the un-used transformation need not exist). * * When the forward transformation of the TranMap is referred to, the * transformation actually used is the forward transformation of the * first Mapping supplied when the TranMap was constructed. Likewise, * when the inverse transformation of the TranMap is referred to, the * transformation actually used is the inverse transformation of the * second Mapping supplied when the TranMap was constructed. * Inheritance: * The TranMap class inherits from the Mapping class. * Attributes: * The TranMap class does not define any new attributes beyond those * which are applicable to all Mappings. * Functions: c The TranMap class does not define any new functions beyond those f The TranMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 10-FEB-2004 (DSB): * Original version. * 19-JAN-2005 (DSB): * Fix memory leak. * 14-FEB-2006 (DSB): * - Over-ride the astDecompose method. * - Fix bug in MapSplit related to use of invert flags. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 10-MAY-2006 (DSB): * Override astEqual. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS TranMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate Mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "permmap.h" /* Coordinate permutation Mappings */ #include "cmpmap.h" /* Compound Mappings */ #include "unitmap.h" /* Unit Mappings */ #include "tranmap.h" /* Interface definition for this class */ #include "frame.h" /* Frames */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static int (* parent_getobjsize)( AstObject *, int * ); static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static int *(* parent_mapsplit)( AstMapping *, int, const int *, AstMapping **, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(TranMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(TranMap,Class_Init) #define class_vtab astGLOBAL(TranMap,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstTranMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstTranMap *astTranMapId_( void *, void *, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *RemoveRegions( AstMapping *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static double Rate( AstMapping *, double *, int, int, int * ); static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * ); static int Equal( AstObject *, AstObject *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void Decompose( AstMapping *, AstMapping **, AstMapping **, int *, int *, int *, int * ); static int GetObjSize( AstObject *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two TranMaps are equivalent. * Type: * Private function. * Synopsis: * #include "tranmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * TranMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two TranMaps are equivalent. * Parameters: * this * Pointer to the first Object (a TranMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the TranMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstTranMap *that; AstTranMap *this; int nin; int nout; int result; int that_inv1; int that_inv2; int this_inv1; int this_inv2; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two TranMap structures. */ this = (AstTranMap *) this_object; that = (AstTranMap *) that_object; /* Check the second object is a TranMap. We know the first is a TranMap since we have arrived at this implementation of the virtual function. */ if( astIsATranMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNin( that ) == nin && astGetNout( that ) == nout ) { /* Temporarily re-instate the original Invert flag values. */ that_inv1 = astGetInvert( that->map1 ); that_inv2 = astGetInvert( that->map2 ); this_inv1 = astGetInvert( this->map1 ); this_inv2 = astGetInvert( this->map2 ); astSetInvert( this->map1, this->invert1 ); astSetInvert( this->map2, this->invert2 ); astSetInvert( that->map1, that->invert1 ); astSetInvert( that->map2, that->invert2 ); /* If the Invert flags for the two TranMaps differ, it may still be possible for them to be equivalent. First compare the TranMaps if their Invert flags are the same. In this case all the attributes of the two TranMaps must be identical. */ if( astGetInvert( this ) == astGetInvert( that ) ) { if( astEqual( this->map1, that->map1 ) && astEqual( this->map2, that->map2 ) ) { result = 1; } /* If the Invert flags for the two TranMaps differ, the attributes of the two TranMaps must be inversely related to each other. */ } else { astInvert( that->map1 ); astInvert( that->map2 ); if( astEqual( this->map1, that->map2 ) && astEqual( this->map2, that->map1 ) ) { result = 1; } } /* Restore the original Invert flag values. */ astSetInvert( this->map1, this_inv1 ); astSetInvert( this->map2, this_inv2 ); astSetInvert( that->map1, that_inv1 ); astSetInvert( that->map2, that_inv2 ); } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "tranmap.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * TranMap member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied TranMap, * in bytes. * Parameters: * this * Pointer to the TranMap. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstTranMap *this; /* Pointer to TranMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the TranMap structure. */ this = (AstTranMap *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->map1 ); result += astGetObjSize( this->map2 ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static void Decompose( AstMapping *this_mapping, AstMapping **map1, AstMapping **map2, int *series, int *invert1, int *invert2, int *status ) { /* * * Name: * Decompose * Purpose: * Decompose a Mapping into two component Mappings. * Type: * Private function. * Synopsis: * #include "tranmap.h" * void Decompose( AstMapping *this, AstMapping **map1, * AstMapping **map2, int *series, * int *invert1, int *invert2, int *status ) * Class Membership: * TranMap member function (over-rides the protected astDecompose * method inherited from the Mapping class). * Description: * This function returns pointers to the two Mappings encapsulated by * a TranMap. * Parameters: * this * Pointer to the Mapping. * map1 * Address of a location to receive a pointer to first component * Mapping (the forward Mapping). * map2 * Address of a location to receive a pointer to second component * Mapping (the inverse Mapping). * series * Address of a location to receive a value indicating if the * component Mappings are applied in series or parallel. A non-zero * value means that the supplied Mapping is equivalent to applying map1 * followed by map2 in series. A zero value means that the supplied * Mapping is equivalent to applying map1 to the lower numbered axes * and map2 to the higher numbered axes, in parallel. Zero is * returned for a TranMap. * invert1 * The value of the Invert attribute to be used with map1. * invert2 * The value of the Invert attribute to be used with map2. * status * Pointer to the inherited status variable. * Notes: * - Any changes made to the component Mappings using the returned * pointers will be reflected in the supplied Mapping. *- */ /* Local Variables: */ AstTranMap *this; /* Pointer to TranMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the TranMap structure. */ this = (AstTranMap *) this_mapping; /* If the TranMap has been inverted, return the Mappings in reverse order with inverted Invert falgs. */ if( astGetInvert( this ) ) { if( map1 ) *map1 = astClone( this->map2 ); if( map2 ) *map2 = astClone( this->map1 ); if( invert1 ) *invert1 = this->invert2 ? 0 : 1; if( invert2 ) *invert2 = this->invert1 ? 0 : 1; /* If the TranMap has not been inverted, return the Mappings in their original order with their original Invert flags. */ } else { if( map1 ) *map1 = astClone( this->map1 ); if( map2 ) *map2 = astClone( this->map2 ); if( invert1 ) *invert1 = this->invert1; if( invert2 ) *invert2 = this->invert2; } } void astInitTranMapVtab_( AstTranMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitTranMapVtab * Purpose: * Initialise a virtual function table for a TranMap. * Type: * Protected function. * Synopsis: * #include "tranmap.h" * void astInitTranMapVtab( AstTranMapVtab *vtab, const char *name ) * Class Membership: * TranMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the TranMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsATranMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ /* None. */ /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; mapping->RemoveRegions = RemoveRegions; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_transform = mapping->Transform; mapping->Transform = Transform; parent_mapsplit = mapping->MapSplit; mapping->MapSplit = MapSplit; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->Decompose = Decompose; mapping->MapMerge = MapMerge; mapping->Rate = Rate; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "TranMap", "Compound Transformation Mapping" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * TranMap member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstTranMap *this; /* Pointer to TranMap structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the TranMap structure. */ this = (AstTranMap *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->map1, mode, extra, fail ); if( !result ) result = astManageLock( this->map2, mode, extra, fail ); return result; } #endif static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a TranMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * TranMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated TranMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated TranMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated TranMap which is to be merged with * its neighbours. This should be a cloned copy of the TranMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * TranMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated TranMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstCmpMap *cmap; /* Pointer to compound Mapping */ AstMapping *cmap_f; /* Pointer to compound Mapping */ AstMapping *cmap_i; /* Pointer to compound Mapping */ AstMapping *hmap1; /* Pointer to 1st comp of higher TranMap */ AstMapping *hmap2; /* Pointer to 2nd comp of higher TranMap */ AstMapping *hmap_f; /* Pointer to fwd Mapping of higher TranMap */ AstMapping *hmap_i; /* Pointer to inv Mapping of higher TranMap */ AstMapping *map1; /* Pointer to 1st comp of nominated TranMap */ AstMapping *map2; /* Pointer to 2nd comp of nominated TranMap */ AstMapping *map_f; /* Pointer to fwd Mapping of nominated TranMap */ AstMapping *map_i; /* Pointer to inv Mapping of nominated TranMap */ AstMapping *smap; /* Pointer to simplified Mapping */ AstMapping *smap_f; /* Pointer to simplified Mapping */ AstMapping *smap_i; /* Pointer to simplified Mapping */ AstTranMap *hmap; /* Pointer to higher TranMap */ AstTranMap *map; /* Pointer to this TranMap */ AstTranMap *new; /* Pointer to merged TranMap */ int i; /* Loop count */ int old_hinv1; /* Original Invert flag for hmap->map1 */ int old_hinv2; /* Original Invert flag for hmap->map2 */ int old_inv1; /* Original Invert flag for this->map1 */ int old_inv2; /* Original Invert flag for this->map2 */ int result; /* The value to return */ /* Initialise.*/ result = -1; /* Check the inherited status. */ if ( !astOK ) return result; /* Get a pointer to this TranMap. */ map = (AstTranMap *) this; /* Get the two component Mappings,and temporarily set their Invert attributes back to the values they had when the TranMap was created, saving their current Invert values so that they can be re-instated later. */ map1 = map->map1; old_inv1 = astGetInvert( map1 ); astSetInvert( map1, map->invert1 ); map2 = map->map2; old_inv2 = astGetInvert( map2 ); astSetInvert( map2, map->invert2 ); /* Simplify the TranMap on its own. */ /* ================================ */ /* If the TranMap is inverted, creat an equal TranMap which is not inverted. To do this, invert and swap the component Mappings. */ if( ( *invert_list )[ where ] ) { astInvert( map1 ); astInvert( map2 ); new = astTranMap( map2, map1, "", status ); astInvert( map1 ); astInvert( map2 ); (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) new; ( *invert_list )[ where ] = 0; result = where; /* Otherwise, try to simplify each of the component Mappings. */ } else { smap_f = astSimplify( map1 ); smap_i = astSimplify( map2 ); /* Assume some simplification took place if the pointers have changed. */ if( smap_f != map1 || smap_i != map2 ) { /* Construct a new TranMap from these simplifgied Mappings. */ (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) astTranMap( smap_f, smap_i, "", status ); result = where; /* Otherwise, if the both component Mappings are defined in both directions... */ } else if( astGetTranForward( map1 ) && astGetTranInverse( map1 ) && astGetTranForward( map2 ) && astGetTranInverse( map2 ) ) { /* Form a series CmpMap from the two component Mappings, with the second Mapping inverted. */ astInvert( map2 ); cmap = astCmpMap( map1, map2, 1, "", status ); astInvert( map2 ); /* If this CmpMap simplifies to a UnitMap, then the two components of the TranMap are equal, and so we can replace the entire TranMap with either of its components. Note, we leave the supplied invert flag unchanged, since the copycreated below refers to the Mapping as it was when the TranMap was created. However, we invert the returned Mapping if necessary. */ smap = astSimplify( cmap ); if( astIsAUnitMap( smap ) ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = astCopy( map1 ); if( ( *invert_list )[ where ] ) astInvert( ( *map_list )[ where ] ); result = where; } /* Release resources. */ smap = astAnnul( smap ); cmap = astAnnul( cmap ); } /* Release resources. */ smap_f = astAnnul( smap_f ); smap_i = astAnnul( smap_i ); } /* Merge the TranMap with a neighbouring TranMap. */ /* ============================================== */ /* Only do this if no change was made above, and we are combining the Mappings in series. */ if( result == -1 && series ) { /* Is the higher neighbour a TranMap? */ if( where < ( *nmap - 1 ) && astIsATranMap( ( *map_list )[ where + 1 ] ) ){ /* Get the two component Mappings of the higher TranMap, and temporarily set their Invert attributes back to the values they had when the TranMap was created, saving their current Invert values so that they can be re-instated later. */ hmap = (AstTranMap *) ( *map_list )[ where + 1 ]; hmap1 = hmap->map1; old_hinv1 = astGetInvert( hmap1 ); astSetInvert( hmap1, hmap->invert1 ); hmap2 = hmap->map2; old_hinv2 = astGetInvert( hmap2 ); astSetInvert( hmap2, hmap->invert2 ); /* Get the Mappings which defines the forward and inverse transformation of the lower TranMap ("this"). Then, map_f and map_i are pointers to Mappings which could be used to construct a new TranMap which would be equivalent to "this" with the supplied invert setting. */ if( ( *invert_list )[ where ] ) { map_f = map2; map_i = map1; astInvert( map_f ); astInvert( map_i ); } else { map_f = map1; map_i = map2; } /* Likewise, get the Mappings which defines the forward and inverse transformation of the higher TranMap. */ if( ( *invert_list )[ where + 1 ] ) { hmap_f = hmap2; hmap_i = hmap1; astInvert( hmap_f ); astInvert( hmap_i ); } else { hmap_f = hmap1; hmap_i = hmap2; } /* Combine the two forward Mappings together into a series CmpMap, and simplify it. */ cmap_f = (AstMapping *) astCmpMap( map_f, hmap_f, 1, "", status ); smap_f = astSimplify( cmap_f ); /* Do the same for the inverse Mappings */ cmap_i = (AstMapping *) astCmpMap( map_i, hmap_i, 1, "", status ); smap_i = astSimplify( cmap_i ); /* Was any simplification performed? We assume this is the case if the either of the simplied pointer differs from the original pointer. */ if( cmap_f != smap_f || cmap_i != smap_i ) { /* In which case,construct a new TranMap from the simplified Mappings. */ new = astTranMap( smap_f, smap_i, "", status ); } else { new = NULL; } /* Free resources.*/ cmap_f = astAnnul( cmap_f ); smap_f = astAnnul( smap_f ); cmap_i = astAnnul( cmap_i ); smap_i = astAnnul( smap_i ); /* Re-instate the original Invert values for the component Mappings of the higher TranMap. */ astSetInvert( hmap1, old_hinv1 ); astSetInvert( hmap2, old_hinv2 ); /* If we have a new TranMap, annul the first of the two Mappings, and replace it with the merged TranMap. Also set the invert flag. */ if( new ) { (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) new; ( *invert_list )[ where ] = 0; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ where + 1 ] ); for ( i = where + 2; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = where; } } } /* Re-instate the original Invert values for the component Mappings. */ astSetInvert( map1, old_inv1 ); astSetInvert( map2, old_inv2 ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){ /* * Name: * MapSplit * Purpose: * Create a Mapping representing a subset of the inputs of an existing * TranMap. * Type: * Private function. * Synopsis: * #include "tranmap.h" * int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status ) * Class Membership: * TranMap method (over-rides the protected astMapSplit method * inherited from the Mapping class). * Description: * This function creates a new Mapping by picking specified inputs from * an existing TranMap. This is only possible if the specified inputs * correspond to some subset of the TranMap outputs. That is, there * must exist a subset of the TranMap outputs for which each output * depends only on the selected TranMap inputs, and not on any of the * inputs which have not been selected. If this condition is not met * by the supplied TranMap, then a NULL Mapping is returned. * Parameters: * this * Pointer to the TranMap to be split (the TranMap is not actually * modified by this function). * nin * The number of inputs to pick from "this". * in * Pointer to an array of indices (zero based) for the inputs which * are to be picked. This array should have "nin" elements. If "Nin" * is the number of inputs of the supplied TranMap, then each element * should have a value in the range zero to Nin-1. * map * Address of a location at which to return a pointer to the new * Mapping. This Mapping will have "nin" inputs (the number of * outputs may be different to "nin"). A NULL pointer will be * returned if the supplied TranMap has no subset of outputs which * depend only on the selected inputs. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array of ints. The number of * elements in this array will equal the number of outputs for the * returned Mapping. Each element will hold the index of the * corresponding output in the supplied TranMap. The array should be * freed using astFree when no longer needed. A NULL pointer will * be returned if no output Mapping can be created. * Notes: * - If this function is invoked with the global error status set, * or if it should fail for any reason, then NULL values will be * returned as the function value and for the "map" pointer. */ /* Local Variables: */ AstMapping *fmap; /* Pointer to forward Mapping in supplied TranMap */ AstMapping *imap; /* Pointer to inverse Mapping in supplied TranMap */ AstMapping *rfmap; /* Pointer to split forward Mapping */ AstMapping *rimap; /* Pointer to split inverse Mapping */ AstTranMap *this; /* Pointer to TranMap structure */ int *ires; /* I/ps of inv Mapping dependent on selected o/ps */ int *out; /* O/ps of fwd Mapping dependent on selected i/ps */ int *result; /* Pointer to returned array */ int finv; /* Invert flag to use with fmap */ int i; /* Loop count */ int iinv; /* Invert flag to use with imap */ int nout; /* No. of outputs dependent on selected inputs */ int ok; /* Can required Mapping be created? */ int old_finv; /* Original Invert flag for fmap */ int old_iinv; /* Original Invert flag for imap */ /* Initialise */ result = NULL; *map = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the parent astMapSplit method to see if it can do the job. */ result = (*parent_mapsplit)( this_map, nin, in, map, status ); /* If not, we provide a special implementation here. */ if( !result ) { /* Get a pointer to the TranMap structure. */ this = (AstTranMap *) this_map; /* Get pointers to the forward and inverse Mappings, taking into account whether the TranMap has been inverted. */ if( !astGetInvert( this ) ) { fmap = this->map1; finv = this->invert1; imap = this->map2; iinv = this->invert2; } else { imap = this->map1; iinv = !( this->invert1 ); fmap = this->map2; finv = !( this->invert2 ); } /* Temporarily set the Invert flag of both Mappings back to their original values. */ old_finv = astGetInvert( fmap ); astSetInvert( fmap, finv ); old_iinv = astGetInvert( imap ); astSetInvert( imap, iinv ); /* Try to split the forward Mapping. */ out = astMapSplit( fmap, nin, in, &rfmap ); /* Check the split could be done. */ if( out ) { /* Get the number of outputs which are fed by the selected inputs. */ nout = astGetNout( rfmap ); /* See if the inverse Mapping can be split using these outputs as inputs. */ astInvert( imap ); ires = astMapSplit( imap, nout, out, &rimap ); astInvert( imap ); if( ires ) { astInvert( rimap ); /* Check that the resulting inputs are the same as the supplied inputs. */ if( astGetNin( rimap ) == nin ) { ok = 1; for( i = 0; i < nin; i++ ) { if( in[ i ] != ires[ i ] ) { ok = 0; break; } } /* If so create the required new TranMap. */ if( ok ) { *map = (AstMapping *) astTranMap( rfmap, rimap, "", status ); result = out; } } /* Free resources. */ ires = astFree( ires ); rimap = astAnnul( rimap ); } if( !result ) out = astFree( out ); rfmap = astAnnul( rfmap ); } /* Re-instate the Invert flags of the component Mappings. */ astSetInvert( fmap, old_finv ); astSetInvert( imap, old_iinv ); } /* Free returned resources if an error has occurred. */ if( !astOK ) { result = astFree( result ); *map = astAnnul( *map ); } /* Return the list of output indices. */ return result; } static double Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ){ /* * Name: * Rate * Purpose: * Calculate the rate of change of a Mapping output. * Type: * Private function. * Synopsis: * #include "tranmap.h" * result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status ) * Class Membership: * TranMap member function (overrides the astRate method inherited * from the Mapping class ). * Description: * This function returns the rate of change of a specified output of * the supplied Mapping with respect to a specified input, at a * specified input position. Also evaluates the second derivative. * Parameters: * this * Pointer to the Mapping to be applied. * at * The address of an array holding the axis values at the position * at which the rate of change is to be evaluated. The number of * elements in this array should equal the number of inputs to the * Mapping. * ax1 * The index of the Mapping output for which the rate of change is to * be found (output numbering starts at 0 for the first output). * ax2 * The index of the Mapping input which is to be varied in order to * find the rate of change (input numbering starts at 0 for the first * input). * status * Pointer to the inherited status variable. * Returned Value: * The rate of change of Mapping output "ax1" with respect to input * "ax2", evaluated at "at", or AST__BAD if the value cannot be * calculated. */ /* Local Variables: */ AstTranMap *map; AstMapping *cmap; double result; int cinv; int old_inv; /* Check inherited status */ if( !astOK ) return AST__BAD; /* Get a pointer to the TranMap structure. */ map = (AstTranMap *) this; /* Choose the component Mapping to use, and get its original Invert value. Invert this if the TranMap itself has been inverted (this is because the astRate function has no "invert" argument so we need to invert the Mapping before calling astRate). */ if( astGetInvert( this ) ) { cmap = map->map2; cinv = !(map->invert2); } else { cmap = map->map1; cinv = map->invert1; } /* Temporarily set the Invert flag of the component Mapping back to its original value. */ old_inv = astGetInvert( cmap ); astSetInvert( cmap, cinv ); /* Use the astRate method of the component Mapping. */ result = astRate( cmap, at, ax1, ax2 ); /* Re-instate the Invert flag of the component Mapping. */ astSetInvert( cmap, old_inv ); /* Return the result. */ return result; } static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) { /* * Name: * RemoveRegions * Purpose: * Remove any Regions from a Mapping. * Type: * Private function. * Synopsis: * #include "tranmap.h" * AstMapping *RemoveRegions( AstMapping *this, int *status ) * Class Membership: * TranMap method (over-rides the astRemoveRegions method inherited * from the Mapping class). * Description: * This function searches the supplied Mapping (which may be a * compound Mapping such as a TranMap) for any component Mappings * that are instances of the AST Region class. It then creates a new * Mapping from which all Regions have been removed. If a Region * cannot simply be removed (for instance, if it is a component of a * parallel TranMap), then it is replaced with an equivalent UnitMap * in the returned Mapping. * * The implementation provided by the TranMap class invokes the * astRemoveRegions method on the two component Mappings, and joins * the results together into a new TranMap. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the modified mapping. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. */ /* Local Variables: */ AstTranMap *new; /* Pointer to new TranMap */ AstTranMap *this; /* Pointer to TranMap structure */ AstMapping *newmap1; /* New first component Mapping */ AstMapping *newmap2; /* New second component Mapping */ AstMapping *result; /* Result pointer to return */ int nax; /* Number of Frame axes */ int unit1; /* Is new first Mapping a UnitMap? */ int unit2; /* Is new second Mapping a UnitMap? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the TranMap. */ this = (AstTranMap *) this_mapping; /* Invoke the astRemoveRegions method on the two component Mappings. */ newmap1 = astRemoveRegions( this->map1 ); newmap2 = astRemoveRegions( this->map2 ); /* If neither component was modified, just return a clone of the supplied pointer. */ if( this->map1 == newmap1 && this->map2 == newmap2 ) { result = astClone( this ); /* Otherwise, we need to create a new Mapping to return. */ } else { /* The implementation of the astRemoveRegions method provided by the Region class returns a Frame rather than a UnitMap. But we need Mappings here, not Frames. So if either of these new Mappings is a Frame, replace it with an equivalent UnitMap. Also, get flags indicating if either Mapping is a UnitMap.*/ if( astIsAFrame( newmap1 ) ) { nax = astGetNin( newmap1 ); (void) astAnnul( newmap1 ); newmap1 = (AstMapping *) astUnitMap( nax, " ", status ); unit1 = 1; } else { unit1 = astIsAUnitMap( newmap1 ); } if( astIsAFrame( newmap2 ) ) { nax = astGetNin( newmap2 ); (void) astAnnul( newmap2 ); newmap2 = (AstMapping *) astUnitMap( nax, " ", status ); unit2 = 1; } else { unit2 = astIsAUnitMap( newmap2 ); } /* If both new Mappings are UnitMaps, return an equivalent UnitMap. */ if( unit1 && unit2 ) { result = (AstMapping *) astUnitMap( astGetNin( newmap1 ) + astGetNin( newmap2 ), " ", status ); /* Otherwise, return a new TranMap containing the two new Mappings. */ } else { new = astCopy( this ); (void) astAnnul( new->map1 ); (void) astAnnul( new->map2 ); new->map1 = astClone( newmap1 ); new->map2 = astClone( newmap2 ); result = (AstMapping *) new; } } /* Free resources. */ newmap1 = astAnnul( newmap1 ); newmap2 = astAnnul( newmap2 ); /* Annul the returned Mapping if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a TranMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "tranmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * TranMap member function (over-rides the astTransform method inherited * from the Mapping class). * Description: * This function takes a TranMap and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required Mapping. * This implies applying each of the TranMap's component Mappings in turn, * either in series or in parallel. * Parameters: * this * Pointer to the TranMap. * in * Pointer to the PointSet associated with the input coordinate values. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the TranMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstMapping *cmap; /* Mapping which defines the required transformation */ AstPointSet *result; /* Pointer to output PointSet */ AstTranMap *map; /* Pointer to TranMap to be applied */ int cinv; /* Invert flag when TranMap was created */ int old_inv; /* Invert flag on entry to this function */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the TranMap. */ map = (AstTranMap *) this; /* Apply the parent Mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We now extend the parent astTransform method by applying the component Mappings of the TranMap to generate the output coordinate values. */ /* Determine whether to apply the forward or inverse Mapping, according to the direction specified and whether the Mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* Choose the component Mapping to use, and get its original Invert value. */ if( forward ) { cmap = map->map1; cinv = map->invert1; }else { cmap = map->map2; cinv = map->invert2; } /* Temporarily set the Invert flag of the component Mapping back to its original value. */ old_inv = astGetInvert( cmap ); astSetInvert( cmap, cinv ); /* Use the Transform method of the component Mapping. */ result = astTransform( cmap, in, forward, out ); /* Re-instate the Invert flag of the component Mapping. */ astSetInvert( cmap, old_inv ); /* If an error occurred, clean up by deleting the output PointSet (if allocated by this function) and setting a NULL result pointer. */ if ( !astOK ) { if ( !out ) result = astDelete( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for TranMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for TranMap objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Mappings within the TranMap. */ /* Local Variables: */ AstTranMap *in; /* Pointer to input TranMap */ AstTranMap *out; /* Pointer to output TranMap */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output TranMaps. */ in = (AstTranMap *) objin; out = (AstTranMap *) objout; /* For safety, start by clearing any references to the input component Mappings from the output TranMap. */ out->map1 = NULL; out->map2 = NULL; /* Make copies of these Mappings and store pointers to them in the output TranMap structure. */ out->map1 = astCopy( in->map1 ); out->map2 = astCopy( in->map2 ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for TranMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for TranMap objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstTranMap *this; /* Pointer to TranMap */ /* Obtain a pointer to the TranMap structure. */ this = (AstTranMap *) obj; /* Annul the pointers to the component Mappings. */ this->map1 = astAnnul( this->map1 ); this->map2 = astAnnul( this->map2 ); /* Clear the remaining TranMap variables. */ this->invert1 = 0; this->invert2 = 0; } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for TranMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the TranMap class to an output Channel. * Parameters: * this * Pointer to the TranMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstTranMap *this; /* Pointer to the TranMap structure */ int ival; /* Integer value */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the TranMap structure. */ this = (AstTranMap *) this_object; /* Write out values representing the instance variables for the TranMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* First Invert flag. */ /* ------------------ */ ival = this->invert1; set = ( ival != 0 ); astWriteInt( channel, "InvA", set, 0, ival, ival ? "First Mapping used in inverse direction" : "First Mapping used in forward direction" ); /* Second Invert flag. */ /* ------------------- */ ival = this->invert2; set = ( ival != 0 ); astWriteInt( channel, "InvB", set, 0, ival, ival ? "Second Mapping used in inverse direction" : "Second Mapping used in forward direction" ); /* First Mapping. */ /* -------------- */ astWriteObject( channel, "MapA", 1, 1, this->map1, "Mapping for forward transformation" ); /* Second Mapping. */ /* --------------- */ astWriteObject( channel, "MapB", 1, 1, this->map2, "Mapping for inverse transformation" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsATranMap and astCheckTranMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(TranMap,Mapping) astMAKE_CHECK(TranMap) AstTranMap *astTranMap_( void *map1_void, void *map2_void, const char *options, int *status, ...) { /* *+ * Name: * astTranMap * Purpose: * Create a TranMap. * Type: * Protected function. * Synopsis: * #include "tranmap.h" * AstTranMap *astTranMap( AstMapping *map1, AstMapping *map2, const char *options, int *status, ... ) * Class Membership: * TranMap constructor. * Description: * This function creates a new TranMap and optionally initialises its * attributes. * Parameters: * map1 * Pointer to the first Mapping (which deinfes the forward * transformation). * map2 * Pointer to the second Mapping (which deinfes the inverse * transformation). * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new TranMap. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new TranMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic TranMap constructor which is * available via the protected interface to the TranMap class. A * public interface is provided by the astTranMapId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "map1" and "map2" parameters are of type (void *) and are * converted and validated within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTranMap *new; /* Pointer to new TranMap */ AstMapping *map1; /* Pointer to first Mapping structure */ AstMapping *map2; /* Pointer to second Mapping structure */ va_list args; /* Variable argument list */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return new; /* Obtain and validate pointers to the Mapping structures provided. */ map1 = astCheckMapping( map1_void ); map2 = astCheckMapping( map2_void ); if ( astOK ) { /* Initialise the TranMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitTranMap( NULL, sizeof( AstTranMap ), !class_init, &class_vtab, "TranMap", map1, map2 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new TranMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new TranMap. */ return new; } AstTranMap *astTranMapId_( void *map1_void, void *map2_void, const char *options, ... ) { /* *++ * Name: c astTranMap f AST_TRANMAP * Purpose: * Create a TranMap. * Type: * Public function. * Synopsis: c #include "tranmap.h" c AstTranMap *astTranMap( AstMapping *map1, AstMapping *map2, c const char *options, ... ) f RESULT = AST_TRANMAP( MAP1, MAP2, OPTIONS, STATUS ) * Class Membership: * TranMap constructor. * Description: * This function creates a new TranMap and optionally initialises * its attributes. * * A TranMap is a Mapping which combines the forward transformation of * a supplied Mapping with the inverse transformation of another * supplied Mapping, ignoring the un-used transformation in each * Mapping (indeed the un-used transformation need not exist). * * When the forward transformation of the TranMap is referred to, the * transformation actually used is the forward transformation of the * first Mapping supplied when the TranMap was constructed. Likewise, * when the inverse transformation of the TranMap is referred to, the * transformation actually used is the inverse transformation of the * second Mapping supplied when the TranMap was constructed. * Parameters: c map1 f MAP1 = INTEGER (Given) * Pointer to the first component Mapping, which defines the * forward transformation. c map2 f MAP2 = INTEGER (Given) * Pointer to the second component Mapping, which defines the * inverse transformation. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new TranMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new TranMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astTranMap() f AST_TRANMAP = INTEGER * A pointer to the new TranMap. * Notes: * - The number of output coordinates generated by the two Mappings * (their Nout attribute) must be equal, as must the number of input * coordinates accepted by each Mapping (their Nin attribute). * - The forward transformation of the first Mapping must exist. * - The inverse transformation of the second Mapping must exist. c - Note that the component Mappings supplied are not copied by c astTranMap (the new TranMap simply retains a reference to c them). They may continue to be used for other purposes, but c should not be deleted. If a TranMap containing a copy of its c component Mappings is required, then a copy of the TranMap should c be made using astCopy. f - Note that the component Mappings supplied are not copied by f AST_TRANMAP (the new TranMap simply retains a reference to f them). They may continue to be used for other purposes, but f should not be deleted. If a TranMap containing a copy of its f component Mappings is required, then a copy of the TranMap should f be made using AST_COPY. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- * Implementation Notes: * - This function implements the external (public) interface to * the astTranMap constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astTranMap_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - Because no checking or casting of arguments is performed * before the function is invoked, the "map1" and "map2" parameters * are of type (void *) and are converted from an ID value to a * pointer and validated within the function itself. * - The variable argument list also prevents this function from * invoking astTranMap_ directly, so it must be a re-implementation * of it in all respects, except for the conversions between IDs * and pointers on input/output of Objects. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTranMap *new; /* Pointer to new TranMap */ AstMapping *map1; /* Pointer to first Mapping structure */ AstMapping *map2; /* Pointer to second Mapping structure */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = NULL; /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return new; /* Obtain the Mapping pointers from the ID's supplied and validate the pointers to ensure they identify valid Mappings. */ map1 = astVerifyMapping( astMakePointer( map1_void ) ); map2 = astVerifyMapping( astMakePointer( map2_void ) ); if ( astOK ) { /* Initialise the TranMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitTranMap( NULL, sizeof( AstTranMap ), !class_init, &class_vtab, "TranMap", map1, map2 ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new TranMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return an ID value for the new TranMap. */ return astMakeId( new ); } AstTranMap *astInitTranMap_( void *mem, size_t size, int init, AstTranMapVtab *vtab, const char *name, AstMapping *map1, AstMapping *map2, int *status ) { /* *+ * Name: * astInitTranMap * Purpose: * Initialise a TranMap. * Type: * Protected function. * Synopsis: * #include "tranmap.h" * AstTranMap *astInitTranMap( void *mem, size_t size, int init, * AstTranMapVtab *vtab, const char *name, * AstMapping *map1, AstMapping *map2 ) * Class Membership: * TranMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new TranMap object. It allocates memory (if necessary) to * accommodate the TranMap plus any additional data associated with the * derived class. It then initialises a TranMap structure at the start * of this memory. If the "init" flag is set, it also initialises the * contents of a virtual function table for a TranMap at the start of * the memory passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the TranMap is to be initialised. * This must be of sufficient size to accommodate the TranMap data * (sizeof(TranMap)) plus any data used by the derived class. If a * value of NULL is given, this function will allocate the memory itself * using the "size" parameter to determine its size. * size * The amount of memory used by the TranMap (plus derived class * data). This will be used to allocate memory if a value of NULL is * given for the "mem" parameter. This value is also stored in the * TranMap structure, so a valid value must be supplied even if not * required for allocating memory. * init * A logical flag indicating if the TranMap's virtual function table * is to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new TranMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * map1 * Pointer to the first Mapping. * map2 * Pointer to the second Mapping. * Returned Value: * A pointer to the new TranMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstTranMap *new; /* Pointer to new TranMap */ int nin; /* No. input coordinates for TranMap */ int nout; /* No. output coordinates for TranMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitTranMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Report an error if map1 has no forward transformation. */ if( !astGetTranForward( map1 ) && astOK ) { astError( AST__INTRD, "astInitTranMap(%s): The first supplied Mapping " "is not able to transform coordinates in the forward direction.", status, name ); } /* Report an error if map2 has no inverse transformation. */ if( !astGetTranInverse( map2 ) && astOK ) { astError( AST__INTRD, "astInitTranMap(%s): The second supplied Mapping " "is not able to transform coordinates in the inverse direction.", status, name ); } /* Check that the number of coordinates are compatible and report an error if they are not. */ nout = astGetNout( map1 ); if ( astGetNout( map2 ) != nout && astOK ) { astError( AST__INNCO, "astInitTranMap(%s): The number of output " "coordinates per point (%d) for the first Mapping " "supplied does not match the number of output " "coordinates (%d) for the second Mapping.", status, name, nout, astGetNout( map2 ) ); } nin = astGetNin( map1 ); if ( astGetNin( map2 ) != nin && astOK ) { astError( AST__INNCO, "astInitTranMap(%s): The number of input " "coordinates per point (%d) for the first Mapping " "supplied does not match the number of input " "coordinates (%d) for the second Mapping.", status, name, nin, astGetNin( map2 ) ); } /* Initialise a Mapping structure (the parent class) as the first component within the TranMap structure, allocating memory if necessary. Specify the number of input and output coordinates and in which directions the Mapping should be defined. */ if ( astOK ) { new = (AstTranMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, nin, nout, 1, 1 ); if ( astOK ) { /* Initialise the TranMap data. */ /* --------------------------- */ /* Store pointers to the component Mappings. */ new->map1 = astClone( map1 ); new->map2 = astClone( map2 ); /* Save the initial values of the inversion flags for these Mappings. */ new->invert1 = astGetInvert( map1 ); new->invert2 = astGetInvert( map2 ); /* If an error occurred, clean up by annulling the Mapping pointers and deleting the new object. */ if ( !astOK ) { new->map1 = astAnnul( new->map1 ); new->map2 = astAnnul( new->map2 ); new = astDelete( new ); } } } /* Return a pointer to the new object. */ return new; } AstTranMap *astLoadTranMap_( void *mem, size_t size, AstTranMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadTranMap * Purpose: * Load a TranMap. * Type: * Protected function. * Synopsis: * #include "tranmap.h" * AstTranMap *astLoadTranMap( void *mem, size_t size, * AstTranMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * TranMap loader. * Description: * This function is provided to load a new TranMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * TranMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a TranMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the TranMap is to be * loaded. This must be of sufficient size to accommodate the * TranMap data (sizeof(TranMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the TranMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the TranMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstTranMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new TranMap. If this is NULL, a pointer to * the (static) virtual function table for the TranMap class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "TranMap" is used instead. * Returned Value: * A pointer to the new TranMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstTranMap *new; /* Pointer to the new TranMap */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this TranMap. In this case the TranMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstTranMap ); vtab = &class_vtab; name = "TranMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitTranMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built TranMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "TranMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* First Invert flag. */ /* ------------------ */ new->invert1 = astReadInt( channel, "inva", 0 ); new->invert1 = ( new->invert1 != 0 ); /* Second Invert flag. */ /* ------------------- */ new->invert2 = astReadInt( channel, "invb", 0 ); new->invert2 = ( new->invert2 != 0 ); /* First Mapping. */ /* -------------- */ new->map1 = astReadObject( channel, "mapa", NULL ); /* Second Mapping. */ /* --------------- */ new->map2 = astReadObject( channel, "mapb", NULL ); /* If an error occurred, clean up by deleting the new TranMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new TranMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ /* None. */ ./ast-7.3.3/proj.c0000644000175000017500000031725612262533650012276 0ustar olesoles/*============================================================================ * * WCSLIB - an implementation of the FITS WCS proposal. * Copyright (C) 1995-2002, Mark Calabretta * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library 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 Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street,Fifth Floor, Boston, MA 02110-1301, USA * * Correspondence concerning WCSLIB may be directed to: * Internet email: mcalabre@atnf.csiro.au * Postal address: Dr. Mark Calabretta, * Australia Telescope National Facility, * P.O. Box 76, * Epping, NSW, 2121, * AUSTRALIA * * *============================================================================= * * This version of proj.c is based on the version in wcslib-2.9, but has * been modified in the following ways by the Starlink project (e-mail: * ussc@star.rl.ac.uk): * - The copysign macro is now always defined within this file * instead of only being defined if the COPYSIGN macro has previously * been defined. * - Sine values which are slightly larger than 1.0 are now treated * as 1.0 in function astCYPrev. * - The maximum number of projection parameters has been changed from * 10 to 100. * - The maximum number of projection parameters is given by the * WCSLIB_MXPAR macro (defined in proj.h) instead of being hard-wired. * - The names of all functions and structures have been chanegd to avoid * clashes with wcslib. This involves adding "Ast" or "ast" at the * front and changing the capitalisation. * - Include string.h (for strcpy and strcmp prototypes). * - Include stdlib.h (for abs prototype). * - Comment out declarations of npcode and pcodes variables (they * are not needed by AST) in order to avoid clash with similar names * in other modules imported as part of other software systems (e.g. * SkyCat). * - astZPNfwd: Loop from prj->n to zero, not from MAXPAR to zero. * - astZPNfwd: Only return "2" if prj->n is larger than 2. * - Lots of variables are initialised to null values in order to * avoid "use of uninitialised variable" messages from compilers which * are not clever enough to work out that the uninitialised variable is * not in fact ever used. * - Use dynamic rather than static memory for the parameter arrays in * the AstPrjPrm structure.Override astGetObjSize. This is to * reduce the in-memory size of a WcsMap. * - Healpix projection added. * - The expressions for xc in astHPXrev and phic in astHPXfwd have * been conditioned differently to the WCSLIB code in order to improve * accuracy of the floor function for arguments very slightly below an * integer value. *============================================================================= * * C implementation of the spherical map projections recognized by the FITS * "World Coordinate System" (WCS) convention. * * Summary of routines * ------------------- * Each projection is implemented via separate functions for the forward, * *fwd(), and reverse, *rev(), transformation. * * Initialization routines, *set(), compute intermediate values from the * projection parameters but need not be called explicitly - see the * explanation of prj.flag below. * * astPRJset astPRJfwd astPRJrev Driver routines (see below). * * astAZPset astAZPfwd astAZPrev AZP: zenithal/azimuthal perspective * astSZPset astSZPfwd astSZPrev SZP: slant zenithal perspective * astTANset astTANfwd astTANrev TAN: gnomonic * astSTGset astSTGfwd astSTGrev STG: stereographic * astSINset astSINfwd astSINrev SIN: orthographic/synthesis * astARCset astARCfwd astARCrev ARC: zenithal/azimuthal equidistant * astZPNset astZPNfwd astZPNrev ZPN: zenithal/azimuthal polynomial * astZEAset astZEAfwd astZEArev ZEA: zenithal/azimuthal equal area * astAIRset astAIRfwd astAIRrev AIR: Airy * astCYPset astCYPfwd astCYPrev CYP: cylindrical perspective * astCEAset astCEAfwd astCEArev CEA: cylindrical equal area * astCARset astCARfwd astCARrev CAR: Cartesian * astMERset astMERfwd astMERrev MER: Mercator * astSFLset astSFLfwd astSFLrev SFL: Sanson-Flamsteed * astPARset astPARfwd astPARrev PAR: parabolic * astMOLset astMOLfwd astMOLrev MOL: Mollweide * astAITset astAITfwd astAITrev AIT: Hammer-Aitoff * astCOPset astCOPfwd astCOPrev COP: conic perspective * astCOEset astCOEfwd astCOErev COE: conic equal area * astCODset astCODfwd astCODrev COD: conic equidistant * astCOOset astCOOfwd astCOOrev COO: conic orthomorphic * astBONset astBONfwd astBONrev BON: Bonne * astPCOset astPCOfwd astPCOrev PCO: polyconic * astTSCset astTSCfwd astTSCrev TSC: tangential spherical cube * astCSCset astCSCfwd astCSCrev CSC: COBE quadrilateralized spherical cube * astQSCset astQSCfwd astQSCrev QSC: quadrilateralized spherical cube * astHPXset astHPXfwd astHPXrev HPX: HEALPix projection * * * Driver routines; astPRJset(), astPRJfwd() & astPRJrev() * ---------------------------------------------- * A set of driver routines are available for use as a generic interface to * the specific projection routines. The interfaces to astPRJfwd() and astPRJrev() * are the same as those of the forward and reverse transformation routines * for the specific projections (see below). * * The interface to astPRJset() differs slightly from that of the initialization * routines for the specific projections and unlike them it must be invoked * explicitly to use astPRJfwd() and astPRJrev(). * * Given: * pcode[4] const char * WCS projection code. * * Given and/or returned: * prj AstPrjPrm* Projection parameters (see below). * * Function return value: * int Error status * 0: Success. * * * Initialization routine; *set() * ------------------------------ * Initializes members of a AstPrjPrm data structure which hold intermediate * values. Note that this routine need not be called directly; it will be * invoked by astPRJfwd() and astPRJrev() if the "flag" structure member is * anything other than a predefined magic value. * * Given and/or returned: * prj AstPrjPrm* Projection parameters (see below). * * Function return value: * int Error status * 0: Success. * 1: Invalid projection parameters. * * Forward transformation; *fwd() * ----------------------------- * Compute (x,y) coordinates in the plane of projection from native spherical * coordinates (phi,theta). * * Given: * phi, const double * theta Longitude and latitude of the projected point in * native spherical coordinates, in degrees. * * Given and returned: * prj AstPrjPrm* Projection parameters (see below). * * Returned: * x,y double* Projected coordinates. * * Function return value: * int Error status * 0: Success. * 1: Invalid projection parameters. * 2: Invalid value of (phi,theta). * * Reverse transformation; *rev() * ----------------------------- * Compute native spherical coordinates (phi,theta) from (x,y) coordinates in * the plane of projection. * * Given: * x,y const double * Projected coordinates. * * Given and returned: * prj AstPrjPrm* Projection parameters (see below). * * Returned: * phi, double* Longitude and latitude of the projected point in * theta native spherical coordinates, in degrees. * * Function return value: * int Error status * 0: Success. * 1: Invalid projection parameters. * 2: Invalid value of (x,y). * 1: Invalid projection parameters. * * Projection parameters * --------------------- * The AstPrjPrm struct consists of the following: * * int flag * This flag must be set to zero whenever any of p[] or r0 are set * or changed. This signals the initialization routine to recompute * intermediaries. flag may also be set to -1 to disable strict bounds * checking for the AZP, SZP, TAN, SIN, ZPN, and COP projections. * * double r0 * r0; The radius of the generating sphere for the projection, a linear * scaling parameter. If this is zero, it will be reset to the default * value of 180/pi (the value for FITS WCS). * * double p[] * Contains the projection parameters associated with the * longitude axis. * * The remaining members of the AstPrjPrm struct are maintained by the * initialization routines and should not be modified. This is done for the * sake of efficiency and to allow an arbitrary number of contexts to be * maintained simultaneously. * * char code[4] * Three-letter projection code. * * double phi0, theta0 * Native longitude and latitude of the reference point, in degrees. * * double w[10] * int n * Intermediate values derived from the projection parameters. * * int (*astPRJfwd)() * int (*astPRJrev)() * Pointers to the forward and reverse projection routines. * * Usage of the p[] array as it applies to each projection is described in * the prologue to each trio of projection routines. * * Argument checking * ----------------- * Forward routines: * * The values of phi and theta (the native longitude and latitude) * normally lie in the range [-180,180] for phi, and [-90,90] for theta. * However, all forward projections will accept any value of phi and will * not normalize it. * * The forward projection routines do not explicitly check that theta lies * within the range [-90,90]. They do check for any value of theta which * produces an invalid argument to the projection equations (e.g. leading * to division by zero). The forward routines for AZP, SZP, TAN, SIN, * ZPN, and COP also return error 2 if (phi,theta) corresponds to the * overlapped (far) side of the projection but also return the * corresponding value of (x,y). This strict bounds checking may be * relaxed by setting prj->flag to -1 (rather than 0) when these * projections are initialized. * * Reverse routines: * * Error checking on the projected coordinates (x,y) is limited to that * required to ascertain whether a solution exists. Where a solution does * exist no check is made that the value of phi and theta obtained lie * within the ranges [-180,180] for phi, and [-90,90] for theta. * * Accuracy * -------- * Closure to a precision of at least 1E-10 degree of longitude and latitude * has been verified for typical projection parameters on the 1 degree grid * of native longitude and latitude (to within 5 degrees of any latitude * where the projection may diverge). * * Author: Mark Calabretta, Australia Telescope National Facility * $Id$ *===========================================================================*/ /* Set the name of the module we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. NB, this module is not a proper AST class, but it defines this macro sanyway in order to get the protected symbols defined in memory.h */ #include #include #include #include "wcsmath.h" #include "wcstrig.h" #include "memory.h" #include "proj.h" /* Following variables are not needed in AST and are commented out to avoid name clashes with other software systems (e.g. SkyCat) which defines them. int npcode = 26; char pcodes[26][4] = {"AZP", "SZP", "TAN", "STG", "SIN", "ARC", "ZPN", "ZEA", "AIR", "CYP", "CEA", "CAR", "MER", "COP", "COE", "COD", "COO", "SFL", "PAR", "MOL", "AIT", "BON", "PCO", "TSC", "CSC", "QSC", "HPX"}; */ const int WCS__AZP = 101; const int WCS__SZP = 102; const int WCS__TAN = 103; const int WCS__STG = 104; const int WCS__SIN = 105; const int WCS__ARC = 106; const int WCS__ZPN = 107; const int WCS__ZEA = 108; const int WCS__AIR = 109; const int WCS__CYP = 201; const int WCS__CEA = 202; const int WCS__CAR = 203; const int WCS__MER = 204; const int WCS__SFL = 301; const int WCS__PAR = 302; const int WCS__MOL = 303; const int WCS__AIT = 401; const int WCS__COP = 501; const int WCS__COE = 502; const int WCS__COD = 503; const int WCS__COO = 504; const int WCS__BON = 601; const int WCS__PCO = 602; const int WCS__TSC = 701; const int WCS__CSC = 702; const int WCS__QSC = 703; const int WCS__HPX = 801; /* Map error number to error message for each function. */ const char *astPRJset_errmsg[] = { 0, "Invalid projection parameters"}; const char *astPRJfwd_errmsg[] = { 0, "Invalid projection parameters", "Invalid value of (phi,theta)"}; const char *astPRJrev_errmsg[] = { 0, "Invalid projection parameters", "Invalid value of (x,y)"}; #define copysign(X, Y) ((Y) < 0.0 ? -fabs(X) : fabs(X)) /*==========================================================================*/ int astPRJset(pcode, prj) const char pcode[4]; struct AstPrjPrm *prj; { /* Set pointers to the forward and reverse projection routines. */ if (strcmp(pcode, "AZP") == 0) { astAZPset(prj); } else if (strcmp(pcode, "SZP") == 0) { astSZPset(prj); } else if (strcmp(pcode, "TAN") == 0) { astTANset(prj); } else if (strcmp(pcode, "STG") == 0) { astSTGset(prj); } else if (strcmp(pcode, "SIN") == 0) { astSINset(prj); } else if (strcmp(pcode, "ARC") == 0) { astARCset(prj); } else if (strcmp(pcode, "ZPN") == 0) { astZPNset(prj); } else if (strcmp(pcode, "ZEA") == 0) { astZEAset(prj); } else if (strcmp(pcode, "AIR") == 0) { astAIRset(prj); } else if (strcmp(pcode, "CYP") == 0) { astCYPset(prj); } else if (strcmp(pcode, "CEA") == 0) { astCEAset(prj); } else if (strcmp(pcode, "CAR") == 0) { astCARset(prj); } else if (strcmp(pcode, "MER") == 0) { astMERset(prj); } else if (strcmp(pcode, "SFL") == 0) { astSFLset(prj); } else if (strcmp(pcode, "PAR") == 0) { astPARset(prj); } else if (strcmp(pcode, "MOL") == 0) { astMOLset(prj); } else if (strcmp(pcode, "AIT") == 0) { astAITset(prj); } else if (strcmp(pcode, "COP") == 0) { astCOPset(prj); } else if (strcmp(pcode, "COE") == 0) { astCOEset(prj); } else if (strcmp(pcode, "COD") == 0) { astCODset(prj); } else if (strcmp(pcode, "COO") == 0) { astCOOset(prj); } else if (strcmp(pcode, "BON") == 0) { astBONset(prj); } else if (strcmp(pcode, "PCO") == 0) { astPCOset(prj); } else if (strcmp(pcode, "TSC") == 0) { astTSCset(prj); } else if (strcmp(pcode, "CSC") == 0) { astCSCset(prj); } else if (strcmp(pcode, "QSC") == 0) { astQSCset(prj); } else if (strcmp(pcode, "HPX") == 0) { astHPXset(prj); } else { /* Unrecognized projection code. */ return 1; } return 0; } /*--------------------------------------------------------------------------*/ int astPRJfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { return prj->astPRJfwd(phi, theta, prj, x, y); } /*--------------------------------------------------------------------------*/ int astPRJrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { return prj->astPRJrev(x, y, prj, phi, theta); } /*============================================================================ * AZP: zenithal/azimuthal perspective projection. * * Given: * prj->p[1] Distance parameter, mu in units of r0. * prj->p[2] Tilt angle, gamma in degrees. * * Given and/or returned: * prj->flag AZP, or -AZP if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "AZP" * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] r0*(mu+1) * prj->w[1] tan(gamma) * prj->w[2] sec(gamma) * prj->w[3] cos(gamma) * prj->w[4] sin(gamma) * prj->w[5] asin(-1/mu) for |mu| >= 1, -90 otherwise * prj->w[6] mu*cos(gamma) * prj->w[7] 1 if |mu*cos(gamma)| < 1, 0 otherwise * prj->astPRJfwd Pointer to astAZPfwd(). * prj->astPRJrev Pointer to astAZPrev(). *===========================================================================*/ int astAZPset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "AZP"); prj->flag = copysign(WCS__AZP, prj->flag); prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = prj->r0*(prj->p[1] + 1.0); if (prj->w[0] == 0.0) { return 1; } prj->w[3] = astCosd(prj->p[2]); if (prj->w[3] == 0.0) { return 1; } prj->w[2] = 1.0/prj->w[3]; prj->w[4] = astSind(prj->p[2]); prj->w[1] = prj->w[4] / prj->w[3]; if (fabs(prj->p[1]) > 1.0) { prj->w[5] = astASind(-1.0/prj->p[1]); } else { prj->w[5] = -90.0; } prj->w[6] = prj->p[1] * prj->w[3]; prj->w[7] = (fabs(prj->w[6]) < 1.0) ? 1.0 : 0.0; prj->astPRJfwd = astAZPfwd; prj->astPRJrev = astAZPrev; return 0; } /*--------------------------------------------------------------------------*/ int astAZPfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, b, cphi, cthe, r, s, t; if (abs(prj->flag) != WCS__AZP) { if (astAZPset(prj)) return 1; } cphi = astCosd(phi); cthe = astCosd(theta); s = prj->w[1]*cphi; t = (prj->p[1] + astSind(theta)) + cthe*s; if (t == 0.0) { return 2; } r = prj->w[0]*cthe/t; *x = r*astSind(phi); *y = -r*cphi*prj->w[2]; /* Bounds checking. */ if (prj->flag > 0) { /* Overlap. */ if (theta < prj->w[5]) { return 2; } /* Divergence. */ if (prj->w[7] > 0.0) { t = prj->p[1] / sqrt(1.0 + s*s); if (fabs(t) <= 1.0) { s = astATand(-s); t = astASind(t); a = s - t; b = s + t + 180.0; if (a > 90.0) a -= 360.0; if (b > 90.0) b -= 360.0; if (theta < ((a > b) ? a : b)) { return 2; } } } } return 0; } /*--------------------------------------------------------------------------*/ int astAZPrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, b, r, s, t, ycosg; const double tol = 1.0e-13; if (abs(prj->flag) != WCS__AZP) { if (astAZPset(prj)) return 1; } ycosg = y*prj->w[3]; r = sqrt(x*x + ycosg*ycosg); if (r == 0.0) { *phi = 0.0; *theta = 90.0; } else { *phi = astATan2d(x, -ycosg); s = r / (prj->w[0] + y*prj->w[4]); t = s*prj->p[1]/sqrt(s*s + 1.0); s = astATan2d(1.0, s); if (fabs(t) > 1.0) { t = copysign(90.0,t); if (fabs(t) > 1.0+tol) { return 2; } } else { t = astASind(t); } a = s - t; b = s + t + 180.0; if (a > 90.0) a -= 360.0; if (b > 90.0) b -= 360.0; *theta = (a > b) ? a : b; } return 0; } /*============================================================================ * SZP: slant zenithal perspective projection. * * Given: * prj->p[1] Distance of the point of projection from the centre of the * generating sphere, mu in units of r0. * prj->p[2] Native longitude, phi_c, and ... * prj->p[3] Native latitude, theta_c, on the planewards side of the * intersection of the line through the point of projection * and the centre of the generating sphere, phi_c in degrees. * * Given and/or returned: * prj->flag SZP, or -SZP if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "SZP" * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] 1/r0 * prj->w[1] xp = -mu*cos(theta_c)*sin(phi_c) * prj->w[2] yp = mu*cos(theta_c)*cos(phi_c) * prj->w[3] zp = mu*sin(theta_c) + 1 * prj->w[4] r0*xp * prj->w[5] r0*yp * prj->w[6] r0*zp * prj->w[7] (zp - 1)^2 * prj->w[8] asin(1-zp) if |1 - zp| < 1, -90 otherwise * prj->astPRJfwd Pointer to astSZPfwd(). * prj->astPRJrev Pointer to astSZPrev(). *===========================================================================*/ int astSZPset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "SZP"); prj->flag = copysign(WCS__SZP, prj->flag); prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = 1.0/prj->r0; prj->w[3] = prj->p[1] * astSind(prj->p[3]) + 1.0; if (prj->w[3] == 0.0) { return 1; } prj->w[1] = -prj->p[1] * astCosd(prj->p[3]) * astSind(prj->p[2]); prj->w[2] = prj->p[1] * astCosd(prj->p[3]) * astCosd(prj->p[2]); prj->w[4] = prj->r0 * prj->w[1]; prj->w[5] = prj->r0 * prj->w[2]; prj->w[6] = prj->r0 * prj->w[3]; prj->w[7] = (prj->w[3] - 1.0) * prj->w[3] - 1.0; if (fabs(prj->w[3] - 1.0) < 1.0) { prj->w[8] = astASind(1.0 - prj->w[3]); } else { prj->w[8] = -90.0; } prj->astPRJfwd = astSZPfwd; prj->astPRJrev = astSZPrev; return 0; } /*--------------------------------------------------------------------------*/ int astSZPfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, b, cphi, cthe, s, sphi, t; if (abs(prj->flag) != WCS__SZP) { if (astSZPset(prj)) return 1; } cphi = astCosd(phi); sphi = astSind(phi); cthe = astCosd(theta); s = 1.0 - astSind(theta); t = prj->w[3] - s; if (t == 0.0) { return 2; } *x = (prj->w[6]*cthe*sphi - prj->w[4]*s)/t; *y = -(prj->w[6]*cthe*cphi + prj->w[5]*s)/t; /* Bounds checking. */ if (prj->flag > 0) { /* Divergence. */ if (theta < prj->w[8]) { return 2; } /* Overlap. */ if (fabs(prj->p[1]) > 1.0) { s = prj->w[1]*sphi - prj->w[2]*cphi; t = 1.0/sqrt(prj->w[7] + s*s); if (fabs(t) <= 1.0) { s = astATan2d(s, prj->w[3] - 1.0); t = astASind(t); a = s - t; b = s + t + 180.0; if (a > 90.0) a -= 360.0; if (b > 90.0) b -= 360.0; if (theta < ((a > b) ? a : b)) { return 2; } } } } return 0; } /*--------------------------------------------------------------------------*/ int astSZPrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, b, c, d, r2, sth1, sth2, sthe, sxy, t, x1, xp, y1, yp, z; const double tol = 1.0e-13; if (abs(prj->flag) != WCS__SZP) { if (astSZPset(prj)) return 1; } xp = x*prj->w[0]; yp = y*prj->w[0]; r2 = xp*xp + yp*yp; x1 = (xp - prj->w[1])/prj->w[3]; y1 = (yp - prj->w[2])/prj->w[3]; sxy = xp*x1 + yp*y1; if (r2 < 1.0e-10) { /* Use small angle formula. */ z = r2/2.0; *theta = 90.0 - R2D*sqrt(r2/(1.0 + sxy)); } else { t = x1*x1 + y1*y1; a = t + 1.0; b = sxy - t; c = r2 - sxy - sxy + t - 1.0; d = b*b - a*c; /* Check for a solution. */ if (d < 0.0) { return 2; } d = sqrt(d); /* Choose solution closest to pole. */ sth1 = (-b + d)/a; sth2 = (-b - d)/a; sthe = (sth1 > sth2) ? sth1 : sth2; if (sthe > 1.0) { if (sthe-1.0 < tol) { sthe = 1.0; } else { sthe = (sth1 < sth2) ? sth1 : sth2; } } if (sthe < -1.0) { if (sthe+1.0 > -tol) { sthe = -1.0; } } if (sthe > 1.0 || sthe < -1.0) { return 2; } *theta = astASind(sthe); z = 1.0 - sthe; } *phi = astATan2d(xp - x1*z, -(yp - y1*z)); return 0; } /*============================================================================ * TAN: gnomonic projection. * * Given and/or returned: * prj->flag TAN, or -TAN if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "TAN" * prj->phi0 0.0 * prj->theta0 90.0 * prj->astPRJfwd Pointer to astTANfwd(). * prj->astPRJrev Pointer to astTANrev(). *===========================================================================*/ int astTANset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "TAN"); prj->flag = copysign(WCS__TAN, prj->flag); prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->astPRJfwd = astTANfwd; prj->astPRJrev = astTANrev; return 0; } /*--------------------------------------------------------------------------*/ int astTANfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double r, s; if (abs(prj->flag) != WCS__TAN) { if(astTANset(prj)) return 1; } s = astSind(theta); if (s == 0.0) { return 2; } r = prj->r0*astCosd(theta)/s; *x = r*astSind(phi); *y = -r*astCosd(phi); if (prj->flag > 0 && s < 0.0) { return 2; } return 0; } /*--------------------------------------------------------------------------*/ int astTANrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double r; if (abs(prj->flag) != WCS__TAN) { if (astTANset(prj)) return 1; } r = sqrt(x*x + y*y); if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } *theta = astATan2d(prj->r0, r); return 0; } /*============================================================================ * STG: stereographic projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "STG" * prj->flag STG * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] 2*r0 * prj->w[1] 1/(2*r0) * prj->astPRJfwd Pointer to astSTGfwd(). * prj->astPRJrev Pointer to astSTGrev(). *===========================================================================*/ int astSTGset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "STG"); prj->flag = WCS__STG; prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 360.0/PI; prj->w[1] = PI/360.0; } else { prj->w[0] = 2.0*prj->r0; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astSTGfwd; prj->astPRJrev = astSTGrev; return 0; } /*--------------------------------------------------------------------------*/ int astSTGfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double r, s; if (prj->flag != WCS__STG) { if (astSTGset(prj)) return 1; } s = 1.0 + astSind(theta); if (s == 0.0) { return 2; } r = prj->w[0]*astCosd(theta)/s; *x = r*astSind(phi); *y = -r*astCosd(phi); return 0; } /*--------------------------------------------------------------------------*/ int astSTGrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double r; if (prj->flag != WCS__STG) { if (astSTGset(prj)) return 1; } r = sqrt(x*x + y*y); if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } *theta = 90.0 - 2.0*astATand(r*prj->w[1]); return 0; } /*============================================================================ * SIN: orthographic/synthesis projection. * * Given: * prj->p[1:2] Obliqueness parameters, xi and eta. * * Given and/or returned: * prj->flag SIN, or -SIN if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "SIN" * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] 1/r0 * prj->w[1] xi**2 + eta**2 * prj->w[2] xi**2 + eta**2 + 1 * prj->w[3] xi**2 + eta**2 - 1 * prj->astPRJfwd Pointer to astSINfwd(). * prj->astPRJrev Pointer to astSINrev(). *===========================================================================*/ int astSINset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "SIN"); prj->flag = copysign(WCS__SIN, prj->flag); prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = 1.0/prj->r0; prj->w[1] = prj->p[1]*prj->p[1] + prj->p[2]*prj->p[2]; prj->w[2] = prj->w[1] + 1.0; prj->w[3] = prj->w[1] - 1.0; prj->astPRJfwd = astSINfwd; prj->astPRJrev = astSINrev; return 0; } /*--------------------------------------------------------------------------*/ int astSINfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double cphi, cthe, sphi, t, z; if (abs(prj->flag) != WCS__SIN) { if (astSINset(prj)) return 1; } t = (90.0 - fabs(theta))*D2R; if (t < 1.0e-5) { if (theta > 0.0) { z = t*t/2.0; } else { z = 2.0 - t*t/2.0; } cthe = t; } else { z = 1.0 - astSind(theta); cthe = astCosd(theta); } cphi = astCosd(phi); sphi = astSind(phi); *x = prj->r0*(cthe*sphi + prj->p[1]*z); *y = -prj->r0*(cthe*cphi - prj->p[2]*z); /* Validate this solution. */ if (prj->flag > 0) { if (prj->w[1] == 0.0) { /* Orthographic projection. */ if (theta < 0.0) { return 2; } } else { /* "Synthesis" projection. */ t = -astATand(prj->p[1]*sphi - prj->p[2]*cphi); if (theta < t) { return 2; } } } return 0; } /*--------------------------------------------------------------------------*/ int astSINrev (x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { const double tol = 1.0e-13; double a, b, c, d, r2, sth1, sth2, sthe, sxy, x0, x1, xp, y0, y1, yp, z; if (abs(prj->flag) != WCS__SIN) { if (astSINset(prj)) return 1; } /* Compute intermediaries. */ x0 = x*prj->w[0]; y0 = y*prj->w[0]; r2 = x0*x0 + y0*y0; if (prj->w[1] == 0.0) { /* Orthographic projection. */ if (r2 != 0.0) { *phi = astATan2d(x0, -y0); } else { *phi = 0.0; } if (r2 < 0.5) { *theta = astACosd(sqrt(r2)); } else if (r2 <= 1.0) { *theta = astASind(sqrt(1.0 - r2)); } else { return 2; } } else { /* "Synthesis" projection. */ x1 = prj->p[1]; y1 = prj->p[2]; sxy = x0*x1 + y0*y1; if (r2 < 1.0e-10) { /* Use small angle formula. */ z = r2/2.0; *theta = 90.0 - R2D*sqrt(r2/(1.0 + sxy)); } else { a = prj->w[2]; b = sxy - prj->w[1]; c = r2 - sxy - sxy + prj->w[3]; d = b*b - a*c; /* Check for a solution. */ if (d < 0.0) { return 2; } d = sqrt(d); /* Choose solution closest to pole. */ sth1 = (-b + d)/a; sth2 = (-b - d)/a; sthe = (sth1 > sth2) ? sth1 : sth2; if (sthe > 1.0) { if (sthe-1.0 < tol) { sthe = 1.0; } else { sthe = (sth1 < sth2) ? sth1 : sth2; } } if (sthe < -1.0) { if (sthe+1.0 > -tol) { sthe = -1.0; } } if (sthe > 1.0 || sthe < -1.0) { return 2; } *theta = astASind(sthe); z = 1.0 - sthe; } xp = -y0 + prj->p[2]*z; yp = x0 - prj->p[1]*z; if (xp == 0.0 && yp == 0.0) { *phi = 0.0; } else { *phi = astATan2d(yp,xp); } } return 0; } /*============================================================================ * ARC: zenithal/azimuthal equidistant projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "ARC" * prj->flag ARC * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->astPRJfwd Pointer to astARCfwd(). * prj->astPRJrev Pointer to astARCrev(). *===========================================================================*/ int astARCset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "ARC"); prj->flag = WCS__ARC; prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astARCfwd; prj->astPRJrev = astARCrev; return 0; } /*--------------------------------------------------------------------------*/ int astARCfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double r; if (prj->flag != WCS__ARC) { if (astARCset(prj)) return 1; } r = prj->w[0]*(90.0 - theta); *x = r*astSind(phi); *y = -r*astCosd(phi); return 0; } /*--------------------------------------------------------------------------*/ int astARCrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double r; if (prj->flag != WCS__ARC) { if (astARCset(prj)) return 1; } r = sqrt(x*x + y*y); if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } *theta = 90.0 - r*prj->w[1]; return 0; } /*============================================================================ * ZPN: zenithal/azimuthal polynomial projection. * * Given: * prj->p[0:WCSLIB_MXPAR-1] Polynomial coefficients. * * Given and/or returned: * prj->flag ZPN, or -ZPN if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "ZPN" * prj->phi0 0.0 * prj->theta0 90.0 * prj->n Degree of the polynomial, N. * prj->w[0] Co-latitude of the first point of inflection (N > 2). * prj->w[1] Radius of the first point of inflection (N > 2). * prj->astPRJfwd Pointer to astZPNfwd(). * prj->astPRJrev Pointer to astZPNrev(). *===========================================================================*/ int astZPNset(prj) struct AstPrjPrm *prj; { int i, j, k, plen; double d, d1, d2, r, zd, zd1, zd2; const double tol = 1.0e-13; strcpy(prj->code, "ZPN"); prj->flag = copysign(WCS__ZPN, prj->flag); prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; /* Find the highest non-zero coefficient. */ plen = astSizeOf( prj->p )/sizeof( double ); for (k = plen-1; k >= 0 && prj->p[k] == 0.0; k--); if (k < 0) return 1; prj->n = k; if (k >= 3) { /* Find the point of inflection closest to the pole. */ zd1 = 0.0; d1 = prj->p[1]; if (d1 <= 0.0) { return 1; } /* Find the point where the derivative first goes negative. */ for (i = 0; i < 180; i++) { zd2 = i*D2R; d2 = 0.0; for (j = k; j > 0; j--) { d2 = d2*zd2 + j*prj->p[j]; } if (d2 <= 0.0) break; zd1 = zd2; d1 = d2; } if (i == 180) { /* No negative derivative -> no point of inflection. */ zd = PI; } else { /* Find where the derivative is zero. */ for (i = 1; i <= 10; i++) { zd = zd1 - d1*(zd2-zd1)/(d2-d1); d = 0.0; for (j = k; j > 0; j--) { d = d*zd + j*prj->p[j]; } if (fabs(d) < tol) break; if (d < 0.0) { zd2 = zd; d2 = d; } else { zd1 = zd; d1 = d; } } } r = 0.0; for (j = k; j >= 0; j--) { r = r*zd + prj->p[j]; } prj->w[0] = zd; prj->w[1] = r; } prj->astPRJfwd = astZPNfwd; prj->astPRJrev = astZPNrev; return 0; } /*--------------------------------------------------------------------------*/ int astZPNfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { int j; double r, s; if (abs(prj->flag) != WCS__ZPN) { if (astZPNset(prj)) return 1; } s = (90.0 - theta)*D2R; r = 0.0; for (j = prj->n; j >= 0; j--) { r = r*s + prj->p[j]; } r = prj->r0*r; *x = r*astSind(phi); *y = -r*astCosd(phi); if (prj->flag > 0 && s > prj->w[0] && prj->n > 2 ) { return 2; } return 0; } /*--------------------------------------------------------------------------*/ int astZPNrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { int i, j, k; double a, b, c, d, lambda, r, r1, r2, rt, zd, zd1, zd2; const double tol = 1.0e-13; if (abs(prj->flag) != WCS__ZPN) { if (astZPNset(prj)) return 1; } k = prj->n; r = sqrt(x*x + y*y)/prj->r0; if (k < 1) { /* Constant - no solution. */ return 1; } else if (k == 1) { /* Linear. */ zd = (r - prj->p[0])/prj->p[1]; } else if (k == 2) { /* Quadratic. */ a = prj->p[2]; b = prj->p[1]; c = prj->p[0] - r; d = b*b - 4.0*a*c; if (d < 0.0) { return 2; } d = sqrt(d); /* Choose solution closest to pole. */ zd1 = (-b + d)/(2.0*a); zd2 = (-b - d)/(2.0*a); zd = (zd1zd2) ? zd1 : zd2; if (zd < 0.0) { if (zd < -tol) { return 2; } zd = 0.0; } else if (zd > PI) { if (zd > PI+tol) { return 2; } zd = PI; } } else { /* Higher order - solve iteratively. */ zd1 = 0.0; r1 = prj->p[0]; zd2 = prj->w[0]; r2 = prj->w[1]; if (r < r1) { if (r < r1-tol) { return 2; } zd = zd1; } else if (r > r2) { if (r > r2+tol) { return 2; } zd = zd2; } else { /* Disect the interval. */ for (j = 0; j < 100; j++) { lambda = (r2 - r)/(r2 - r1); if (lambda < 0.1) { lambda = 0.1; } else if (lambda > 0.9) { lambda = 0.9; } zd = zd2 - lambda*(zd2 - zd1); rt = 0.0; for (i = k; i >= 0; i--) { rt = (rt * zd) + prj->p[i]; } if (rt < r) { if (r-rt < tol) break; r1 = rt; zd1 = zd; } else { if (rt-r < tol) break; r2 = rt; zd2 = zd; } if (fabs(zd2-zd1) < tol) break; } } } if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } *theta = 90.0 - zd*R2D; return 0; } /*============================================================================ * ZEA: zenithal/azimuthal equal area projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "ZEA" * prj->flag ZEA * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] 2*r0 * prj->w[1] 1/(2*r0) * prj->astPRJfwd Pointer to astZEAfwd(). * prj->astPRJrev Pointer to astZEArev(). *===========================================================================*/ int astZEAset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "ZEA"); prj->flag = WCS__ZEA; prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 360.0/PI; prj->w[1] = PI/360.0; } else { prj->w[0] = 2.0*prj->r0; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astZEAfwd; prj->astPRJrev = astZEArev; return 0; } /*--------------------------------------------------------------------------*/ int astZEAfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double r; if (prj->flag != WCS__ZEA) { if (astZEAset(prj)) return 1; } r = prj->w[0]*astSind((90.0 - theta)/2.0); *x = r*astSind(phi); *y = -r*astCosd(phi); return 0; } /*--------------------------------------------------------------------------*/ int astZEArev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double r, s; const double tol = 1.0e-12; if (prj->flag != WCS__ZEA) { if (astZEAset(prj)) return 1; } r = sqrt(x*x + y*y); if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } s = r*prj->w[1]; if (fabs(s) > 1.0) { if (fabs(r - prj->w[0]) < tol) { *theta = -90.0; } else { return 2; } } else { *theta = 90.0 - 2.0*astASind(s); } return 0; } /*============================================================================ * AIR: Airy's projection. * * Given: * prj->p[1] Latitude theta_b within which the error is minimized, in * degrees. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "AIR" * prj->flag AIR * prj->phi0 0.0 * prj->theta0 90.0 * prj->w[0] 2*r0 * prj->w[1] ln(cos(xi_b))/tan(xi_b)**2, where xi_b = (90-theta_b)/2 * prj->w[2] 1/2 - prj->w[1] * prj->w[3] 2*r0*prj->w[2] * prj->w[4] tol, cutoff for using small angle approximation, in * radians. * prj->w[5] prj->w[2]*tol * prj->w[6] (180/pi)/prj->w[2] * prj->astPRJfwd Pointer to astAIRfwd(). * prj->astPRJrev Pointer to astAIRrev(). *===========================================================================*/ int astAIRset(prj) struct AstPrjPrm *prj; { const double tol = 1.0e-4; double cxi; strcpy(prj->code, "AIR"); prj->flag = WCS__AIR; prj->phi0 = 0.0; prj->theta0 = 90.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = 2.0*prj->r0; if (prj->p[1] == 90.0) { prj->w[1] = -0.5; prj->w[2] = 1.0; } else if (prj->p[1] > -90.0) { cxi = astCosd((90.0 - prj->p[1])/2.0); prj->w[1] = log(cxi)*(cxi*cxi)/(1.0-cxi*cxi); prj->w[2] = 0.5 - prj->w[1]; } else { return 1; } prj->w[3] = prj->w[0] * prj->w[2]; prj->w[4] = tol; prj->w[5] = prj->w[2]*tol; prj->w[6] = R2D/prj->w[2]; prj->astPRJfwd = astAIRfwd; prj->astPRJrev = astAIRrev; return 0; } /*--------------------------------------------------------------------------*/ int astAIRfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double cxi, r, txi, xi; if (prj->flag != WCS__AIR) { if (astAIRset(prj)) return 1; } if (theta == 90.0) { r = 0.0; } else if (theta > -90.0) { xi = D2R*(90.0 - theta)/2.0; if (xi < prj->w[4]) { r = xi*prj->w[3]; } else { cxi = astCosd((90.0 - theta)/2.0); txi = sqrt(1.0-cxi*cxi)/cxi; r = -prj->w[0]*(log(cxi)/txi + prj->w[1]*txi); } } else { return 2; } *x = r*astSind(phi); *y = -r*astCosd(phi); return 0; } /*--------------------------------------------------------------------------*/ int astAIRrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { int j; double cxi, lambda, r, r1, r2, rt, txi, x1, x2, xi; const double tol = 1.0e-12; if (prj->flag != WCS__AIR) { if (astAIRset(prj)) return 1; } r = sqrt(x*x + y*y)/prj->w[0]; if (r == 0.0) { xi = 0.0; } else if (r < prj->w[5]) { xi = r*prj->w[6]; } else { /* Find a solution interval. */ x1 = 1.0; r1 = 0.0; for (j = 0; j < 30; j++) { x2 = x1/2.0; txi = sqrt(1.0-x2*x2)/x2; r2 = -(log(x2)/txi + prj->w[1]*txi); if (r2 >= r) break; x1 = x2; r1 = r2; } if (j == 30) return 2; for (j = 0; j < 100; j++) { /* Weighted division of the interval. */ lambda = (r2-r)/(r2-r1); if (lambda < 0.1) { lambda = 0.1; } else if (lambda > 0.9) { lambda = 0.9; } cxi = x2 - lambda*(x2-x1); txi = sqrt(1.0-cxi*cxi)/cxi; rt = -(log(cxi)/txi + prj->w[1]*txi); if (rt < r) { if (r-rt < tol) break; r1 = rt; x1 = cxi; } else { if (rt-r < tol) break; r2 = rt; x2 = cxi; } } if (j == 100) return 2; xi = astACosd(cxi); } if (r == 0.0) { *phi = 0.0; } else { *phi = astATan2d(x, -y); } *theta = 90.0 - 2.0*xi; return 0; } /*============================================================================ * CYP: cylindrical perspective projection. * * Given: * prj->p[1] Distance of point of projection from the centre of the * generating sphere, mu, in units of r0. * prj->p[2] Radius of the cylinder of projection, lambda, in units of * r0. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "CYP" * prj->flag CYP * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*lambda*(pi/180) * prj->w[1] (180/pi)/(r0*lambda) * prj->w[2] r0*(mu + lambda) * prj->w[3] 1/(r0*(mu + lambda)) * prj->astPRJfwd Pointer to astCYPfwd(). * prj->astPRJrev Pointer to astCYPrev(). *===========================================================================*/ int astCYPset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "CYP"); prj->flag = WCS__CYP; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = prj->p[2]; if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[2] = R2D*(prj->p[1] + prj->p[2]); if (prj->w[2] == 0.0) { return 1; } prj->w[3] = 1.0/prj->w[2]; } else { prj->w[0] = prj->r0*prj->p[2]*D2R; if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[2] = prj->r0*(prj->p[1] + prj->p[2]); if (prj->w[2] == 0.0) { return 1; } prj->w[3] = 1.0/prj->w[2]; } prj->astPRJfwd = astCYPfwd; prj->astPRJrev = astCYPrev; return 0; } /*--------------------------------------------------------------------------*/ int astCYPfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double s; if (prj->flag != WCS__CYP) { if (astCYPset(prj)) return 1; } s = prj->p[1] + astCosd(theta); if (s == 0.0) { return 2; } *x = prj->w[0]*phi; *y = prj->w[2]*astSind(theta)/s; return 0; } /*--------------------------------------------------------------------------*/ int astCYPrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double eta; double a; const double tol = 1.0e-13; if (prj->flag != WCS__CYP) { if (astCYPset(prj)) return 1; } *phi = x*prj->w[1]; eta = y*prj->w[3]; a = eta*prj->p[1]/sqrt(eta*eta+1.0); if( fabs( a ) < 1.0 ) { *theta = astATan2d(eta,1.0) + astASind( a ); } else if( fabs( a ) < 1.0 + tol ) { if( a > 0.0 ){ *theta = astATan2d(eta,1.0) + 90.0; } else { *theta = astATan2d(eta,1.0) - 90.0; } } else { return 2; } return 0; } /*============================================================================ * CEA: cylindrical equal area projection. * * Given: * prj->p[1] Square of the cosine of the latitude at which the * projection is conformal, lambda. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "CEA" * prj->flag CEA * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->w[2] r0/lambda * prj->w[3] lambda/r0 * prj->astPRJfwd Pointer to astCEAfwd(). * prj->astPRJrev Pointer to astCEArev(). *===========================================================================*/ int astCEAset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "CEA"); prj->flag = WCS__CEA; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; if (prj->p[1] <= 0.0 || prj->p[1] > 1.0) { return 1; } prj->w[2] = prj->r0/prj->p[1]; prj->w[3] = prj->p[1]/prj->r0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = R2D/prj->r0; if (prj->p[1] <= 0.0 || prj->p[1] > 1.0) { return 1; } prj->w[2] = prj->r0/prj->p[1]; prj->w[3] = prj->p[1]/prj->r0; } prj->astPRJfwd = astCEAfwd; prj->astPRJrev = astCEArev; return 0; } /*--------------------------------------------------------------------------*/ int astCEAfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { if (prj->flag != WCS__CEA) { if (astCEAset(prj)) return 1; } *x = prj->w[0]*phi; *y = prj->w[2]*astSind(theta); return 0; } /*--------------------------------------------------------------------------*/ int astCEArev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double s; const double tol = 1.0e-13; if (prj->flag != WCS__CEA) { if (astCEAset(prj)) return 1; } s = y*prj->w[3]; if (fabs(s) > 1.0) { if (fabs(s) > 1.0+tol) { return 2; } s = copysign(1.0,s); } *phi = x*prj->w[1]; *theta = astASind(s); return 0; } /*============================================================================ * CAR: Cartesian projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "CAR" * prj->flag CAR * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->astPRJfwd Pointer to astCARfwd(). * prj->astPRJrev Pointer to astCARrev(). *===========================================================================*/ int astCARset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "CAR"); prj->flag = WCS__CAR; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astCARfwd; prj->astPRJrev = astCARrev; return 0; } /*--------------------------------------------------------------------------*/ int astCARfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { if (prj->flag != WCS__CAR) { if (astCARset(prj)) return 1; } *x = prj->w[0]*phi; *y = prj->w[0]*theta; return 0; } /*--------------------------------------------------------------------------*/ int astCARrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { if (prj->flag != WCS__CAR) { if (astCARset(prj)) return 1; } *phi = prj->w[1]*x; *theta = prj->w[1]*y; return 0; } /*============================================================================ * MER: Mercator's projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "MER" * prj->flag MER * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->astPRJfwd Pointer to astMERfwd(). * prj->astPRJrev Pointer to astMERrev(). *===========================================================================*/ int astMERset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "MER"); prj->flag = WCS__MER; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astMERfwd; prj->astPRJrev = astMERrev; return 0; } /*--------------------------------------------------------------------------*/ int astMERfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { if (prj->flag != WCS__MER) { if (astMERset(prj)) return 1; } if (theta <= -90.0 || theta >= 90.0) { return 2; } *x = prj->w[0]*phi; *y = prj->r0*log(astTand((90.0+theta)/2.0)); return 0; } /*--------------------------------------------------------------------------*/ int astMERrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { if (prj->flag != WCS__MER) { if (astMERset(prj)) return 1; } *phi = x*prj->w[1]; *theta = 2.0*astATand(exp(y/prj->r0)) - 90.0; return 0; } /*============================================================================ * SFL: Sanson-Flamsteed ("global sinusoid") projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "SFL" * prj->flag SFL * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->astPRJfwd Pointer to astSFLfwd(). * prj->astPRJrev Pointer to astSFLrev(). *===========================================================================*/ int astSFLset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "SFL"); prj->flag = WCS__SFL; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astSFLfwd; prj->astPRJrev = astSFLrev; return 0; } /*--------------------------------------------------------------------------*/ int astSFLfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { if (prj->flag != WCS__SFL) { if (astSFLset(prj)) return 1; } *x = prj->w[0]*phi*astCosd(theta); *y = prj->w[0]*theta; return 0; } /*--------------------------------------------------------------------------*/ int astSFLrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double w; if (prj->flag != WCS__SFL) { if (astSFLset(prj)) return 1; } w = cos(y/prj->r0); if (w == 0.0) { *phi = 0.0; } else { *phi = x*prj->w[1]/cos(y/prj->r0); } *theta = y*prj->w[1]; return 0; } /*============================================================================ * PAR: parabolic projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "PAR" * prj->flag PAR * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->w[2] pi*r0 * prj->w[3] 1/(pi*r0) * prj->astPRJfwd Pointer to astPARfwd(). * prj->astPRJrev Pointer to astPARrev(). *===========================================================================*/ int astPARset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "PAR"); prj->flag = WCS__PAR; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; prj->w[2] = 180.0; prj->w[3] = 1.0/prj->w[2]; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; prj->w[2] = PI*prj->r0; prj->w[3] = 1.0/prj->w[2]; } prj->astPRJfwd = astPARfwd; prj->astPRJrev = astPARrev; return 0; } /*--------------------------------------------------------------------------*/ int astPARfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double s; if (prj->flag != WCS__PAR) { if (astPARset(prj)) return 1; } s = astSind(theta/3.0); *x = prj->w[0]*phi*(1.0 - 4.0*s*s); *y = prj->w[2]*s; return 0; } /*--------------------------------------------------------------------------*/ int astPARrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double s, t; if (prj->flag != WCS__PAR) { if (astPARset(prj)) return 1; } s = y*prj->w[3]; if (s > 1.0 || s < -1.0) { return 2; } t = 1.0 - 4.0*s*s; if (t == 0.0) { if (x == 0.0) { *phi = 0.0; } else { return 2; } } else { *phi = prj->w[1]*x/t; } *theta = 3.0*astASind(s); return 0; } /*============================================================================ * MOL: Mollweide's projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "MOL" * prj->flag MOL * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] sqrt(2)*r0 * prj->w[1] sqrt(2)*r0/90 * prj->w[2] 1/(sqrt(2)*r0) * prj->w[3] 90/r0 * prj->astPRJfwd Pointer to astMOLfwd(). * prj->astPRJrev Pointer to astMOLrev(). *===========================================================================*/ int astMOLset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "MOL"); prj->flag = WCS__MOL; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = SQRT2*prj->r0; prj->w[1] = prj->w[0]/90.0; prj->w[2] = 1.0/prj->w[0]; prj->w[3] = 90.0/prj->r0; prj->w[4] = 2.0/PI; prj->astPRJfwd = astMOLfwd; prj->astPRJrev = astMOLrev; return 0; } /*--------------------------------------------------------------------------*/ int astMOLfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { int j; double gamma, resid, u, v, v0, v1; const double tol = 1.0e-13; if (prj->flag != WCS__MOL) { if (astMOLset(prj)) return 1; } if (fabs(theta) == 90.0) { *x = 0.0; *y = copysign(prj->w[0],theta); } else if (theta == 0.0) { *x = prj->w[1]*phi; *y = 0.0; } else { u = PI*astSind(theta); v0 = -PI; v1 = PI; v = u; for (j = 0; j < 100; j++) { resid = (v - u) + sin(v); if (resid < 0.0) { if (resid > -tol) break; v0 = v; } else { if (resid < tol) break; v1 = v; } v = (v0 + v1)/2.0; } gamma = v/2.0; *x = prj->w[1]*phi*cos(gamma); *y = prj->w[0]*sin(gamma); } return 0; } /*--------------------------------------------------------------------------*/ int astMOLrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double s, y0, z; const double tol = 1.0e-12; if (prj->flag != WCS__MOL) { if (astMOLset(prj)) return 1; } y0 = y/prj->r0; s = 2.0 - y0*y0; if (s <= tol) { if (s < -tol) { return 2; } s = 0.0; if (fabs(x) > tol) { return 2; } *phi = 0.0; } else { s = sqrt(s); *phi = prj->w[3]*x/s; } z = y*prj->w[2]; if (fabs(z) > 1.0) { if (fabs(z) > 1.0+tol) { return 2; } z = copysign(1.0,z) + y0*s/PI; } else { z = asin(z)*prj->w[4] + y0*s/PI; } if (fabs(z) > 1.0) { if (fabs(z) > 1.0+tol) { return 2; } z = copysign(1.0,z); } *theta = astASind(z); return 0; } /*============================================================================ * AIT: Hammer-Aitoff projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "AIT" * prj->flag AIT * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] 2*r0**2 * prj->w[1] 1/(2*r0)**2 * prj->w[2] 1/(4*r0)**2 * prj->w[3] 1/(2*r0) * prj->astPRJfwd Pointer to astAITfwd(). * prj->astPRJrev Pointer to astAITrev(). *===========================================================================*/ int astAITset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "AIT"); prj->flag = WCS__AIT; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = 2.0*prj->r0*prj->r0; prj->w[1] = 1.0/(2.0*prj->w[0]); prj->w[2] = prj->w[1]/4.0; prj->w[3] = 1.0/(2.0*prj->r0); prj->astPRJfwd = astAITfwd; prj->astPRJrev = astAITrev; return 0; } /*--------------------------------------------------------------------------*/ int astAITfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double cthe, w; if (prj->flag != WCS__AIT) { if (astAITset(prj)) return 1; } cthe = astCosd(theta); w = sqrt(prj->w[0]/(1.0 + cthe*astCosd(phi/2.0))); *x = 2.0*w*cthe*astSind(phi/2.0); *y = w*astSind(theta); return 0; } /*--------------------------------------------------------------------------*/ int astAITrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double s, u, xp, yp, z; const double tol = 1.0e-13; if (prj->flag != WCS__AIT) { if (astAITset(prj)) return 1; } u = 1.0 - x*x*prj->w[2] - y*y*prj->w[1]; if (u < 0.0) { if (u < -tol) { return 2; } u = 0.0; } z = sqrt(u); s = z*y/prj->r0; if (fabs(s) > 1.0) { if (fabs(s) > 1.0+tol) { return 2; } s = copysign(1.0,s); } xp = 2.0*z*z - 1.0; yp = z*x*prj->w[3]; if (xp == 0.0 && yp == 0.0) { *phi = 0.0; } else { *phi = 2.0*astATan2d(yp, xp); } *theta = astASind(s); return 0; } /*============================================================================ * COP: conic perspective projection. * * Given: * prj->p[1] sigma = (theta2+theta1)/2 * prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the * latitudes of the standard parallels, in degrees. * * Given and/or returned: * prj->flag COP, or -COP if prj->flag is given < 0. * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "COP" * prj->phi0 0.0 * prj->theta0 sigma * prj->w[0] C = sin(sigma) * prj->w[1] 1/C * prj->w[2] Y0 = r0*cos(delta)*cot(sigma) * prj->w[3] r0*cos(delta) * prj->w[4] 1/(r0*cos(delta) * prj->w[5] cot(sigma) * prj->astPRJfwd Pointer to astCOPfwd(). * prj->astPRJrev Pointer to astCOPrev(). *===========================================================================*/ int astCOPset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "COP"); prj->flag = copysign(WCS__COP, prj->flag); prj->phi0 = 0.0; prj->theta0 = prj->p[1]; if (prj->r0 == 0.0) prj->r0 = R2D; prj->w[0] = astSind(prj->p[1]); if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[3] = prj->r0*astCosd(prj->p[2]); if (prj->w[3] == 0.0) { return 1; } prj->w[4] = 1.0/prj->w[3]; prj->w[5] = 1.0/astTand(prj->p[1]); prj->w[2] = prj->w[3]*prj->w[5]; prj->astPRJfwd = astCOPfwd; prj->astPRJrev = astCOPrev; return 0; } /*--------------------------------------------------------------------------*/ int astCOPfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, r, s, t; if (abs(prj->flag) != WCS__COP) { if (astCOPset(prj)) return 1; } t = theta - prj->p[1]; s = astCosd(t); if (s == 0.0) { return 2; } a = prj->w[0]*phi; r = prj->w[2] - prj->w[3]*astSind(t)/s; *x = r*astSind(a); *y = prj->w[2] - r*astCosd(a); if (prj->flag > 0 && r*prj->w[0] < 0.0) { return 2; } return 0; } /*--------------------------------------------------------------------------*/ int astCOPrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, dy, r; if (abs(prj->flag) != WCS__COP) { if (astCOPset(prj)) return 1; } dy = prj->w[2] - y; r = sqrt(x*x + dy*dy); if (prj->p[1] < 0.0) r = -r; if (r == 0.0) { a = 0.0; } else { a = astATan2d(x/r, dy/r); } *phi = a*prj->w[1]; *theta = prj->p[1] + astATand(prj->w[5] - r*prj->w[4]); return 0; } /*============================================================================ * COE: conic equal area projection. * * Given: * prj->p[1] sigma = (theta2+theta1)/2 * prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the * latitudes of the standard parallels, in degrees. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "COE" * prj->flag COE * prj->phi0 0.0 * prj->theta0 sigma * prj->w[0] C = (sin(theta1) + sin(theta2))/2 * prj->w[1] 1/C * prj->w[2] Y0 = chi*sqrt(psi - 2C*astSind(sigma)) * prj->w[3] chi = r0/C * prj->w[4] psi = 1 + sin(theta1)*sin(theta2) * prj->w[5] 2C * prj->w[6] (1 + sin(theta1)*sin(theta2))*(r0/C)**2 * prj->w[7] C/(2*r0**2) * prj->w[8] chi*sqrt(psi + 2C) * prj->astPRJfwd Pointer to astCOEfwd(). * prj->astPRJrev Pointer to astCOErev(). *===========================================================================*/ int astCOEset(prj) struct AstPrjPrm *prj; { double theta1, theta2; strcpy(prj->code, "COE"); prj->flag = WCS__COE; prj->phi0 = 0.0; prj->theta0 = prj->p[1]; if (prj->r0 == 0.0) prj->r0 = R2D; theta1 = prj->p[1] - prj->p[2]; theta2 = prj->p[1] + prj->p[2]; prj->w[0] = (astSind(theta1) + astSind(theta2))/2.0; if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[3] = prj->r0/prj->w[0]; prj->w[4] = 1.0 + astSind(theta1)*astSind(theta2); prj->w[5] = 2.0*prj->w[0]; prj->w[6] = prj->w[3]*prj->w[3]*prj->w[4]; prj->w[7] = 1.0/(2.0*prj->r0*prj->w[3]); prj->w[8] = prj->w[3]*sqrt(prj->w[4] + prj->w[5]); prj->w[2] = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*astSind(prj->p[1])); prj->astPRJfwd = astCOEfwd; prj->astPRJrev = astCOErev; return 0; } /*--------------------------------------------------------------------------*/ int astCOEfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, r; if (prj->flag != WCS__COE) { if (astCOEset(prj)) return 1; } a = phi*prj->w[0]; if (theta == -90.0) { r = prj->w[8]; } else { r = prj->w[3]*sqrt(prj->w[4] - prj->w[5]*astSind(theta)); } *x = r*astSind(a); *y = prj->w[2] - r*astCosd(a); return 0; } /*--------------------------------------------------------------------------*/ int astCOErev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, dy, r, w; const double tol = 1.0e-12; if (prj->flag != WCS__COE) { if (astCOEset(prj)) return 1; } dy = prj->w[2] - y; r = sqrt(x*x + dy*dy); if (prj->p[1] < 0.0) r = -r; if (r == 0.0) { a = 0.0; } else { a = astATan2d(x/r, dy/r); } *phi = a*prj->w[1]; if (fabs(r - prj->w[8]) < tol) { *theta = -90.0; } else { w = (prj->w[6] - r*r)*prj->w[7]; if (fabs(w) > 1.0) { if (fabs(w-1.0) < tol) { *theta = 90.0; } else if (fabs(w+1.0) < tol) { *theta = -90.0; } else { return 2; } } else { *theta = astASind(w); } } return 0; } /*============================================================================ * COD: conic equidistant projection. * * Given: * prj->p[1] sigma = (theta2+theta1)/2 * prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the * latitudes of the standard parallels, in degrees. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "COD" * prj->flag COD * prj->phi0 0.0 * prj->theta0 sigma * prj->w[0] C = r0*sin(sigma)*sin(delta)/delta * prj->w[1] 1/C * prj->w[2] Y0 = delta*cot(delta)*cot(sigma) * prj->w[3] Y0 + sigma * prj->astPRJfwd Pointer to astCODfwd(). * prj->astPRJrev Pointer to astCODrev(). *===========================================================================*/ int astCODset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "COD"); prj->flag = WCS__COD; prj->phi0 = 0.0; prj->theta0 = prj->p[1]; if (prj->r0 == 0.0) prj->r0 = R2D; if (prj->p[2] == 0.0) { prj->w[0] = prj->r0*astSind(prj->p[1])*D2R; } else { prj->w[0] = prj->r0*astSind(prj->p[1])*astSind(prj->p[2])/prj->p[2]; } if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[2] = prj->r0*astCosd(prj->p[2])*astCosd(prj->p[1])/prj->w[0]; prj->w[3] = prj->w[2] + prj->p[1]; prj->astPRJfwd = astCODfwd; prj->astPRJrev = astCODrev; return 0; } /*--------------------------------------------------------------------------*/ int astCODfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, r; if (prj->flag != WCS__COD) { if (astCODset(prj)) return 1; } a = prj->w[0]*phi; r = prj->w[3] - theta; *x = r*astSind(a); *y = prj->w[2] - r*astCosd(a); return 0; } /*--------------------------------------------------------------------------*/ int astCODrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, dy, r; if (prj->flag != WCS__COD) { if (astCODset(prj)) return 1; } dy = prj->w[2] - y; r = sqrt(x*x + dy*dy); if (prj->p[1] < 0.0) r = -r; if (r == 0.0) { a = 0.0; } else { a = astATan2d(x/r, dy/r); } *phi = a*prj->w[1]; *theta = prj->w[3] - r; return 0; } /*============================================================================ * COO: conic orthomorphic projection. * * Given: * prj->p[1] sigma = (theta2+theta1)/2 * prj->p[2] delta = (theta2-theta1)/2, where theta1 and theta2 are the * latitudes of the standard parallels, in degrees. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "COO" * prj->flag COO * prj->phi0 0.0 * prj->theta0 sigma * prj->w[0] C = ln(cos(theta2)/cos(theta1))/ln(tan(tau2)/tan(tau1)) * where tau1 = (90 - theta1)/2 * tau2 = (90 - theta2)/2 * prj->w[1] 1/C * prj->w[2] Y0 = psi*tan((90-sigma)/2)**C * prj->w[3] psi = (r0*cos(theta1)/C)/tan(tau1)**C * prj->w[4] 1/psi * prj->astPRJfwd Pointer to astCOOfwd(). * prj->astPRJrev Pointer to astCOOrev(). *===========================================================================*/ int astCOOset(prj) struct AstPrjPrm *prj; { double cos1, cos2, tan1, tan2, theta1, theta2; strcpy(prj->code, "COO"); prj->flag = WCS__COO; prj->phi0 = 0.0; prj->theta0 = prj->p[1]; if (prj->r0 == 0.0) prj->r0 = R2D; theta1 = prj->p[1] - prj->p[2]; theta2 = prj->p[1] + prj->p[2]; tan1 = astTand((90.0 - theta1)/2.0); cos1 = astCosd(theta1); if (theta1 == theta2) { prj->w[0] = astSind(theta1); } else { tan2 = astTand((90.0 - theta2)/2.0); cos2 = astCosd(theta2); prj->w[0] = log(cos2/cos1)/log(tan2/tan1); } if (prj->w[0] == 0.0) { return 1; } prj->w[1] = 1.0/prj->w[0]; prj->w[3] = prj->r0*(cos1/prj->w[0])/pow(tan1,prj->w[0]); if (prj->w[3] == 0.0) { return 1; } prj->w[2] = prj->w[3]*pow(astTand((90.0 - prj->p[1])/2.0),prj->w[0]); prj->w[4] = 1.0/prj->w[3]; prj->astPRJfwd = astCOOfwd; prj->astPRJrev = astCOOrev; return 0; } /*--------------------------------------------------------------------------*/ int astCOOfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, r; if (prj->flag != WCS__COO) { if (astCOOset(prj)) return 1; } a = prj->w[0]*phi; if (theta == -90.0) { if (prj->w[0] < 0.0) { r = 0.0; } else { return 2; } } else { r = prj->w[3]*pow(astTand((90.0 - theta)/2.0),prj->w[0]); } *x = r*astSind(a); *y = prj->w[2] - r*astCosd(a); return 0; } /*--------------------------------------------------------------------------*/ int astCOOrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, dy, r; if (prj->flag != WCS__COO) { if (astCOOset(prj)) return 1; } dy = prj->w[2] - y; r = sqrt(x*x + dy*dy); if (prj->p[1] < 0.0) r = -r; if (r == 0.0) { a = 0.0; } else { a = astATan2d(x/r, dy/r); } *phi = a*prj->w[1]; if (r == 0.0) { if (prj->w[0] < 0.0) { *theta = -90.0; } else { return 2; } } else { *theta = 90.0 - 2.0*astATand(pow(r*prj->w[4],prj->w[1])); } return 0; } /*============================================================================ * BON: Bonne's projection. * * Given: * prj->p[1] Bonne conformal latitude, theta1, in degrees. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "BON" * prj->flag BON * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[1] r0*pi/180 * prj->w[2] Y0 = r0*(cot(theta1) + theta1*pi/180) * prj->astPRJfwd Pointer to astBONfwd(). * prj->astPRJrev Pointer to astBONrev(). *===========================================================================*/ int astBONset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "BON"); prj->flag = WCS__BON; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[1] = 1.0; prj->w[2] = prj->r0*astCosd(prj->p[1])/astSind(prj->p[1]) + prj->p[1]; } else { prj->w[1] = prj->r0*D2R; prj->w[2] = prj->r0*(astCosd(prj->p[1])/astSind(prj->p[1]) + prj->p[1]*D2R); } prj->astPRJfwd = astBONfwd; prj->astPRJrev = astBONrev; return 0; } /*--------------------------------------------------------------------------*/ int astBONfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, r; if (prj->p[1] == 0.0) { /* Sanson-Flamsteed. */ return astSFLfwd(phi, theta, prj, x, y); } if (prj->flag != WCS__BON) { if (astBONset(prj)) return 1; } r = prj->w[2] - theta*prj->w[1]; a = prj->r0*phi*astCosd(theta)/r; *x = r*astSind(a); *y = prj->w[2] - r*astCosd(a); return 0; } /*--------------------------------------------------------------------------*/ int astBONrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double a, cthe, dy, r; if (prj->p[1] == 0.0) { /* Sanson-Flamsteed. */ return astSFLrev(x, y, prj, phi, theta); } if (prj->flag != WCS__BON) { if (astBONset(prj)) return 1; } dy = prj->w[2] - y; r = sqrt(x*x + dy*dy); if (prj->p[1] < 0.0) r = -r; if (r == 0.0) { a = 0.0; } else { a = astATan2d(x/r, dy/r); } *theta = (prj->w[2] - r)/prj->w[1]; cthe = astCosd(*theta); if (cthe == 0.0) { *phi = 0.0; } else { *phi = a*(r/prj->r0)/cthe; } return 0; } /*============================================================================ * PCO: polyconic projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "PCO" * prj->flag PCO * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/180) * prj->w[1] 1/r0 * prj->w[2] 2*r0 * prj->astPRJfwd Pointer to astPCOfwd(). * prj->astPRJrev Pointer to astPCOrev(). *===========================================================================*/ int astPCOset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "PCO"); prj->flag = WCS__PCO; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; prj->w[2] = 360.0/PI; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = 1.0/prj->w[0]; prj->w[2] = 2.0*prj->r0; } prj->astPRJfwd = astPCOfwd; prj->astPRJrev = astPCOrev; return 0; } /*--------------------------------------------------------------------------*/ int astPCOfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double a, cthe, cotthe, sthe; if (prj->flag != WCS__PCO) { if (astPCOset(prj)) return 1; } cthe = astCosd(theta); sthe = astSind(theta); a = phi*sthe; if (sthe == 0.0) { *x = prj->w[0]*phi; *y = 0.0; } else { cotthe = cthe/sthe; *x = prj->r0*cotthe*astSind(a); *y = prj->r0*(cotthe*(1.0 - astCosd(a)) + theta*D2R); } return 0; } /*--------------------------------------------------------------------------*/ int astPCOrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { int j; double f, fneg, fpos, lambda, tanthe, theneg, thepos, w, xp, xx, ymthe, yp; const double tol = 1.0e-12; if (prj->flag != WCS__PCO) { if (astPCOset(prj)) return 1; } w = fabs(y*prj->w[1]); if (w < tol) { *phi = x*prj->w[1]; *theta = 0.0; } else if (fabs(w-90.0) < tol) { *phi = 0.0; *theta = copysign(90.0,y); } else { /* Iterative solution using weighted division of the interval. */ if (y > 0.0) { thepos = 90.0; } else { thepos = -90.0; } theneg = 0.0; xx = x*x; ymthe = y - prj->w[0]*thepos; fpos = xx + ymthe*ymthe; fneg = -999.0; for (j = 0; j < 64; j++) { if (fneg < -100.0) { /* Equal division of the interval. */ *theta = (thepos+theneg)/2.0; } else { /* Weighted division of the interval. */ lambda = fpos/(fpos-fneg); if (lambda < 0.1) { lambda = 0.1; } else if (lambda > 0.9) { lambda = 0.9; } *theta = thepos - lambda*(thepos-theneg); } /* Compute the residue. */ ymthe = y - prj->w[0]*(*theta); tanthe = astTand(*theta); f = xx + ymthe*(ymthe - prj->w[2]/tanthe); /* Check for convergence. */ if (fabs(f) < tol) break; if (fabs(thepos-theneg) < tol) break; /* Redefine the interval. */ if (f > 0.0) { thepos = *theta; fpos = f; } else { theneg = *theta; fneg = f; } } xp = prj->r0 - ymthe*tanthe; yp = x*tanthe; if (xp == 0.0 && yp == 0.0) { *phi = 0.0; } else { *phi = astATan2d(yp, xp)/astSind(*theta); } } return 0; } /*============================================================================ * TSC: tangential spherical cube projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "TSC" * prj->flag TSC * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/4) * prj->w[1] (4/pi)/r0 * prj->astPRJfwd Pointer to astTSCfwd(). * prj->astPRJrev Pointer to astTSCrev(). *===========================================================================*/ int astTSCset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "TSC"); prj->flag = WCS__TSC; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 45.0; prj->w[1] = 1.0/45.0; } else { prj->w[0] = prj->r0*PI/4.0; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astTSCfwd; prj->astPRJrev = astTSCrev; return 0; } /*--------------------------------------------------------------------------*/ int astTSCfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { int face; double cthe, l, m, n, rho, x0, xf, y0, yf; const double tol = 1.0e-12; x0 = 0.0; xf = 0.0; y0 = 0.0; yf = 0.0; if (prj->flag != WCS__TSC) { if (astTSCset(prj)) return 1; } cthe = astCosd(theta); l = cthe*astCosd(phi); m = cthe*astSind(phi); n = astSind(theta); face = 0; rho = n; if (l > rho) { face = 1; rho = l; } if (m > rho) { face = 2; rho = m; } if (-l > rho) { face = 3; rho = -l; } if (-m > rho) { face = 4; rho = -m; } if (-n > rho) { face = 5; rho = -n; } if (face == 0) { xf = m/rho; yf = -l/rho; x0 = 0.0; y0 = 2.0; } else if (face == 1) { xf = m/rho; yf = n/rho; x0 = 0.0; y0 = 0.0; } else if (face == 2) { xf = -l/rho; yf = n/rho; x0 = 2.0; y0 = 0.0; } else if (face == 3) { xf = -m/rho; yf = n/rho; x0 = 4.0; y0 = 0.0; } else if (face == 4) { xf = l/rho; yf = n/rho; x0 = 6.0; y0 = 0.0; } else if (face == 5) { xf = m/rho; yf = l/rho; x0 = 0.0; y0 = -2.0; } if (fabs(xf) > 1.0) { if (fabs(xf) > 1.0+tol) { return 2; } xf = copysign(1.0,xf); } if (fabs(yf) > 1.0) { if (fabs(yf) > 1.0+tol) { return 2; } yf = copysign(1.0,yf); } *x = prj->w[0]*(xf + x0); *y = prj->w[0]*(yf + y0); return 0; } /*--------------------------------------------------------------------------*/ int astTSCrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double l, m, n, xf, yf; if (prj->flag != WCS__TSC) { if (astTSCset(prj)) return 1; } xf = x*prj->w[1]; yf = y*prj->w[1]; /* Check bounds. */ if (fabs(xf) <= 1.0) { if (fabs(yf) > 3.0) return 2; } else { if (fabs(xf) > 7.0) return 2; if (fabs(yf) > 1.0) return 2; } /* Map negative faces to the other side. */ if (xf < -1.0) xf += 8.0; /* Determine the face. */ if (xf > 5.0) { /* face = 4 */ xf = xf - 6.0; m = -1.0/sqrt(1.0 + xf*xf + yf*yf); l = -m*xf; n = -m*yf; } else if (xf > 3.0) { /* face = 3 */ xf = xf - 4.0; l = -1.0/sqrt(1.0 + xf*xf + yf*yf); m = l*xf; n = -l*yf; } else if (xf > 1.0) { /* face = 2 */ xf = xf - 2.0; m = 1.0/sqrt(1.0 + xf*xf + yf*yf); l = -m*xf; n = m*yf; } else if (yf > 1.0) { /* face = 0 */ yf = yf - 2.0; n = 1.0/sqrt(1.0 + xf*xf + yf*yf); l = -n*yf; m = n*xf; } else if (yf < -1.0) { /* face = 5 */ yf = yf + 2.0; n = -1.0/sqrt(1.0 + xf*xf + yf*yf); l = -n*yf; m = -n*xf; } else { /* face = 1 */ l = 1.0/sqrt(1.0 + xf*xf + yf*yf); m = l*xf; n = l*yf; } if (l == 0.0 && m == 0.0) { *phi = 0.0; } else { *phi = astATan2d(m, l); } *theta = astASind(n); return 0; } /*============================================================================ * CSC: COBE quadrilateralized spherical cube projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "CSC" * prj->flag CSC * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/4) * prj->w[1] (4/pi)/r0 * prj->astPRJfwd Pointer to astCSCfwd(). * prj->astPRJrev Pointer to astCSCrev(). *===========================================================================*/ int astCSCset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "CSC"); prj->flag = WCS__CSC; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 45.0; prj->w[1] = 1.0/45.0; } else { prj->w[0] = prj->r0*PI/4.0; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astCSCfwd; prj->astPRJrev = astCSCrev; return 0; } /*--------------------------------------------------------------------------*/ int astCSCfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { int face; float cthe, eta, l, m, n, rho, xi; const float tol = 1.0e-7; float a, a2, a2b2, a4, ab, b, b2, b4, ca2, cb2, x0, xf, y0, yf; const float gstar = 1.37484847732; const float mm = 0.004869491981; const float gamma = -0.13161671474; const float omega1 = -0.159596235474; const float d0 = 0.0759196200467; const float d1 = -0.0217762490699; const float c00 = 0.141189631152; const float c10 = 0.0809701286525; const float c01 = -0.281528535557; const float c11 = 0.15384112876; const float c20 = -0.178251207466; const float c02 = 0.106959469314; eta = 0.0; xi = 0.0; x0 = 0.0; y0 = 0.0; if (prj->flag != WCS__CSC) { if (astCSCset(prj)) return 1; } cthe = astCosd(theta); l = cthe*astCosd(phi); m = cthe*astSind(phi); n = astSind(theta); face = 0; rho = n; if (l > rho) { face = 1; rho = l; } if (m > rho) { face = 2; rho = m; } if (-l > rho) { face = 3; rho = -l; } if (-m > rho) { face = 4; rho = -m; } if (-n > rho) { face = 5; rho = -n; } if (face == 0) { xi = m; eta = -l; x0 = 0.0; y0 = 2.0; } else if (face == 1) { xi = m; eta = n; x0 = 0.0; y0 = 0.0; } else if (face == 2) { xi = -l; eta = n; x0 = 2.0; y0 = 0.0; } else if (face == 3) { xi = -m; eta = n; x0 = 4.0; y0 = 0.0; } else if (face == 4) { xi = l; eta = n; x0 = 6.0; y0 = 0.0; } else if (face == 5) { xi = m; eta = l; x0 = 0.0; y0 = -2.0; } a = xi/rho; b = eta/rho; a2 = a*a; b2 = b*b; ca2 = 1.0 - a2; cb2 = 1.0 - b2; /* Avoid floating underflows. */ ab = fabs(a*b); a4 = (a2 > 1.0e-16) ? a2*a2 : 0.0; b4 = (b2 > 1.0e-16) ? b2*b2 : 0.0; a2b2 = (ab > 1.0e-16) ? a2*b2 : 0.0; xf = a*(a2 + ca2*(gstar + b2*(gamma*ca2 + mm*a2 + cb2*(c00 + c10*a2 + c01*b2 + c11*a2b2 + c20*a4 + c02*b4)) + a2*(omega1 - ca2*(d0 + d1*a2)))); yf = b*(b2 + cb2*(gstar + a2*(gamma*cb2 + mm*b2 + ca2*(c00 + c10*b2 + c01*a2 + c11*a2b2 + c20*b4 + c02*a4)) + b2*(omega1 - cb2*(d0 + d1*b2)))); if (fabs(xf) > 1.0) { if (fabs(xf) > 1.0+tol) { return 2; } xf = copysign(1.0,xf); } if (fabs(yf) > 1.0) { if (fabs(yf) > 1.0+tol) { return 2; } yf = copysign(1.0,yf); } *x = prj->w[0]*(x0 + xf); *y = prj->w[0]*(y0 + yf); return 0; } /*--------------------------------------------------------------------------*/ int astCSCrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { int face; float l, m, n; float a, b, xf, xx, yf, yy, z0, z1, z2, z3, z4, z5, z6; const float p00 = -0.27292696; const float p10 = -0.07629969; const float p20 = -0.22797056; const float p30 = 0.54852384; const float p40 = -0.62930065; const float p50 = 0.25795794; const float p60 = 0.02584375; const float p01 = -0.02819452; const float p11 = -0.01471565; const float p21 = 0.48051509; const float p31 = -1.74114454; const float p41 = 1.71547508; const float p51 = -0.53022337; const float p02 = 0.27058160; const float p12 = -0.56800938; const float p22 = 0.30803317; const float p32 = 0.98938102; const float p42 = -0.83180469; const float p03 = -0.60441560; const float p13 = 1.50880086; const float p23 = -0.93678576; const float p33 = 0.08693841; const float p04 = 0.93412077; const float p14 = -1.41601920; const float p24 = 0.33887446; const float p05 = -0.63915306; const float p15 = 0.52032238; const float p06 = 0.14381585; l = 0.0; m = 0.0; n = 0.0; if (prj->flag != WCS__CSC) { if (astCSCset(prj)) return 1; } xf = x*prj->w[1]; yf = y*prj->w[1]; /* Check bounds. */ if (fabs(xf) <= 1.0) { if (fabs(yf) > 3.0) return 2; } else { if (fabs(xf) > 7.0) return 2; if (fabs(yf) > 1.0) return 2; } /* Map negative faces to the other side. */ if (xf < -1.0) xf += 8.0; /* Determine the face. */ if (xf > 5.0) { face = 4; xf = xf - 6.0; } else if (xf > 3.0) { face = 3; xf = xf - 4.0; } else if (xf > 1.0) { face = 2; xf = xf - 2.0; } else if (yf > 1.0) { face = 0; yf = yf - 2.0; } else if (yf < -1.0) { face = 5; yf = yf + 2.0; } else { face = 1; } xx = xf*xf; yy = yf*yf; z0 = p00 + xx*(p10 + xx*(p20 + xx*(p30 + xx*(p40 + xx*(p50 + xx*(p60)))))); z1 = p01 + xx*(p11 + xx*(p21 + xx*(p31 + xx*(p41 + xx*(p51))))); z2 = p02 + xx*(p12 + xx*(p22 + xx*(p32 + xx*(p42)))); z3 = p03 + xx*(p13 + xx*(p23 + xx*(p33))); z4 = p04 + xx*(p14 + xx*(p24)); z5 = p05 + xx*(p15); z6 = p06; a = z0 + yy*(z1 + yy*(z2 + yy*(z3 + yy*(z4 + yy*(z5 + yy*z6))))); a = xf + xf*(1.0 - xx)*a; z0 = p00 + yy*(p10 + yy*(p20 + yy*(p30 + yy*(p40 + yy*(p50 + yy*(p60)))))); z1 = p01 + yy*(p11 + yy*(p21 + yy*(p31 + yy*(p41 + yy*(p51))))); z2 = p02 + yy*(p12 + yy*(p22 + yy*(p32 + yy*(p42)))); z3 = p03 + yy*(p13 + yy*(p23 + yy*(p33))); z4 = p04 + yy*(p14 + yy*(p24)); z5 = p05 + yy*(p15); z6 = p06; b = z0 + xx*(z1 + xx*(z2 + xx*(z3 + xx*(z4 + xx*(z5 + xx*z6))))); b = yf + yf*(1.0 - yy)*b; if (face == 0) { n = 1.0/sqrt(a*a + b*b + 1.0); l = -b*n; m = a*n; } else if (face == 1) { l = 1.0/sqrt(a*a + b*b + 1.0); m = a*l; n = b*l; } else if (face == 2) { m = 1.0/sqrt(a*a + b*b + 1.0); l = -a*m; n = b*m; } else if (face == 3) { l = -1.0/sqrt(a*a + b*b + 1.0); m = a*l; n = -b*l; } else if (face == 4) { m = -1.0/sqrt(a*a + b*b + 1.0); l = -a*m; n = -b*m; } else if (face == 5) { n = -1.0/sqrt(a*a + b*b + 1.0); l = -b*n; m = -a*n; } if (l == 0.0 && m == 0.0) { *phi = 0.0; } else { *phi = astATan2d(m, l); } *theta = astASind(n); return 0; } /*============================================================================ * QSC: quadrilaterilized spherical cube projection. * * Given and/or returned: * prj->r0 r0; reset to 180/pi if 0. * * Returned: * prj->code "QSC" * prj->flag QSC * prj->phi0 0.0 * prj->theta0 0.0 * prj->w[0] r0*(pi/4) * prj->w[1] (4/pi)/r0 * prj->astPRJfwd Pointer to astQSCfwd(). * prj->astPRJrev Pointer to astQSCrev(). *===========================================================================*/ int astQSCset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "QSC"); prj->flag = WCS__QSC; prj->phi0 = 0.0; prj->theta0 = 0.0; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 45.0; prj->w[1] = 1.0/45.0; } else { prj->w[0] = prj->r0*PI/4.0; prj->w[1] = 1.0/prj->w[0]; } prj->astPRJfwd = astQSCfwd; prj->astPRJrev = astQSCrev; return 0; } /*--------------------------------------------------------------------------*/ int astQSCfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { int face; double cthe, eta, l, m, n, omega, p, rho, rhu, t, tau, x0, xf, xi, y0, yf; const double tol = 1.0e-12; eta = 0.0; x0 = 0.0; xf = 0.0; xi = 0.0; y0 = 0.0; yf = 0.0; if (prj->flag != WCS__QSC) { if (astQSCset(prj)) return 1; } if (fabs(theta) == 90.0) { *x = 0.0; *y = copysign(2.0*prj->w[0],theta); return 0; } cthe = astCosd(theta); l = cthe*astCosd(phi); m = cthe*astSind(phi); n = astSind(theta); face = 0; rho = n; if (l > rho) { face = 1; rho = l; } if (m > rho) { face = 2; rho = m; } if (-l > rho) { face = 3; rho = -l; } if (-m > rho) { face = 4; rho = -m; } if (-n > rho) { face = 5; rho = -n; } rhu = 1.0 - rho; if (face == 0) { xi = m; eta = -l; if (rhu < 1.0e-8) { /* Small angle formula. */ t = (90.0 - theta)*D2R; rhu = t*t/2.0; } x0 = 0.0; y0 = 2.0; } else if (face == 1) { xi = m; eta = n; if (rhu < 1.0e-8) { /* Small angle formula. */ t = theta*D2R; p = fmod(phi,360.0); if (p < -180.0) p += 360.0; if (p > 180.0) p -= 360.0; p *= D2R; rhu = (p*p + t*t)/2.0; } x0 = 0.0; y0 = 0.0; } else if (face == 2) { xi = -l; eta = n; if (rhu < 1.0e-8) { /* Small angle formula. */ t = theta*D2R; p = fmod(phi,360.0); if (p < -180.0) p += 360.0; p = (90.0 - p)*D2R; rhu = (p*p + t*t)/2.0; } x0 = 2.0; y0 = 0.0; } else if (face == 3) { xi = -m; eta = n; if (rhu < 1.0e-8) { /* Small angle formula. */ t = theta*D2R; p = fmod(phi,360.0); if (p < 0.0) p += 360.0; p = (180.0 - p)*D2R; rhu = (p*p + t*t)/2.0; } x0 = 4.0; y0 = 0.0; } else if (face == 4) { xi = l; eta = n; if (rhu < 1.0e-8) { /* Small angle formula. */ t = theta*D2R; p = fmod(phi,360.0); if (p > 180.0) p -= 360.0; p *= (90.0 + p)*D2R; rhu = (p*p + t*t)/2.0; } x0 = 6; y0 = 0.0; } else if (face == 5) { xi = m; eta = l; if (rhu < 1.0e-8) { /* Small angle formula. */ t = (90.0 + theta)*D2R; rhu = t*t/2.0; } x0 = 0.0; y0 = -2; } if (xi == 0.0 && eta == 0.0) { xf = 0.0; yf = 0.0; } else if (-xi >= fabs(eta)) { omega = eta/xi; tau = 1.0 + omega*omega; xf = -sqrt(rhu/(1.0-1.0/sqrt(1.0+tau))); yf = (xf/15.0)*(astATand(omega) - astASind(omega/sqrt(tau+tau))); } else if (xi >= fabs(eta)) { omega = eta/xi; tau = 1.0 + omega*omega; xf = sqrt(rhu/(1.0-1.0/sqrt(1.0+tau))); yf = (xf/15.0)*(astATand(omega) - astASind(omega/sqrt(tau+tau))); } else if (-eta > fabs(xi)) { omega = xi/eta; tau = 1.0 + omega*omega; yf = -sqrt(rhu/(1.0-1.0/sqrt(1.0+tau))); xf = (yf/15.0)*(astATand(omega) - astASind(omega/sqrt(tau+tau))); } else if (eta > fabs(xi)) { omega = xi/eta; tau = 1.0 + omega*omega; yf = sqrt(rhu/(1.0-1.0/sqrt(1.0+tau))); xf = (yf/15.0)*(astATand(omega) - astASind(omega/sqrt(tau+tau))); } if (fabs(xf) > 1.0) { if (fabs(xf) > 1.0+tol) { return 2; } xf = copysign(1.0,xf); } if (fabs(yf) > 1.0) { if (fabs(yf) > 1.0+tol) { return 2; } yf = copysign(1.0,yf); } *x = prj->w[0]*(xf + x0); *y = prj->w[0]*(yf + y0); return 0; } /*--------------------------------------------------------------------------*/ int astQSCrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { int direct, face; double l, m, n, omega, rho, rhu, tau, xf, yf, w; const double tol = 1.0e-12; l = 0.0; m = 0.0; n = 0.0; if (prj->flag != WCS__QSC) { if (astQSCset(prj)) return 1; } xf = x*prj->w[1]; yf = y*prj->w[1]; /* Check bounds. */ if (fabs(xf) <= 1.0) { if (fabs(yf) > 3.0) return 2; } else { if (fabs(xf) > 7.0) return 2; if (fabs(yf) > 1.0) return 2; } /* Map negative faces to the other side. */ if (xf < -1.0) xf += 8.0; /* Determine the face. */ if (xf > 5.0) { face = 4; xf = xf - 6.0; } else if (xf > 3.0) { face = 3; xf = xf - 4.0; } else if (xf > 1.0) { face = 2; xf = xf - 2.0; } else if (yf > 1.0) { face = 0; yf = yf - 2.0; } else if (yf < -1.0) { face = 5; yf = yf + 2.0; } else { face = 1; } direct = (fabs(xf) > fabs(yf)); if (direct) { if (xf == 0.0) { omega = 0.0; tau = 1.0; rho = 1.0; rhu = 0.0; } else { w = 15.0*yf/xf; omega = astSind(w)/(astCosd(w) - SQRT2INV); tau = 1.0 + omega*omega; rhu = xf*xf*(1.0 - 1.0/sqrt(1.0 + tau)); rho = 1.0 - rhu; } } else { if (yf == 0.0) { omega = 0.0; tau = 1.0; rho = 1.0; rhu = 0.0; } else { w = 15.0*xf/yf; omega = astSind(w)/(astCosd(w) - SQRT2INV); tau = 1.0 + omega*omega; rhu = yf*yf*(1.0 - 1.0/sqrt(1.0 + tau)); rho = 1.0 - rhu; } } if (rho < -1.0) { if (rho < -1.0-tol) { return 2; } rho = -1.0; rhu = 2.0; w = 0.0; } else { w = sqrt(rhu*(2.0-rhu)/tau); } if (face == 0) { n = rho; if (direct) { m = w; if (xf < 0.0) m = -m; l = -m*omega; } else { l = w; if (yf > 0.0) l = -l; m = -l*omega; } } else if (face == 1) { l = rho; if (direct) { m = w; if (xf < 0.0) m = -m; n = m*omega; } else { n = w; if (yf < 0.0) n = -n; m = n*omega; } } else if (face == 2) { m = rho; if (direct) { l = w; if (xf > 0.0) l = -l; n = -l*omega; } else { n = w; if (yf < 0.0) n = -n; l = -n*omega; } } else if (face == 3) { l = -rho; if (direct) { m = w; if (xf > 0.0) m = -m; n = -m*omega; } else { n = w; if (yf < 0.0) n = -n; m = -n*omega; } } else if (face == 4) { m = -rho; if (direct) { l = w; if (xf < 0.0) l = -l; n = l*omega; } else { n = w; if (yf < 0.0) n = -n; l = n*omega; } } else if (face == 5) { n = -rho; if (direct) { m = w; if (xf < 0.0) m = -m; l = m*omega; } else { l = w; if (yf < 0.0) l = -l; m = l*omega; } } if (l == 0.0 && m == 0.0) { *phi = 0.0; } else { *phi = astATan2d(m, l); } *theta = astASind(n); return 0; } /*============================================================================ * HPX: HEALPix projection. * * Given: * prj->p[1] H - the number of facets in longitude. * prj->p[2] K - the number of facets in latitude * * Given and/or returned: * prj->r0 Reset to 180/pi if 0. * prj->phi0 Reset to 0.0 * prj->theta0 Reset to 0.0 * * Returned: * prj->flag HPX * prj->code "HPX" * prj->n True if K is odd. * prj->w[0] r0*(pi/180) * prj->w[1] (180/pi)/r0 * prj->w[2] (K-1)/K * prj->w[3] 90*K/H * prj->w[4] (K+1)/2 * prj->w[5] 90*(K-1)/H * prj->w[6] 180/H * prj->w[7] H/360 * prj->w[8] (90*K/H)*r0*(pi/180) * prj->w[9] (180/H)*r0*(pi/180) * prj->astPRJfwd Pointer to astHPXfwd(). * prj->astPRJrev Pointer to astHPXrev(). *===========================================================================*/ int astHPXset(prj) struct AstPrjPrm *prj; { strcpy(prj->code, "HPX"); prj->flag = WCS__HPX; prj->phi0 = 0.0; prj->theta0 = 0.0; prj->n = ((int)prj->p[2])%2; if (prj->r0 == 0.0) { prj->r0 = R2D; prj->w[0] = 1.0; prj->w[1] = 1.0; } else { prj->w[0] = prj->r0*D2R; prj->w[1] = R2D/prj->r0; } prj->w[2] = (prj->p[2] - 1.0) / prj->p[2]; prj->w[3] = 90.0 * prj->p[2] / prj->p[1]; prj->w[4] = (prj->p[2] + 1.0) / 2.0; prj->w[5] = 90.0 * (prj->p[2] - 1.0) / prj->p[1]; prj->w[6] = 180.0 / prj->p[1]; prj->w[7] = prj->p[1] / 360.0; prj->w[8] = prj->w[3] * prj->w[0]; prj->w[9] = prj->w[6] * prj->w[0]; prj->astPRJfwd = astHPXfwd; prj->astPRJrev = astHPXrev; return 0; } /*--------------------------------------------------------------------------*/ int astHPXfwd(phi, theta, prj, x, y) const double phi, theta; struct AstPrjPrm *prj; double *x, *y; { double abssin, sigma, sinthe, phic; int hodd; if( prj->flag != WCS__HPX ) { if( astHPXset( prj ) ) return 1; } sinthe = astSind( theta ); abssin = fabs( sinthe ); /* Equatorial zone */ if( abssin <= prj->w[2] ) { *x = prj->w[0] * phi; *y = prj->w[8] * sinthe; /* Polar zone */ } else { /* DSB - The expression for phic is conditioned differently to the WCSLIB code in order to improve accuracy of the floor function for arguments very slightly below an integer value. */ hodd = ((int)prj->p[1]) % 2; if( !prj->n && theta <= 0.0 ) hodd = 1 - hodd; if( hodd ) { phic = -180.0 + (2.0*floor( prj->w[7] * phi + 1/2 ) + prj->p[1] ) * prj->w[6]; } else { phic = -180.0 + (2.0*floor( prj->w[7] * phi ) + prj->p[1] + 1 ) * prj->w[6]; } sigma = sqrt( prj->p[2]*( 1.0 - abssin )); *x = prj->w[0] *( phic + ( phi - phic )*sigma ); *y = prj->w[9] * ( prj->w[4] - sigma ); if( theta < 0 ) *y = -*y; } return 0; } /*--------------------------------------------------------------------------*/ int astHPXrev(x, y, prj, phi, theta) const double x, y; struct AstPrjPrm *prj; double *phi, *theta; { double absy, sigma, t, yr, xc; int hodd; if (prj->flag != WCS__HPX) { if (astHPXset(prj)) return 1; } yr = prj->w[1]*y; absy = fabs( yr ); /* Equatorial zone */ if( absy <= prj->w[5] ) { *phi = prj->w[1] * x; t = yr/prj->w[3]; if( t < -1.0 || t > 1.0 ) { return 2; } else { *theta = astASind( t ); } /* Polar zone */ } else if( absy <= 90 ){ /* DSB - The expression for xc is conditioned differently to the WCSLIB code in order to improve accuracy of the floor function for arguments very slightly below an integer value. */ hodd = ((int)prj->p[1]) % 2; if( !prj->n && yr <= 0.0 ) hodd = 1 - hodd; if( hodd ) { xc = -180.0 + (2.0*floor( prj->w[7] * x + 1/2 ) + prj->p[1] ) * prj->w[6]; } else { xc = -180.0 + (2.0*floor( prj->w[7] * x ) + prj->p[1] + 1 ) * prj->w[6]; } sigma = prj->w[4] - absy / prj->w[6]; if( sigma == 0.0 ) { return 2; } else { t = ( x - xc )/sigma; if( fabs( t ) <= prj->w[6] ) { *phi = prj->w[1] *( xc + t ); } else { return 2; } } t = 1.0 - sigma*sigma/prj->p[2]; if( t < -1.0 || t > 1.0 ) { return 2; } else { *theta = astASind( t ); if( y < 0 ) *theta = -*theta; } } else { return 2; } return 0; } ./ast-7.3.3/fspecframe.c0000644000175000017500000000756612262533650013437 0ustar olesoles/* *+ * Name: * fspecframe.c * Purpose: * Define a FORTRAN 77 interface to the AST SpecFrame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the SpecFrame class. * Routines Defined: * AST_ISASPECFRAME * AST_SPECFRAME * AST_SETREFPOS * AST_GETREFPOS * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 20-NOV-2002 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "specframe.h" /* C interface to the SpecFrame class */ F77_LOGICAL_FUNCTION(ast_isaspecframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASPECFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsASpecFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_specframe)( CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_SPECFRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astSpecFrame( "%s", options ) ); astFree( options ); ) return RESULT; } F77_SUBROUTINE(ast_getrefpos)( INTEGER(THIS), INTEGER(FRM), DOUBLE(LON), DOUBLE(LAT), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(FRM) GENPTR_DOUBLE(LON) GENPTR_DOUBLE(LAT) astAt( "AST_GETREFPOS", NULL, 0 ); astWatchSTATUS( astGetRefPos( astI2P( *THIS ), astI2P( *FRM ), LON, LAT ); ) } F77_SUBROUTINE(ast_setrefpos)( INTEGER(THIS), INTEGER(FRM), DOUBLE(LON), DOUBLE(LAT), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_INTEGER(FRM) GENPTR_DOUBLE(LON) GENPTR_DOUBLE(LAT) astAt( "AST_SETREFPOS", NULL, 0 ); astWatchSTATUS( astSetRefPos( astI2P( *THIS ), astI2P( *FRM ), *LON, *LAT ); ) } ./ast-7.3.3/timemap.h0000644000175000017500000002055312262533650012754 0ustar olesoles#if !defined( TIMEMAP_INCLUDED ) /* Include this file only once */ #define TIMEMAP_INCLUDED /* *+ * Name: * timemap.h * Type: * C include file. * Purpose: * Define the interface to the TimeMap class. * Invocation: * #include "timemap.h" * Description: * This include file defines the interface to the TimeMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The TimeMap class encapsulates various time coordinate * conversions. Since, typically, a sequence of these conversions is * required, a TimeMap can be used to accumulate a series of conversions * which it then applies in sequence. * Inheritance: * The TimeMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * astTransform * Use an TimeMap to transform a set of points. * Protected: * astMapMerge * Simplify a sequence of Mappings containing an TimeMap. * New Methods Defined: * Public: * astTimeAdd * Add a coordinate conversion step to an TimeMap. * Private: * None. * Other Class Functions: * Public: * astIsATimeMap * Test class membership. * astTimeMap * Create an TimeMap. * Protected: * astCheckTimeMap * Validate class membership. * astInitTimeMap * Initialise an TimeMap. * astLoadTimeMap * Load an TimeMap. * Macros: * None. * Type Definitions: * Public: * AstTimeMap * TimeMap object type. * Protected: * AstTimeMapVtab * TimeMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 24-MAY-2005 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* TimeMap structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstTimeMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ int *cvttype; /* Pointer to array of conversion types */ double **cvtargs; /* Pointer to argument list pointer array */ int ncvt; /* Number of conversions to perform */ } AstTimeMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstTimeMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* TimeAdd)( AstTimeMap *, const char *, const double[], int * ); } AstTimeMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstTimeMapGlobals { AstTimeMapVtab Class_Vtab; int Class_Init; } AstTimeMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitTimeMapGlobals_( AstTimeMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(TimeMap) /* Check class membership */ astPROTO_ISA(TimeMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstTimeMap *astTimeMap_( int, const char *, int *, ...); #else AstTimeMap *astTimeMapId_( int, const char *, ... )__attribute__((format(printf,2,3))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstTimeMap *astInitTimeMap_( void *, size_t, int, AstTimeMapVtab *, const char *, int, int * ); /* Vtab initialiser. */ void astInitTimeMapVtab_( AstTimeMapVtab *, const char *, int * ); /* Loader. */ AstTimeMap *astLoadTimeMap_( void *, size_t, AstTimeMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astTimeAdd_( AstTimeMap *, const char *, const double[], int * ); #if defined(astCLASS) /* Protected. */ double astDat_( double, int, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckTimeMap(this) astINVOKE_CHECK(TimeMap,this,0) #define astVerifyTimeMap(this) astINVOKE_CHECK(TimeMap,this,1) /* Test class membership. */ #define astIsATimeMap(this) astINVOKE_ISA(TimeMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astTimeMap astINVOKE(F,astTimeMap_) #else #define astTimeMap astINVOKE(F,astTimeMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitTimeMap(mem,size,init,vtab,name,flags) \ astINVOKE(O,astInitTimeMap_(mem,size,init,vtab,name,flags,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitTimeMapVtab(vtab,name) astINVOKE(V,astInitTimeMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadTimeMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadTimeMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckTimeMap to validate TimeMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astTimeAdd(this,cvt,args) \ astINVOKE(V,astTimeAdd_(astCheckTimeMap(this),cvt,args,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astDat(in,forward) astDat_(in,forward,STATUS_PTR) #endif #endif ./ast-7.3.3/ftimeframe.c0000644000175000017500000000644012262533650013431 0ustar olesoles/* *+ * Name: * ftimeframe.c * Purpose: * Define a FORTRAN 77 interface to the AST TimeFrame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the TimeFrame class. * Routines Defined: * AST_ISATIMEFRAME * AST_TIMEFRAME * AST_CURRENTTIME * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * NG: Norman Gray (Starlink) * History: * 02-AUG-2003 (NG): * Original version, heavily based on fspecframe.c. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "timeframe.h" /* C interface to the TimeFrame class */ F77_LOGICAL_FUNCTION(ast_isatimeframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISATIMEFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsATimeFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_timeframe)( CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_TIMEFRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astTimeFrame( "%s", options ) ); astFree( options ); ) return RESULT; } F77_DOUBLE_FUNCTION(ast_currenttime)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_DOUBLE_TYPE(RESULT); astAt( "AST_CURRENTTIME", NULL, 0 ); astWatchSTATUS( RESULT = astCurrentTime( astI2P( *THIS ) ); ) return RESULT; } ./ast-7.3.3/pcdmap.c0000644000175000017500000032437112262533650012564 0ustar olesoles/* *class++ * Name: * PcdMap * Purpose: * Apply 2-dimensional pincushion/barrel distortion. * Constructor Function: c astPcdMap f AST_PCDMAP * Description: * A PcdMap is a non-linear Mapping which transforms 2-dimensional * positions to correct for the radial distortion introduced by some * cameras and telescopes. This can take the form either of pincushion * or barrel distortion, and is characterized by a single distortion * coefficient. * * A PcdMap is specified by giving this distortion coefficient and the * coordinates of the centre of the radial distortion. The forward * transformation of a PcdMap applies the distortion: * * RD = R * ( 1 + C * R * R ) * * where R is the undistorted radial distance from the distortion * centre (specified by attribute PcdCen), RD is the radial distance * from the same centre in the presence of distortion, and C is the * distortion coefficient (given by attribute Disco). * * The inverse transformation of a PcdMap removes the distortion * produced by the forward transformation. The expression used to derive * R from RD is an approximate inverse of the expression above. * Inheritance: * The PcdMap class inherits from the Mapping class. * Attributes: * In addition to those attributes common to all Mappings, every * PcdMap also has the following attributes: * * - Disco: PcdMap pincushion/barrel distortion coefficient * - PcdCen(axis): Centre coordinates of pincushion/barrel distortion * Functions: c The PcdMap class does not define any new functions beyond those f The PcdMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * History: * 18-MAY-1999 (DSB): * Original version. * 25-OCT-1999 (DSB): * Fixed memory leak in MapMerge. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitPcdMapVtab * method. * 23-AUG-2006 (DSB): * Override astEqual. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS PcdMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory management facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "unitmap.h" /* Unit mappings */ #include "zoommap.h" /* Zoom mappings */ #include "permmap.h" /* Axis permutations */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "pcdmap.h" /* Interface definition for this class */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(PcdMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(PcdMap,Class_Init) #define class_vtab astGLOBAL(PcdMap,Class_Vtab) #define getattrib_buff astGLOBAL(PcdMap,GetAttrib_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstPcdMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstPcdMap *astPcdMapId_( double, const double [2], const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static double GetDisco( AstPcdMap *, int * ); static double GetPcdCen( AstPcdMap *, int, int * ); static int CanMerge( AstMapping *, AstMapping *, int, int, int * ); static int CanSwap( AstMapping *, AstMapping *, int, int, int * ); static int Equal( AstObject *, AstObject *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int TestDisco( AstPcdMap *, int * ); static int TestPcdCen( AstPcdMap *, int, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void ClearDisco( AstPcdMap *, int * ); static void ClearPcdCen( AstPcdMap *, int, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void PcdPerm( AstMapping **, int *, int, int * ); static void PcdZoom( AstMapping **, int *, int, int * ); static void PermGet( AstPermMap *, int **, int **, double **, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SetDisco( AstPcdMap *, double, int * ); static void SetPcdCen( AstPcdMap *, int, double, int * ); /* Function Macros */ /* =============== */ /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* * * Name: * MAKE_CLEAR * Purpose: * Implement a method to clear a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "pcdmap.h" * MAKE_CLEAR(attr,component,assign,nval) * Class Membership: * Defined by the PcdMap class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Clear( AstPcdMap *this, int axis ) * * and an external interface function of the form: * * void astClear_( AstPcdMap *this, int axis ) * * which implement a method for clearing a single value in a specified * multi-valued attribute for an axis of a PcdMap. * Parameters: * attr * The name of the attribute to be cleared, as it appears in the function * name (e.g. PcdCen in "astClearPcdCen"). * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to assign to the component * to clear its value. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_CLEAR(attr,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Clear##attr( AstPcdMap *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= nval ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astClear" #attr, astGetClass( this ), \ axis + 1, nval ); \ \ /* Assign the "clear" value. */ \ } else { \ this->component[ axis ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astClear##attr##_( AstPcdMap *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,PcdMap,Clear##attr))( this, axis, status ); \ } /* * * Name: * MAKE_GET * Purpose: * Implement a method to get a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "pcdmap.h" * MAKE_GET(attr,type,bad_value,assign,nval) * Class Membership: * Defined by the PcdMap class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static Get( AstPcdMap *this, int axis ) * * and an external interface function of the form: * * astGet_( AstPcdMap *this, int axis ) * * which implement a method for getting a single value from a specified * multi-valued attribute for an axis of a PcdMap. * Parameters: * attr * The name of the attribute whose value is to be obtained, as it * appears in the function name (e.g. PcdCen in "astGetPcdCen"). * type * The C type of the attribute. * bad_value * A constant value to return if the global error status is set, or if * the function fails. * assign * An expression that evaluates to the value to be returned. This can * use the string "axis" to represent the zero-based value index. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. * */ /* Define the macro. */ #define MAKE_GET(attr,type,bad_value,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static type Get##attr( AstPcdMap *this, int axis, int *status ) { \ type result; /* Result to be returned */ \ \ /* Initialise */ \ result = (bad_value); \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= nval ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astGet" #attr, astGetClass( this ), \ axis + 1, nval ); \ \ /* Assign the result value. */ \ } else { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = (bad_value); \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ type astGet##attr##_( AstPcdMap *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return (bad_value); \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,PcdMap,Get##attr))( this, axis, status ); \ } /* * * Name: * MAKE_SET * Purpose: * Implement a method to set a single value in a multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "pcdmap.h" * MAKE_SET(attr,type,component,assign,nval) * Class Membership: * Defined by the PcdMap class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static void Set( AstPcdMap *this, int axis, value ) * * and an external interface function of the form: * * void astSet_( AstPcdMap *this, int axis, value ) * * which implement a method for setting a single value in a specified * multi-valued attribute for a PcdMap. * Parameters: * attr * The name of the attribute to be set, as it appears in the function * name (e.g. PcdCen in "astSetPcdCen"). * type * The C type of the attribute. * component * The name of the class structure component that holds the attribute * value. * assign * An expression that evaluates to the value to be assigned to the * component. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_SET(attr,type,component,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static void Set##attr( AstPcdMap *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= nval ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astSet" #attr, astGetClass( this ), \ axis + 1, nval ); \ \ /* Store the new value in the structure component. */ \ } else { \ this->component[ axis ] = (assign); \ } \ } \ \ /* External interface. */ \ /* ------------------- */ \ void astSet##attr##_( AstPcdMap *this, int axis, type value, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Invoke the required method via the virtual function table. */ \ (**astMEMBER(this,PcdMap,Set##attr))( this, axis, value, status ); \ } /* * * Name: * MAKE_TEST * Purpose: * Implement a method to test if a single value has been set in a * multi-valued attribute. * Type: * Private macro. * Synopsis: * #include "pcdmap.h" * MAKE_TEST(attr,assign,nval) * Class Membership: * Defined by the PcdMap class. * Description: * This macro expands to an implementation of a private member function of * the form: * * static int Test( AstPcdMap *this, int axis ) * * and an external interface function of the form: * * int astTest_( AstPcdMap *this, int axis ) * * which implement a method for testing if a single value in a specified * multi-valued attribute has been set for a class. * Parameters: * attr * The name of the attribute to be tested, as it appears in the function * name (e.g. PcdCen in "astTestPcdCen"). * assign * An expression that evaluates to 0 or 1, to be used as the returned * value. This can use the string "axis" to represent the zero-based * index of the value within the attribute. * nval * Specifies the number of values in the multi-valued attribute. The * "axis" values supplied to the created function should be in the * range zero to (nval - 1). * Notes: * - To avoid problems with some compilers, you should not leave any white * space around the macro arguments. *- */ /* Define the macro. */ #define MAKE_TEST(attr,assign,nval) \ \ /* Private member function. */ \ /* ------------------------ */ \ static int Test##attr( AstPcdMap *this, int axis, int *status ) { \ int result; /* Value to return */ \ \ /* Initialise */ \ result = 0; \ \ /* Check the global error status. */ \ if ( !astOK ) return result; \ \ \ /* Validate the axis index. */ \ if( axis < 0 || axis >= nval ){ \ astError( AST__AXIIN, "%s(%s): Index (%d) is invalid for attribute " \ #attr " - it should be in the range 1 to %d.", status, \ "astTest" #attr, astGetClass( this ), \ axis + 1, nval ); \ \ /* Assign the result value. */ \ } else { \ result = (assign); \ } \ \ /* Check for errors and clear the result if necessary. */ \ if ( !astOK ) result = 0; \ \ /* Return the result. */ \ return result; \ } \ /* External interface. */ \ /* ------------------- */ \ int astTest##attr##_( AstPcdMap *this, int axis, int *status ) { \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Invoke the required method via the virtual function table. */ \ return (**astMEMBER(this,PcdMap,Test##attr))( this, axis, status ); \ } /* Member functions. */ /* ================= */ static int CanMerge( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int *status ){ /* * * Name: * CanMerge * Purpose: * Checks if two Mappings can be merged. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * int CanMerge( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int *status ) * Class Membership: * PcdMap internal utility function. * Description: * This function checks the two supplied Mappings to see if they * can be merged into a single Mapping. One of the pair must be a PcdMap. * Parameters: * map1 * A pointer to the first mapping. * map2 * A pointer to the second mapping. * inv1 * The invert flag to use with the first mapping. * inv2 * The invert flag to use with the second mapping. * status * Pointer to the inherited status variable. * Returned Value: * 1 if the Mappings can be merged, zero otherwise. */ AstPcdMap *pcd; /* Pointer to PcdMap Mapping */ AstPcdMap *pcd2; /* Pointer to second PcdMap Mapping */ AstMapping *nopcd; /* Pointer to non-PcdMap Mapping */ const char *class1; /* Pointer to map1 class string */ const char *class2; /* Pointer to map2 class string */ const char *nopcd_class; /* Pointer to non-PcdMap class string */ int invert[ 2 ]; /* Original invert flags */ int ret; /* Returned flag */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise */ ret = 0; pcd = NULL; nopcd = NULL; /* Temporarily set the Invert attributes of both Mappings to the supplied values. */ invert[ 0 ] = astGetInvert( map1 ); astSetInvert( map1, inv1 ); invert[ 1 ] = astGetInvert( map2 ); astSetInvert( map2, inv2 ); /* Get the classes of the two mappings. */ class1 = astGetClass( map1 ); class2 = astGetClass( map2 ); if( astOK ){ /* Get pointers to the PcdMap and the non-PcdMap Mapping. */ if( !strcmp( class1, "PcdMap" ) ){ pcd = (AstPcdMap * ) map1; nopcd = map2; nopcd_class = class2; } else if( !strcmp( class2, "PcdMap" ) ){ nopcd = map1; pcd = (AstPcdMap * ) map2; nopcd_class = class1; } else { nopcd_class = "unusable"; } /* The Mappings can merge if the other Mapping is a UnitMap. */ if( !strcmp( nopcd_class, "UnitMap" ) ){ ret = 1; /* They can also merge if the other Mapping is also a PcdMap, and is the invert of the other. */ } else if( !strcmp( nopcd_class, "PcdMap" ) ){ pcd2 = (AstPcdMap *) nopcd; /* Check the distortion coefficients are equal. */ if( EQUAL( astGetDisco( pcd ), astGetDisco( pcd2 ) ) ){ /* Check the axis 0 centres are equal. */ if( EQUAL( astGetPcdCen( pcd, 0 ), astGetPcdCen( pcd2, 0 ) ) ){ /* Check the axis 1 centres are equal. */ if( EQUAL( astGetPcdCen( pcd, 1 ), astGetPcdCen( pcd2, 1 ) ) ){ /* Check the Invert flags are different. */ if( astGetInvert( pcd ) != astGetInvert( pcd2 ) ){ /* If the Mappings have passed all these tests, they can be merged. */ ret = 1; } } } } } } /* Re-instate the original settings of the Invert attributes for the supplied Mappings. */ astSetInvert( map1, invert[ 0 ] ); astSetInvert( map2, invert[ 1 ] ); /* Return the answer. */ return astOK ? ret : 0; } static int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int *status ){ /* * Name: * CanSwap * Purpose: * Determine if two Mappings could be swapped. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * int CanSwap( AstMapping *map1, AstMapping *map2, int inv1, int inv2, int *status ) * Class Membership: * PcdMap member function * Description: * This function returns a flag indicating if the pair of supplied * Mappings could be replaced by an equivalent pair of Mappings from the * same classes as the supplied pair, but in reversed order. Each pair * of Mappings is considered to be compounded in series. The supplied * Mappings are not changed in any way. * Parameters: * map1 * The Mapping to be applied first. * map2 * The Mapping to be applied second. * inv1 * The invert flag to use with map1. A value of zero causes the forward * mapping to be used, and a non-zero value causes the inverse * mapping to be used. * inv2 * The invert flag to use with map2. * status * Pointer to the inherited status variable. * Returned Value: * 1 if the Mappings could be swapped, 0 otherwise. * Notes: * - One of the supplied pair of Mappings must be a PcdMap. * - A value of 0 is returned if the two Mappings could be merged into * a single Mapping. * - A value of 0 is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstMapping *nopcd; /* Pointer to non-PcdMap Mapping */ const char *class1; /* Pointer to map1 class string */ const char *class2; /* Pointer to map2 class string */ const char *nopcd_class; /* Pointer to non-PcdMap class string */ double *consts; /* Pointer to constants array */ int *inperm; /* Pointer to input axis permutation array */ int *outperm; /* Pointer to output axis permutation array */ int invert[ 2 ]; /* Original invert flags */ int nin; /* No. of input coordinates for the PermMap */ int nout; /* No. of output coordinates for the PermMap */ int pcdinv; /* Use inverted PcdMap? */ int ret; /* Returned flag */ /* Check the global error status. */ if ( !astOK ) return 0; /* Initialise */ ret = 0; /* Temporarily set the Invert attributes of both Mappings to the supplied values. */ invert[ 0 ] = astGetInvert( map1 ); astSetInvert( map1, inv1 ); invert[ 1 ] = astGetInvert( map2 ); astSetInvert( map2, inv2 ); /* Get the classes of the two mappings. */ class1 = astGetClass( map1 ); class2 = astGetClass( map2 ); if( astOK ){ /* Get a pointer to the non-PcdMap Mapping. */ if( !strcmp( class1, "PcdMap" ) ){ nopcd = map2; nopcd_class = class2; pcdinv = inv1; } else { nopcd = map1; nopcd_class = class1; pcdinv = inv2; } /* If the other Mapping is a ZoomMap, the Mappings can be swapped. */ if( !strcmp( nopcd_class, "ZoomMap" ) ){ ret = 1; /* If it is a PermMap, the Mappings can be swapped so long as the PermMap simply swaps the two axes. */ } else if( !strcmp( nopcd_class, "PermMap" ) ){ /* Get the number of input and output coordinates for the PermMap. */ nin = astGetNin( nopcd ); nout = astGetNout( nopcd ); /* Must be 2-dimensional to swap. */ if( nin == 2 && nout == 2 ) { /* Get the axis permutation arrays and constants array for the PermMap. */ PermGet( (AstPermMap *) nopcd, &outperm, &inperm, &consts, status ); if( astOK ) { /* If the PermMap simply swaps the 2 axes (in both direction) we can swap the two mappings. */ ret = ( outperm[0] == 1 && outperm[1] == 0 && inperm[0] == 1 && inperm[1] == 0 ); /* Free the axis permutation and constants arrays. */ outperm = (int *) astFree( (void *) outperm ); inperm = (int *) astFree( (void *) inperm ); consts = (double *) astFree( (void *) consts ); } } } } /* Re-instate the original settings of the Invert attributes for the supplied Mappings. */ astSetInvert( map1, invert[ 0 ] ); astSetInvert( map2, invert[ 1 ] ); /* Return the answer. */ return astOK ? ret : 0; } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a PcdMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * PcdMap member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * PcdMap, so that the default value will subsequently be used. * Parameters: * this * Pointer to the PcdMap. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPcdMap *this; /* Pointer to the PcdMap structure */ int axis; /* Axis number */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the PcdMap structure. */ this = (AstPcdMap *) this_object; /* Obtain the length of the "attrib" string. */ len = strlen( attrib ); /* Check the attribute name and clear the appropriate attribute. */ /* PcdCen(axis). */ /* ------------- */ if ( nc = 0, ( 1 == astSscanf( attrib, "pcdcen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { astClearPcdCen( this, axis - 1 ); /* PcdCen. */ /* ------- */ } else if ( !strcmp( attrib, "pcdcen" ) ) { astClearPcdCen( this, 0 ); astClearPcdCen( this, 1 ); /* Disco. */ /* ------ */ } else if ( !strcmp( attrib, "disco" ) ) { astClearDisco( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two PcdMaps are equivalent. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * int Equal( AstObject *this, AstObject *that, int *status ) * Class Membership: * PcdMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two PcdMaps are equivalent. * Parameters: * this * Pointer to the first Object (a PcdMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * Returned Value: * One if the PcdMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstPcdMap *that; AstPcdMap *this; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two PcdMap structures. */ this = (AstPcdMap *) this_object; that = (AstPcdMap *) that_object; /* Check the second object is a PcdMap. We know the first is a PcdMap since we have arrived at this implementation of the virtual function. */ if( astIsAPcdMap( that ) ) { /* Check the Invert flags for the two PcdMaps are equal. */ if( astGetInvert( this ) == astGetInvert( that ) ) { /* Check all the attributes are equal. */ if( astEQUAL( this->pcdcen[0], that->pcdcen[0] ) && astEQUAL( this->pcdcen[1], that->pcdcen[1] ) && astEQUAL( this->disco, that->disco ) ) { result = 1; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a PcdMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * PcdMap member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a PcdMap, formatted as a character string. * Parameters: * this * Pointer to the PcdMap. * attrib * Pointer to a null terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the PcdMap, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the PcdMap. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPcdMap *this; /* Pointer to the PcdMap structure */ const char *result; /* Pointer value to return */ double dval; /* Double attribute value */ int axis; /* Axis number */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the PcdMap structure. */ this = (AstPcdMap *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Compare "attrib" with each recognised attribute name in turn, obtaining the value of the required attribute. If necessary, write the value into "getattrib_buff" as a null terminated string in an appropriate format. Set "result" to point at the result string. */ /* Disco. */ /* ------ */ if ( !strcmp( attrib, "disco" ) ) { dval = astGetDisco( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* PcdCen(axis). */ /* ------------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "pcdcen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { dval = astGetPcdCen( this, axis - 1 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* PcdCen. */ /* ------- */ } else if ( !strcmp( attrib, "pcdcen" ) ) { dval = astGetPcdCen( this, 0 ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } void astInitPcdMapVtab_( AstPcdMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitPcdMapVtab * Purpose: * Initialise a virtual function table for a PcdMap. * Type: * Protected function. * Synopsis: * #include "pcdmap.h" * void astInitPcdMapVtab( AstPcdMapVtab *vtab, const char *name ) * Class Membership: * PcdMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the PcdMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAPcdMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearDisco = ClearDisco; vtab->SetDisco = SetDisco; vtab->GetDisco = GetDisco; vtab->TestDisco = TestDisco; vtab->ClearPcdCen = ClearPcdCen; vtab->SetPcdCen = SetPcdCen; vtab->GetPcdCen = GetPcdCen; vtab->TestPcdCen = TestPcdCen; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; object->Equal = Equal; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ mapping->MapMerge = MapMerge; /* Declare the class dump function.*/ astSetDump( vtab, Dump, "PcdMap", "Apply pincushion distortion" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a PcdMap. * Type: * Private function. * Synopsis: * #include "mapping.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status ) * Class Membership: * PcdMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated PcdMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated PcdMap with a Mapping which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated PcdMap which is to be merged with * its neighbours. This should be a cloned copy of the PcdMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * PcdMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated PcdMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping **maplt; /* New mappings list pointer */ AstMapping *map2; /* First mapping to check */ AstMapping *newmap; /* Pointer to replacement Mapping */ AstMapping *mc[2]; /* Copies of supplied Mappings to swap */ AstMapping *smc0; /* Simplied Mapping */ AstMapping *smc1; /* Simplied Mapping */ const char *class1; /* Pointer to first Mapping class string */ const char *class2; /* Pointer to second Mapping class string */ const char *nclass; /* Pointer to neighbouring Mapping class */ int i1; /* Index of first PcdMap to merge */ int i2; /* Index of last PcdMap to merge */ int i; /* Loop counter */ int ic[2]; /* Copies of supplied invert flags to swap */ int invert; /* Should the inverted Mapping be used? */ int *invlt; /* New invert flags list pointer */ int neighbour; /* Index of Mapping with which to swap */ int nin; /* Number of coordinates for PcdMap */ int nmapt; /* No. of Mappings in list */ int nstep1; /* No. of Mappings backwards to next mergable Mapping */ int nstep2; /* No. of Mappings forward to next mergable Mapping */ int result; /* Result value to return */ int swaphi; /* Can PcdMap be swapped with higher neighbour? */ int swaplo; /* Can PcdMap be swapped with lower neighbour? */ /* Initialise. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ neighbour = 0; i1 = 0; i2 = 0; /* Get the number of axes for the PcdMap. */ nin = astGetNin( ( *map_list )[ where ] ); /* First of all, see if the PcdMap can be replaced by a simpler Mapping, without reference to the neighbouring Mappings in the list. */ /* ======================================================================*/ /* If the distortion coefficient in the PcdMap is zero, the PcdMap can be replaced by a UnitMap. */ if( EQUAL( astGetDisco( (AstPcdMap *) ( *map_list )[ where ] ), 0.0 ) ){ /* Annul the PcdMap pointer in the list and replace it with a UnitMap pointer, and indicate that the forward transformation of the returned UnitMap should be used. */ (void) astAnnul( ( *map_list )[ where ] ); ( *map_list )[ where ] = (AstMapping *) astUnitMap( 2, "", status ); ( *invert_list )[ where ] = 0; /* Return the index of the first modified element. */ result = where; /* If the PcdMap itself could not be simplified, see if it can be merged with the Mappings on either side of it in the list. */ } else { /* Store the classes of the neighbouring Mappings in the list. */ class1 = ( where > 0 ) ? astGetClass( ( *map_list )[ where - 1 ] ) : NULL; class2 = ( where < *nmap - 1 ) ? astGetClass( ( *map_list )[ where + 1 ] ) : NULL; /* In series. */ /* ========== */ if ( series ) { /* We first look to see if the PcdMap can be merged with one of its neighbours, resulting in a reduction of one in the number of Mappings in the list. A PcdMap can only merge directly with its own inverse, or a UnitMap. */ if( class1 && CanMerge( ( *map_list )[ where - 1 ], ( *map_list )[ where ], ( *invert_list )[ where - 1 ], ( *invert_list )[ where ], status ) ){ nclass = class1; i1 = where - 1; i2 = where; } else if( class2 && CanMerge( ( *map_list )[ where ], ( *map_list )[ where + 1 ], ( *invert_list )[ where ], ( *invert_list )[ where + 1 ], status ) ){ nclass = class2; i1 = where; i2 = where + 1; } else { nclass = NULL; } /* If the PcdMap can merge with one of its neighbours, create the merged Mapping. */ if( nclass ){ /* If the neighbour is a PcdMap, it must be the inverse of the nominated Mapping, and so they merge to form a UnitMap. */ if( !strcmp( nclass, "PcdMap" ) ){ newmap = (AstMapping *) astUnitMap( 2, "", status ); invert = 0; /* If the neighbour is a UnitMap, they merge to form a clone of the nominated PcdMap. */ } else { newmap = (AstMapping *) astClone( ( *map_list )[ where ] ); invert = ( *invert_list )[ where ]; } /* If succesfull... */ if( astOK ){ /* Annul the first of the two Mappings, and replace it with the merged Mapping. Also set the invert flag. */ (void) astAnnul( ( *map_list )[ i1 ] ); ( *map_list )[ i1 ] = newmap; ( *invert_list )[ i1 ] = invert; /* Annul the second of the two Mappings, and shuffle down the rest of the list to fill the gap. */ (void) astAnnul( ( *map_list )[ i2 ] ); for ( i = i2 + 1; i < *nmap; i++ ) { ( *map_list )[ i - 1 ] = ( *map_list )[ i ]; ( *invert_list )[ i - 1 ] = ( *invert_list )[ i ]; } /* Clear the vacated element at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = i1; } /* If the PcdMap could not merge directly with either of its neighbours, we consider whether it would be worthwhile to swap the PcdMap with either of its neighbours. This can only be done for certain classes of Mapping (ZoomMaps & some PermMaps), and will usually require both Mappings to be modified (unless they are commutative). The advantage of swapping the order of the Mappings is that it may result in the PcdMap being adjacent to a Mapping with which it can merge directly on the next invocation of this function, thus reducing the number of Mappings in the list. */ } else { /* Set a flag if we could swap the PcdMap with its higher neighbour. */ if( where + 1 < *nmap ){ swaphi = CanSwap( ( *map_list )[ where ], ( *map_list )[ where + 1 ], ( *invert_list )[ where ], ( *invert_list )[ where + 1 ], status ); } else { swaphi = 0; } /* If so, step through each of the Mappings which follow the PcdMap, looking for a Mapping with which the PcdMap could merge directly. Stop when such a Mapping is found, or if a Mapping is found with which the PcdMap could definitely not swap. Note the number of Mappings which separate the PcdMap from the Mapping with which it could merge (if any). */ nstep2 = -1; if( swaphi ){ for( i2 = where + 1; i2 < *nmap; i2++ ){ /* See if we may be able to merge with this Mapping. If so, note the number of steps between the two Mappings and leave the loop. */ nclass = astGetClass( ( *map_list )[ i2 ] ); if( !strcmp( nclass, "UnitMap" ) || !strcmp( nclass, "PcdMap" ) ){ nstep2 = i2 - where - 1; break; } /* If there is no chance that we can swap with this Mapping, leave the loop with -1 for the number of steps to indicate that no merging is possible. PcdMaps can swap with ZoomMaps and some PermMaps. */ if( strcmp( nclass, "ZoomMap" ) && strcmp( nclass, "PermMap" ) ) { break; } } } /* Do the same working forward from the PcdMap towards the start of the map list. */ if( where > 0 ){ swaplo = CanSwap( ( *map_list )[ where - 1 ], ( *map_list )[ where ], ( *invert_list )[ where - 1 ], ( *invert_list )[ where ], status ); } else { swaplo = 0; } nstep1 = -1; if( swaplo ){ for( i1 = where - 1; i1 >= 0; i1-- ){ nclass = astGetClass( ( *map_list )[ i1 ] ); if( !strcmp( nclass, "UnitMap" ) || !strcmp( nclass, "PcdMap" ) ){ nstep1 = where - 1 - i1; break; } if( strcmp( nclass, "ZoomMap" ) && strcmp( nclass, "PermMap" ) ) { break; } } } /* Choose which neighbour to swap with so that the PcdMap moves towards the nearest Mapping with which it can merge. */ if( nstep1 != -1 && ( nstep2 == -1 || nstep2 > nstep1 ) ){ nclass = class1; i1 = where - 1; i2 = where; neighbour = i1; } else if( nstep2 != -1 ){ nclass = class2; i1 = where; i2 = where + 1; neighbour = i2; } else { nclass = NULL; } /* If there is a target Mapping in the list with which the PcdMap could merge, replace the supplied Mappings with swapped Mappings to bring a PcdMap closer to the target Mapping. */ if( nclass ){ /* It is possible that the neighbouring Mapping with which we are about to swap could also merge with the target Mapping. When the neighbouring Mapping is reconsidered it may well swap the pair back to put itself nearer the target Mapping. We need to be careful not to end up in an infinite loop in which the pair of neighbouring Mappings are constantly swapped backwards and forwards as each attempts to put itself closer to the target Mapping. To prevent this, we only swap the pair of Mappings if the neighbouring Mapping could not itself merge with the target Mapping. Check to see if this is the case by attempting to merge the neighbouring Mapping with the target Mapping. */ map2 = astClone( (*map_list)[ neighbour ] ); nmapt = *nmap - neighbour; maplt = *map_list + neighbour; invlt = *invert_list + neighbour; result = astMapMerge( map2, 0, series, &nmapt, &maplt, &invlt ); map2 = astAnnul( map2 ); /* If the above call produced a change in the Mapping list, return the remaining number of mappings.. */ if( result != -1 ){ *nmap = nmapt + neighbour; /* Otherwise, if there was no change in the mapping list, swap the Mappings. */ } else { if( !strcmp( nclass, "ZoomMap" ) ){ PcdZoom( (*map_list) + i1, (*invert_list) + i1, where - i1, status ); } else if( !strcmp( nclass, "PermMap" ) ){ PcdPerm( (*map_list) + i1, (*invert_list) + i1, where - i1, status ); } /* Store the index of the first modified Mapping. */ result = i1; } /* If there is no Mapping available for merging, it may still be advantageous to swap with a neighbour because the swapped Mapping may be simpler than the original Mappings. */ } else if( swaphi || swaplo ) { /* Try swapping with each possible neighbour in turn. */ for( i = 0; i < 2; i++ ) { /* Set up the class and pointers for the mappings to be swapped, first the lower neighbour, then the upper neighbour. */ if( i == 0 && swaplo ){ nclass = class1; i1 = where - 1; i2 = where; } else if( i == 1 && swaphi ){ nclass = class2; i1 = where; i2 = where + 1; } else { nclass = NULL; } /* If we have a Mapping to swap with... */ if( nclass ) { /* Take copies of the Mapping and Invert flag arrays so we do not change the supplied values. */ mc[ 0 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[0] ); mc[ 1 ] = (AstMapping *) astCopy( ( (*map_list) + i1 )[1] ); ic[ 0 ] = ( (*invert_list) + i1 )[0]; ic[ 1 ] = ( (*invert_list) + i1 )[1]; /* Swap these Mappings. */ if( !strcmp( nclass, "ZoomMap" ) ){ PcdZoom( mc, ic, where - i1, status ); } else if( !strcmp( nclass, "PermMap" ) ){ PcdPerm( mc, ic, where - i1, status ); } /* If neither of the swapped Mappings can be simplified further, then there is no point in swapping the Mappings, so just annul the map copies. */ smc0 = astSimplify( mc[0] ); smc1 = astSimplify( mc[1] ); if( astGetClass( smc0 ) == astGetClass( mc[0] ) && astGetClass( smc1 ) == astGetClass( mc[1] ) ) { mc[ 0 ] = (AstMapping *) astAnnul( mc[ 0 ] ); mc[ 1 ] = (AstMapping *) astAnnul( mc[ 1 ] ); /* If one or both of the swapped Mappings could be simplified, then annul the supplied Mappings and return the swapped mappings, storing the index of the first modified Mapping. */ } else { (void ) astAnnul( ( (*map_list) + i1 )[0] ); (void ) astAnnul( ( (*map_list) + i1 )[1] ); ( (*map_list) + i1 )[0] = mc[ 0 ]; ( (*map_list) + i1 )[1] = mc[ 1 ]; ( (*invert_list) + i1 )[0] = ic[ 0 ]; ( (*invert_list) + i1 )[1] = ic[ 1 ]; result = i1; break; } /* Annul the simplied Mappings */ smc0 = astAnnul( smc0 ); smc1 = astAnnul( smc1 ); } } } } /* In parallel. */ /* ============ */ /* PcdMaps cannot combine in parallel with any other Mappings. */ } } /* Return the result. */ return result; } static void PermGet( AstPermMap *map, int **outperm, int **inperm, double **consts, int *status ){ /* * Name: * PermGet * Purpose: * Get the axis permutation and constants array for a PermMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * void PermGet( AstPermMap *map, int **outperm, int **inperm, * double **const, int *status ) * Class Membership: * PcdMap member function * Description: * This function returns axis permutation and constants arrays which can * be used to create a PermMap which is equivalent to the supplied PermMap. * Parameters: * map * The PermMap. * outperm * An address at which to return a popinter to an array of ints * holding the output axis permutation array. The array should be * released using astFree when no longer needed. * inperm * An address at which to return a popinter to an array of ints * holding the input axis permutation array. The array should be * released using astFree when no longer needed. * consts * An address at which to return a popinter to an array of doubles * holding the constants array. The array should be released using * astFree when no longer needed. * status * Pointer to the inherited status variable. * Notes: * - NULL pointers are returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstPointSet *pset1; /* PointSet holding input positions for PermMap */ AstPointSet *pset2; /* PointSet holding output positions for PermMap */ double **ptr1; /* Pointer to pset1 data */ double **ptr2; /* Pointer to pset2 data */ double *cnst; /* Pointer to constants array */ double cn; /* Potential new constant value */ double ip; /* Potential output axis index */ double op; /* Potential input axis index */ int *inprm; /* Pointer to input axis permutation array */ int *outprm; /* Pointer to output axis permutation array */ int i; /* Axis count */ int nc; /* Number of constants stored so far */ int nin; /* No. of input coordinates for the PermMap */ int nout; /* No. of output coordinates for the PermMap */ /* Initialise. */ if( outperm ) *outperm = NULL; if( inperm ) *inperm = NULL; if( consts ) *consts = NULL; /* Check the global error status and the supplied pointers. */ if ( !astOK || !outperm || !inperm || !consts ) return; /* Initialise variables to avoid "used of uninitialised variable" messages from dumb compilers. */ nc = 0; /* Get the number of input and output axes for the supplied PermMap. */ nin = astGetNin( map ); nout = astGetNout( map ); /* Allocate the memory for the returned arrays. */ outprm = (int *) astMalloc( sizeof( int )* (size_t) nout ); inprm = (int *) astMalloc( sizeof( int )* (size_t) nin ); cnst = (double *) astMalloc( sizeof( double )* (size_t) ( nout + nin ) ); /* Returned the pointers to these arrays.*/ *outperm = outprm; *inperm = inprm; *consts = cnst; /* Create two PointSets, each holding two points, which can be used for input and output positions with the PermMap. */ pset1 = astPointSet( 2, nin, "", status ); pset2 = astPointSet( 2, nout, "", status ); /* Set up the two input positions to be [0,1,2...] and [-1,-1,-1,...]. The first position is used to enumerate the axes, and the second is used to check for constant axis values. */ ptr1 = astGetPoints( pset1 ); if( astOK ){ for( i = 0; i < nin; i++ ){ ptr1[ i ][ 0 ] = ( double ) i; ptr1[ i ][ 1 ] = -1.0; } } /* Use the PermMap to transform these positions in the forward direction. */ (void) astTransform( map, pset1, 1, pset2 ); /* Look at the mapped positions to determine the output axis permutation array. */ ptr2 = astGetPoints( pset2 ); if( astOK ){ /* No constant axis valeus found yet. */ nc = 0; /* Do each output axis. */ for( i = 0; i < nout; i++ ){ /* If the output axis value is copied from an input axis value, the index of the appropriate input axis will be in the mapped first position. */ op = ptr2[ i ][ 0 ]; /* If the output axis value is assigned a constant value, the result of mapping the two different input axis values will be the same. */ cn = ptr2[ i ][ 1 ]; if( op == cn ) { /* We have found another constant. Store it in the constants array, and store the index of the constant in the output axis permutation array. */ cnst[ nc ] = cn; outprm[ i ] = -( nc + 1 ); nc++; /* If the output axis values are different, then the output axis value must be copied from the input axis value. */ } else { outprm[ i ] = (int) ( op + 0.5 ); } } } /* Now do the same thing to determine the input permutation array. */ if( astOK ){ for( i = 0; i < nout; i++ ){ ptr2[ i ][ 0 ] = ( double ) i; ptr2[ i ][ 1 ] = -1.0; } } (void) astTransform( map, pset2, 0, pset1 ); if( astOK ){ for( i = 0; i < nin; i++ ){ ip = ptr1[ i ][ 0 ]; cn = ptr1[ i ][ 1 ]; if( ip == cn ) { cnst[ nc ] = cn; inprm[ i ] = -( nc + 1 ); nc++; } else { inprm[ i ] = (int) ( ip + 0.5 ); } } } /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* If an error has occurred, attempt to free the returned arrays. */ if( !astOK ) { *outperm = (int *) astFree( (void *) *outperm ); *inperm = (int *) astFree( (void *) *inperm ); *consts = (double *) astFree( (void *) *consts ); } /* Return. */ return; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a PcdMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * void SetAttrib( AstObject *this, const char *setting, int *status ) * Class Membership: * PcdMap member function (over-rides the astSetAttrib protected * method inherited from the Mapping class). * Description: * This function assigns an attribute value for a PcdMap, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the PcdMap. * setting * Pointer to a null terminated string specifying the new attribute * value. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPcdMap *this; /* Pointer to the PcdMap structure */ double dval; /* Double attribute value */ int axis; /* Index for the axis */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the PcdMap structure. */ this = (AstPcdMap *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Test for each recognised attribute in turn, using "astSscanf" to parse the setting string and extract the attribute value (or an offset to it in the case of string values). In each case, use the value set in "nc" to check that the entire string was matched. Once a value has been obtained, use the appropriate method to set it. */ /* Disco. */ /* ------ */ if ( nc = 0, ( 1 == astSscanf( setting, "disco= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetDisco( this, dval ); /* PcdCen(axis). */ /* ------------ */ } else if ( nc = 0, ( 2 == astSscanf( setting, "pcdcen(%d)= %lg %n", &axis, &dval, &nc ) ) && ( nc >= len ) ) { astSetPcdCen( this, axis - 1, dval ); /* PcdCen. */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "pcdcen= %lg %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetPcdCen( this, 0, dval ); astSetPcdCen( this, 1, dval ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a PcdMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * PcdMap member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a PcdMap's attributes. * Parameters: * this * Pointer to the PcdMap. * attrib * Pointer to a null terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstPcdMap *this; /* Pointer to the PcdMap structure */ int axis; /* Axis number */ int len; /* Length of attrib string */ int nc; /* No. characters read by astSscanf */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the PcdMap structure. */ this = (AstPcdMap *) this_object; /* Obtain the length of the attrib string. */ len = strlen( attrib ); /* Check the attribute name and test the appropriate attribute. */ /* Disco. */ /* ------ */ if ( !strcmp( attrib, "disco" ) ) { result = astTestDisco( this ); /* PcdCen. */ /* ------- */ } else if ( !strcmp( attrib, "pcdcen" ) ) { result = astTestPcdCen( this, 0 ); /* PcdCen(axis). */ /* ---------- */ } else if ( nc = 0, ( 1 == astSscanf( attrib, "pcdcen(%d)%n", &axis, &nc ) ) && ( nc >= len ) ) { result = astTestPcdCen( this, axis - 1 ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a PcdMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * PcdMap member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a PcdMap and a set of points encapsulated in a * PointSet and transforms the points so as to map them into the * required window. * Parameters: * this * Pointer to the PcdMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the PcdMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstPcdMap *map; /* Pointer to PcdMap to be applied */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ double *axin_0; /* Pointer to next input axis 0 value */ double *axin_1; /* Pointer to next input axis 1 value */ double *axout_0; /* Pointer to next output axis 0 value */ double *axout_1; /* Pointer to next output axis 1 value */ int npoint; /* Number of points */ int point; /* Loop counter for points */ double dx; /* Undistorted X increment from centre */ double dy; /* Undistorted Y increment from centre */ double dxp; /* Distorted X increment from centre */ double dyp; /* Distorted Y increment from centre */ double disco; /* Distortion coefficient */ double cen0; /* Centre of distortion on axis 0 */ double cen1; /* Centre of distortion on axis 1 */ double cr2; /* Constant */ double a; /* Constant */ double cr2a2; /* Constant */ double f; /* Expansion factor */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the PcdMap. */ map = (AstPcdMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse mapping, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* Get the distortion coefficient and centre. */ disco = astGetDisco( map ); cen0 = astGetPcdCen( map, 0 ); cen1 = astGetPcdCen( map, 1 ); /* Perform coordinate arithmetic. */ /* ------------------------------ */ if( astOK ){ /* Store pointers to the first input and output values on both axes. */ axin_0 = ptr_in[ 0 ]; axin_1 = ptr_in[ 1 ]; axout_0 = ptr_out[ 0 ]; axout_1 = ptr_out[ 1 ]; /* First deal with forward transformations. */ if( forward ){ for( point = 0; point < npoint; point++ ){ if( *axin_0 != AST__BAD && *axin_1 != AST__BAD ){ dx = ( *axin_0 - cen0 ); dy = ( *axin_1 - cen1 ); f = 1.0 + disco*( dx*dx + dy*dy ); dxp = dx*f; dyp = dy*f; *(axout_0++) = dxp + cen0; *(axout_1++) = dyp + cen1; } else { *(axout_0++) = AST__BAD; *(axout_1++) = AST__BAD; } axin_0++; axin_1++; } /* Now deal with inverse transformations. */ } else { for( point = 0; point < npoint; point++ ){ if( *axin_0 != AST__BAD && *axin_1 != AST__BAD ){ dxp = ( *axin_0 - cen0 ); dyp = ( *axin_1 - cen1 ); cr2 = disco*( dxp*dxp + dyp*dyp ); a = ( 2.0*cr2 + 1.0 )/( 3.0*cr2 + 1.0 ); cr2a2 = cr2*a*a; f = ( 2.0*cr2a2*a + 1.0 )/( 3.0*cr2a2 + 1.0 ); dx = dxp*f; dy = dyp*f; /* The above approximate inverse is taken from SLA_UNPCD. If more accuracy c is needed, the following code can be uncommented to iterate to a better c solution. c c fl = 1.0 + disco*( dx*dx + dy*dy ); c dx = dxp/fl; c dy = dyp/fl; c c df = fabs( fl ); c while( df > fabs( fl*1.0E-6 ) ){ c f = 1.0 + disco*( dx*dx + dy*dy ); c df = fabs( f - fl ); c fl = f; c c dx = dxp/f; c dy = dyp/f; c } */ *(axout_0++) = dx + cen0; *(axout_1++) = dy + cen1; } else { *(axout_0++) = AST__BAD; *(axout_1++) = AST__BAD; } axin_0++; axin_1++; } } } /* Return a pointer to the output PointSet. */ return result; } static void PcdZoom( AstMapping **maps, int *inverts, int ipc, int *status ){ /* * Name: * PcdZoom * Purpose: * Swap a PcdMap and a ZoomMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * void PcdZoom( AstMapping **maps, int *inverts, int ipc, int *status ) * Class Membership: * PcdMap member function * Description: * A list of two Mappings is supplied containing a PcdMap and a * ZoomMap. These Mappings are annulled, and replaced with * another pair of Mappings consisting of a PcdMap and a ZoomMap * in the opposite order. These Mappings are chosen so that their * combined effect is the same as the original pair of Mappings. * Parameters: * maps * A pointer to an array of two Mapping pointers. * inverts * A pointer to an array of two invert flags. * ipc * The index within "maps" of the PcdMap. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPcdMap *pm2; /* Pointer to the returned PcdMap */ AstPcdMap *pm; /* Pointer to the supplied PcdMap */ AstZoomMap *zm2; /* Pointer to the returned ZoomMap */ AstZoomMap *zm; /* Pointer to the supplied ZoomMap */ double cen[2]; /* New distortion centre */ double disc; /* Distortion coeff. for returned PcdMap */ double disco; /* Distortion coeff. for supplied PcdMap */ double xcen; /* Axis 0 centre for supplied PcdMap */ double ycen; /* Axis 1 centre for supplied PcdMap */ double zoom; /* Zoom factor for supplied ZoomMap */ int old_pinv; /* Invert value for the supplied PcdMap */ int old_zinv; /* Invert value for the supplied ZoomMap */ /* Check the global error status. */ if ( !astOK ) return; /* Store pointers to the supplied PcdMap and the ZoomMap. */ pm = (AstPcdMap *) maps[ ipc ]; zm = (AstZoomMap *) maps[ 1 - ipc ]; /* Temporarily set the Invert attribute of the supplied Mappings to the supplied values. */ old_pinv = astGetInvert( pm ); astSetInvert( pm, inverts[ ipc ] ); old_zinv = astGetInvert( zm ); astSetInvert( zm, inverts[ 1 - ipc ] ); /* Get the zoom factor from the ZoomMap. */ zoom = astGetZoom( zm ); /* Get the distortion coefficient from the PcdMap. */ disco = astGetDisco( pm ); /* Get the distortion centre from the PcdMap. */ xcen = astGetPcdCen( pm, 0 ); ycen = astGetPcdCen( pm, 1 ); /* Re-instate the original value of the Invert attributes of the supplied Mappings. */ astSetInvert( pm, old_pinv ); astSetInvert( zm, old_zinv ); /* Create the returned ZoomMap. */ zm2 = astZoomMap( 2, zoom, "", status ); /* Find the attributes of the returned PcdMap. If the PCD map is applied first... */ if( ipc == 0 ) { cen[ 0 ] = xcen*zoom; cen[ 1 ] = ycen*zoom; disc = disco/(zoom*zoom); /* If the PCD map is applied second... */ } else { cen[ 0 ] = xcen/zoom; cen[ 1 ] = ycen/zoom; disc = disco*zoom*zoom; } /* Create the returned PcdMap. */ pm2 = astPcdMap( disc, cen, "", status ); if( inverts[ ipc ] ) astInvert( pm2 ); /* Replace the supplied Mappings with the ones created above, swapping the order. */ if( astOK ){ (void) astAnnul( pm ); (void) astAnnul( zm ); maps[ 1 - ipc ] = (AstMapping *) pm2; inverts[ 1 - ipc ] = inverts[ ipc ]; maps[ ipc ] = (AstMapping *) zm2; inverts[ ipc ] = 0; } /* Return. */ return; } static void PcdPerm( AstMapping **maps, int *inverts, int ipc, int *status ){ /* * Name: * PcdPerm * Purpose: * Swap a PcdMap and a PermMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * void PcdPerm( AstMapping **maps, int *inverts, int ipc, int *status ) * Class Membership: * PcdMap member function * Description: * A list of two Mappings is supplied containing a PcdMap and a * PermMap. These Mappings are annulled, and replaced with * another pair of Mappings consisting of a PcdMap and a PermMap * in the opposite order. These Mappings are chosen so that their * combined effect is the same as the original pair of Mappings. * Parameters: * maps * A pointer to an array of two Mapping pointers. * inverts * A pointer to an array of two invert flags. * ipc * The index within "maps" of the PcdMap. * status * Pointer to the inherited status variable. * Notes: * - It should have been checked previously that the PermMap simply * swaps axes 0 and 1. This is the only sort of PermMap which can be * used here. */ AstPermMap *rm; /* Pointer to the supplied PermMap */ AstPermMap *rm2; /* Pointer to the returned PermMap */ AstPcdMap *pm; /* Pointer to the supplied PcdMap */ AstPcdMap *pm2; /* Pointer to the returned PcdMap */ double cen[2]; /* Centre for new PcdMap */ double disco; /* Distortion coeff. for supplied PcdMap */ double xcen; /* Axis 0 centre for supplied PcdMap */ double ycen; /* Axis 1 centre for supplied PcdMap */ int old_rinv; /* Invert value for the supplied PermMap */ int old_pinv; /* Invert value for the supplied PcdMap */ /* Check the global error status. */ if ( !astOK ) return; /* Store pointers to the supplied PcdMap and the PermMap. */ pm = (AstPcdMap *) maps[ ipc ]; rm = (AstPermMap *) maps[ 1 - ipc ]; /* Temporarily set the Invert attribute of the supplied Mappings to the supplied values. */ old_pinv = astGetInvert( pm ); astSetInvert( pm, inverts[ ipc ] ); old_rinv = astGetInvert( rm ); astSetInvert( rm, inverts[ 1 - ipc ] ); /* Get the distortion coefficient from the PcdMap. */ disco = astGetDisco( pm ); /* Get the distortion centre from the PcdMap. */ xcen = astGetPcdCen( pm, 0 ); ycen = astGetPcdCen( pm, 1 ); /* Re-instate the original value of the Invert attributes of the supplied Mappings. */ astSetInvert( pm, old_pinv ); astSetInvert( rm, old_rinv ); /* Create the returned PermMap (unchanged). */ rm2 = astClone( rm ); /* Create the returned PcdMap. */ cen[ 0 ] = ycen; cen[ 1 ] = xcen; pm2 = astPcdMap( disco, cen, "", status ); if( inverts[ ipc ] ) astInvert( pm2 ); /* Replace the supplied Mappings with the ones created above, swapping the order. */ if( astOK ){ (void) astAnnul( pm ); (void) astAnnul( rm ); old_pinv = inverts[ ipc ]; maps[ ipc ] = (AstMapping *) rm2; inverts[ ipc ] = inverts[ 1 - ipc ]; maps[ 1 - ipc ] = (AstMapping *) pm2; inverts[ 1 - ipc ] = old_pinv; } /* Return. */ return; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* *att++ * Name: * Disco * Purpose: * PcdMap pincushion/barrel distortion coefficient. * Type: * Public attribute. * Synopsis: * Double precision. * Description: * This attribute specifies the pincushion/barrel distortion coefficient * used by a PcdMap. This coefficient is set when the PcdMap is created, * but may later be modified. If the attribute is cleared, its default * value is zero, which gives no distortion. For pincushion distortion, * the value should be positive. For barrel distortion, it should be * negative. * * Note that the forward transformation of a PcdMap applies the * distortion specified by this attribute and the inverse * transformation removes this distortion. If the PcdMap is inverted c (e.g. using astInvert), then the forward transformation will f (e.g. using AST_INVERT), then the forward transformation will * remove the distortion and the inverse transformation will apply * it. The distortion itself will still be given by the same value of * Disco. * Applicability: * PcdMap * All PcdMaps have this attribute. *att-- */ /* This ia a double value with a value of AST__BAD when undefined but yielding a default of 0.0. */ astMAKE_CLEAR(PcdMap,Disco,disco,AST__BAD) astMAKE_GET(PcdMap,Disco,double,0.0,( ( this->disco == AST__BAD ) ? 0.0 : this->disco )) astMAKE_SET(PcdMap,Disco,double,disco,value) astMAKE_TEST(PcdMap,Disco,( this->disco != AST__BAD )) /* *att++ * Name: * PcdCen(axis) * Purpose: * Centre coordinates of pincushion/barrel distortion. * Type: * Public attribute. * Synopsis: * Floating point. * Description: * This attribute specifies the centre of the pincushion/barrel * distortion implemented by a PcdMap. It takes a separate value for * each axis of the PcdMap so that, for instance, the settings * "PcdCen(1)=345.0,PcdCen(2)=-104.4" specify that the pincushion * distortion is centred at positions of 345.0 and -104.4 on axes 1 and 2 * respectively. This attribute is set when a PcdMap is created, but may * later be modified. If the attribute is cleared, the default value for * both axes is zero. * Applicability: * PcdMap * All PcdMaps have this attribute. * Notes: * - If no axis is specified, (e.g. "PcdCen" instead of * "PcdCen(2)"), then a "set" or "clear" operation will affect * the attribute value of both axes, while a "get" or "test" * operation will use just the PcdCen(1) value. *att-- */ /* The centre of the distortion. AST__BAD is stored if no value has been supplied, resulting in default values of zero being used. */ MAKE_CLEAR(PcdCen,pcdcen,AST__BAD,2) MAKE_SET(PcdCen,double,pcdcen,value,2) MAKE_TEST(PcdCen,( this->pcdcen[axis] != AST__BAD ),2) MAKE_GET(PcdCen,double,0.0,(( this->pcdcen[axis] == AST__BAD ) ? 0.0 : this->pcdcen[axis] ),2) /* Copy constructor. */ /* ----------------- */ /* No copy constructor is needed, as a byte-by-byte copy suffices. */ /* Destructor. */ /* ----------- */ /* No destructor is needed as no memory, etc. needs freeing. */ /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for PcdMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the PcdMap class to an output Channel. * Parameters: * this * Pointer to the PcdMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPcdMap *this; /* Pointer to the PcdMap structure */ double dval; /* Attribute value */ int set; /* Is a value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the PcdMap structure. */ this = (AstPcdMap *) this_object; /* Write out values representing the instance variables for the PcdMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* PcdCen(0). */ /* ---------- */ set = TestPcdCen( this, 0, status ); dval = set ? GetPcdCen( this, 0, status ) : astGetPcdCen( this, 0 ); astWriteDouble( channel, "PcdCn0", set, 1, dval, "Distortion centre on first axis" ); /* PcdCen(1). */ /* ---------- */ set = TestPcdCen( this, 1, status ); dval = set ? GetPcdCen( this, 1, status ) : astGetPcdCen( this, 1 ); astWriteDouble( channel, "PcdCn1", set, 1, dval, "Distortion centre on second axis" ); /* Disco. */ /* ------ */ set = TestDisco( this, status ); dval = set ? GetDisco( this, status ) : astGetDisco( this ); astWriteDouble( channel, "Disco", set, 1, dval, "Distortion coefficient" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAPcdMap and astCheckPcdMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(PcdMap,Mapping) astMAKE_CHECK(PcdMap) AstPcdMap *astPcdMap_( double disco, const double pcdcen[2], const char *options, int *status, ...) { /* *++ * Name: c astPcdMap f AST_PCDMAP * Purpose: * Create a PcdMap. * Type: * Public function. * Synopsis: c #include "pcdmap.h" c AstPcdMap *astPcdMap( double disco, const double pcdcen[2], c const char *options, ... ) f RESULT = AST_PCDMAP( DISCO, PCDCEN, OPTIONS, STATUS ) * Class Membership: * PcdMap constructor. * Description: * This function creates a new PcdMap and optionally initialises its * attributes. * * A PcdMap is a non-linear Mapping which transforms 2-dimensional * positions to correct for the radial distortion introduced by some * cameras and telescopes. This can take the form either of pincushion * or barrel distortion, and is characterized by a single distortion * coefficient. * * A PcdMap is specified by giving this distortion coefficient and the * coordinates of the centre of the radial distortion. The forward * transformation of a PcdMap applies the distortion: * * RD = R * ( 1 + C * R * R ) * * where R is the undistorted radial distance from the distortion * centre (specified by attribute PcdCen), RD is the radial distance * from the same centre in the presence of distortion, and C is the * distortion coefficient (given by attribute Disco). * * The inverse transformation of a PcdMap removes the distortion * produced by the forward transformation. The expression used to derive * R from RD is an approximate inverse of the expression above, obtained * from two iterations of the Newton-Raphson method. The mismatch between * the forward and inverse expressions is negligible for astrometric * applications (to reach 1 milliarcsec at the edge of the Anglo-Australian * Telescope triplet or a Schmidt field would require field diameters of * 2.4 and 42 degrees respectively). * c If a PcdMap is inverted (e.g. using astInvert) then the roles of the f If a PcdMap is inverted (e.g. using AST_INVERT) then the roles of the * forward and inverse transformations are reversed; the forward * transformation will remove the distortion, and the inverse * transformation will apply it. * Parameters: c disco f DISCO = DOUBLE PRECISION (Given) * The distortion coefficient. Negative values give barrel * distortion, positive values give pincushion distortion, and * zero gives no distortion. c pcdcen f PCDCEN( 2 ) = DOUBLE PRECISION (Given) c A 2-element array containing the coordinates of the centre of the f An array containing the coordinates of the centre of the * distortion. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new PcdMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new PcdMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astPcdMap() f AST_PCDMAP = INTEGER * A pointer to the new PcdMap. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPcdMap *new; /* Pointer to new PcdMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the PcdMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPcdMap( NULL, sizeof( AstPcdMap ), !class_init, &class_vtab, "PcdMap", disco, pcdcen ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new PcdMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new PcdMap. */ return new; } AstPcdMap *astPcdMapId_( double disco, const double pcdcen[2], const char *options, ... ) { /* * Name: * astPcdMapId_ * Purpose: * Create a PcdMap. * Type: * Private function. * Synopsis: * #include "pcdmap.h" * AstPcdMap *astPcdMapId_( double disco, const double pcdcen[2], * const char *options, ... ) * Class Membership: * PcdMap constructor. * Description: * This function implements the external (public) interface to the * astPcdMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astPcdMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astPcdMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astPcdMap_. * Returned Value: * The ID value associated with the new PcdMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPcdMap *new; /* Pointer to new PcdMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the PcdMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitPcdMap( NULL, sizeof( AstPcdMap ), !class_init, &class_vtab, "PcdMap", disco, pcdcen ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new PcdMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new PcdMap. */ return astMakeId( new ); } AstPcdMap *astInitPcdMap_( void *mem, size_t size, int init, AstPcdMapVtab *vtab, const char *name, double disco, const double pcdcen[2], int *status ){ /* *+ * Name: * astInitPcdMap * Purpose: * Initialise a PcdMap. * Type: * Protected function. * Synopsis: * #include "pcdmap.h" * AstPcdMap *astInitPcdMap( void *mem, size_t size, int init, * AstPcdMapVtab *vtab, const char *name, * double disco, const double pcdcen[2] ) * Class Membership: * PcdMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new PcdMap object. It allocates memory (if necessary) to accommodate * the PcdMap plus any additional data associated with the derived class. * It then initialises a PcdMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a PcdMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the PcdMap is to be initialised. * This must be of sufficient size to accommodate the PcdMap data * (sizeof(PcdMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the PcdMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the PcdMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the PcdMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new PcdMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * disco * Distortion coefficient. * pcdcen * Distortion centre. * Returned Value: * A pointer to the new PcdMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstPcdMap *new; /* Pointer to new PcdMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitPcdMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Initialise a Mapping structure (the parent class) as the first component within the PcdMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstPcdMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, 2, 2, 1, 1 ); if ( astOK ) { /* Initialise the PcdMap data. */ /* ---------------------------- */ /* Store the shift and scale for each axis. */ new->pcdcen[0] = pcdcen[0]; new->pcdcen[1] = pcdcen[1]; new->disco = disco; /* If an error occurred, clean up by deleting the new PcdMap. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new PcdMap. */ return new; } AstPcdMap *astLoadPcdMap_( void *mem, size_t size, AstPcdMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadPcdMap * Purpose: * Load a PcdMap. * Type: * Protected function. * Synopsis: * #include "pcdmap.h" * AstPcdMap *astLoadPcdMap( void *mem, size_t size, * AstPcdMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * PcdMap loader. * Description: * This function is provided to load a new PcdMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * PcdMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a PcdMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the PcdMap is to be * loaded. This must be of sufficient size to accommodate the * PcdMap data (sizeof(PcdMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the PcdMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the PcdMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstPcdMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new PcdMap. If this is NULL, a pointer * to the (static) virtual function table for the PcdMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "PcdMap" is used instead. * Returned Value: * A pointer to the new PcdMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstPcdMap *new; /* Pointer to the new PcdMap */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this PcdMap. In this case the PcdMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstPcdMap ); vtab = &class_vtab; name = "PcdMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitPcdMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built PcdMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "PcdMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* PcdCen(0). */ /* ---------- */ new->pcdcen[0] = astReadDouble( channel, "pcdcn0", AST__BAD ); if ( TestPcdCen( new, 0, status ) ) SetPcdCen( new, 0, new->pcdcen[0], status ); /* PcdCen(1). */ /* ---------- */ new->pcdcen[1] = astReadDouble( channel, "pcdcn1", AST__BAD ); if ( TestPcdCen( new, 1, status ) ) SetPcdCen( new, 1, new->pcdcen[1], status ); /* Disco. */ /* ------ */ new->disco = astReadDouble( channel, "disco", AST__BAD ); if ( TestDisco( new, status ) ) SetDisco( new, new->disco, status ); /* If an error occurred, clean up by deleting the new PcdMap. */ if ( !astOK ) new = astDelete( new ); } /* Return the new PcdMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/ast_link_adam.in0000644000175000017500000004046712262533650014273 0ustar olesoles # N.B. the previous line should be blank. #++ # Name: # ast_link_adam # Purpose: # Link an ADAM program with the AST library. # Type of Module: # Shell script. # Description: # This command should only be used when building Starlink ADAM programs # which use the AST library, in order to generate the correct arguments # to allow the ADAM ``alink'' command to link the program. The arguments # generated are written to standard output but may be substituted into # the ``alink'' command line in the standard UNIX way using backward # quotes (see below). # # By default, it is assumed that you are building an ADAM program which # does not produce graphical output. However, switches are provided for # linking other types of program. This command should not be used when # building stand-alone (non-ADAM) programs. Use the ``ast_link'' command # instead. # Invocation: #c alink program.o -L/star/lib `ast_link_adam [switches]` #f alink program.f -L/star/lib `ast_link_adam [switches]` # Switches: # The following switches may optionally be given to this command to # modify its behaviour: # # - ``-csla'': Ignored. Provided for backward compatibility only. # # - ``-fsla'': Ignored. Provided for backward compatibility only. # # - ``-grf'': Requests that no arguments be generated to specify which # 2D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new graphics system yourself and wish to provide your own arguments for # linking with it. This switch differs from the other ``grf'' switches in # that it assumes that your graphics module implements the complete # interface required by the current version of AST. If future versions of # AST introduce new functions to the graphics interface, this switch will # cause ``unresolved symbol'' errors to occur during linking, warning you # that you need to implement new functions in your graphics module. To # avoid such errors, you can use one of the other, version-specific, # switches in place of the ``-grf'' switch, but these will cause run-time # errors to be reported if any AST function is invoked which requires # facilities not in the implemented interface. # # - ``-grf_v2.0'': This switch is equivalent to the ``-mygrf'' switch. # It indicates that you want to link with your own graphics module which # implements the 2D graphics interface required by V2.0 of AST. # # - ``-grf_v3.2'': Indicates that you want to link with your own graphics # module which implements the 2D graphics interface required by V3.2 of AST. # # - ``-grf_v5.6'': Indicates that you want to link with your own graphics # module which implements the 2D graphics interface required by V5.6 of AST. # # - ``-myerr'': Requests that no arguments be generated to specify how # error messages produced by the AST library should be delivered. You # should use this option only if you have implemented an interface to a # new error delivery system yourself and wish to provide your own # arguments for linking with it. By default, error messages are delivered # in the standard ADAM way via the EMS Error Message Service (Starlink # System Note SSN/4). # # - ``-mygrf'': This switch has been superceeded by the ``-grf'' switch, # but is retained in order to allow applications to be linked with a # graphics module which implements the interface used by AST V2.0. It is # equivalent to the ``-grf_v2.0'' switch. # # - ``-pgp'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot'': Requests that the program be linked so that 2D # graphical output from the AST library is displayed via the # standard (or ``native'') version of the PGPLOT graphics # package. By default, no graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # # - ``-grf3d'': Requests that no arguments be generated to specify which # 3D graphics system is used to display output from the AST library. You # should use this option only if you have implemented an interface to a # new 3D graphics system yourself and wish to provide your own arguments # for linking with it. # # - ``-pgp3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via the # Starlink version of the PGPLOT graphics package (which uses GKS # for its output). By default, no 3D graphics package is linked and # this will result in an error at run time if AST routines are # invoked that attempt to generate graphical output. # # - ``-pgplot3d'': Requests that the program be linked so that 3D # graphical output from the AST library is displayed via # the standard (or ``native'') version of the PGPLOT graphics # package. By default, no 3D graphics package is linked and this will # result in an error at run time if AST routines are invoked that # attempt to generate graphical output. # SLALIB: # The AST distribution includes a cut down subset of the C version of # the SLALIB library written by Pat Wallace. This subset contains only # the functions needed by the AST library. It is built as part of the # process of building AST and is distributed under GPL (and is thus # compatible with the AST license). Previous version of this script # allowed AST applications to be linked against external SLALIB # libraries (either Fortran or C) rather than the internal version. # The current version of this script does not provide this option, # and always uses the internal SLALIB library. However, for backward # compatibility, this script still allows the "-fsla" and "-csla" flags # (previously used for selecting which version of SLALIB to use) to be # specified, but they will be ignored. # Examples: #c alink display.o -L/star/lib `ast_link_adam -pgplot` #c Links an ADAM program ``display'' which uses the standard #c version of PGPLOT for graphical output. #c alink plotit.o -L. -L/star/lib `ast_link_adam -grf` -lgrf #c Links an ADAM program ``plotit'', written in C. The ``-grf'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by the current version of AST. #c Here, this interface is supplied by means of the ``-lgrf'' library #c reference. #c alink plotit.o -L. -L/star/lib `ast_link_adam -grf_v2.0` -lgrf #c Links an ADAM program ``plotit'', written in C. The ``-grf_v2.0'' #c switch indicates that graphical output will be delivered through #c a graphical interface which you have implemented yourself, which #c corresponds to the interface required by version 2.0 of AST. Here, #c this interface is supplied by means of the ``-lgrf'' library #c reference. #f alink display.f -L/star/lib `ast_link_adam -pgplot` #f Compiles and links an ADAM Fortran program called ``display'' which #f uses the standard version of PGPLOT for graphical output. #f alink plotit.f -L. -L/star/lib `ast_link_adam -grf` -lgrf #f Compiles and links an ADAM Fortran program ``plotit''. The ``-grf'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by the current version of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. #f alink plotit.f -L. -L/star/lib `ast_link_adam -grf_v2.0` -lgrf #f Compiles and links an ADAM Fortran program ``plotit''. The ``-grf_v2.0'' #f switch indicates that graphical output will be delivered through #f a graphical interface which you have implemented yourself, which #f corresponds to the interface required by version 2.0 of AST. #f Here, this interface is supplied by means of the ``-lgrf'' library #f reference. # Copyright: # Copyright (C) 1997-2006 Council for the Central Laboratory of the Research Councils # Authors: # RFWS: R.F. Warren-Smith (STARLINK) # {enter_new_authors_here} # History: # 11-NOV-1996 (RFWS): # Original version. # 18-NOV-1997 (RFWS): # Adapted prologue for document extraction. # 28-SEP-1998 (RFWS): # Distinguish between -pgp and -pgplot options. # 23-JAN-2004 (DSB): # Added switches to support older grf implementations. # 21-APR-2005 (DSB): # Added "-fsla" option. # 16-JUN-2006 (DSB): # Ignore "-fsla" and "-clsa" options, and always use PAL. # 22-AUG-2007 (DSB): # Added "-grf3d", "-pgplot3d" and "-pgp3d" flags. # 4-MAR-2011 (DSB): # Added v5.6 grf options. # {enter_changes_here} # Bugs: # {note_any_bugs_here} #-- # This function searches the directory path specified in PATH, looking for # an executable file which is not a directory. If found, it echos the full # file name to standard output. Otherwise, it outputs nothing. find() { IFS=':'; for d in $PATH; do f="${d:=.}/${1}" test -x "${f}" -a ! -d "${f}" && echo "${f}" && break done; } # Initialise linking options. err='' grf='' grf3d='' sla='' # Interpret command line switches. # -------------------------------- while :; do case "${1}" in # -csla - Previously used to request C version of SLALIB. Now ignored. -csla) # sla='c' shift;; # -fsla - Previously used to request Fortran version of SLALIB. Now ignored. -fsla) # sla='f' shift;; # -myerr - Requests no error reporting. -myerr) err='my' shift;; # -grf - Requests no 2D graphics. -grf) grf='current' shift;; # -mygrf - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -mygrf) grf='v2.0' shift;; # -grf_v2.0 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V2.0. -grf_v2.0) grf='v2.0' shift;; # -grf_v3.2 - Requests no 2D graphics, except for null implementations of # functions aded to the grf interface after AST V3.2. -grf_v3.2) grf='v3.2' shift;; # -grf_v5.6 - Requests no 2D graphics, except for null implementations of # functions added to the grf interface after AST V5.6. -grf_v5.6) grf='v5.6' shift;; # -pgp - Requests 2D graphical output through Starlink PGPLOT. -pgp) grf='pgp' shift;; # -pgplot - Requests 2D graphical output through native PGPLOT. -pgplot) grf='pgplot' shift;; # -grf3d - Requests no 3D graphics. -grf3d) grf3d='current' shift;; # -pgp3d - Requests 3D graphical output through Starlink PGPLOT. -pgp3d) grf3d='pgp' shift;; # -pgplot3d - Requests 3D graphical output through native PGPLOT. -pgplot3d) grf3d='pgplot' shift;; # Once all switches have been read, continue with the rest of the script. '') break;; # Catch unrecognised switches and report an error. *) echo >&2 "ast_link_adam: unknown argument \""${1}"\" given" exit 1;; esac done # Link with the main AST library. # ------------------------------- # Start forming the list of arguments with the main AST library itself. args='-last' # Generate arguments for linking PAL. # ----------------------------------- case "@EXTERNAL_PAL@" in # If we configured --with-external_pal include a link option to pick up # an external PAL library. 1) args="${args} -lpal";; # Otherwise, use the internal PAL & SOFA libraries. *) args="${args} -last_pal";; esac # Generate arguments for linking the 2D graphics system. # ------------------------------------------------------ case "${grf}" in # If using Starlink PGPLOT, link with the AST PGPLOT interface and # the Fortran library via the PGP link script. pgp) args="${args} -last_pgplot `pgp_link_adam`";; # If using native PGPLOT, link with the AST PGPLOT interface and # the Fortran library via the PGPLOT link script. pgplot) args="${args} -last_pgplot `pgplot_link_adam`";; # If using own graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # If using own graphics which conform to the requirements of version 5.6 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 5.6. v5.6) :;; # If using own graphics which conform to the requirements of version 3.2 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 3.2. v3.2) args="${args} -last_grf_5.6";; # If using own graphics which conform to the requirements of version 2.0 # of AST, produce arguments which link in dummy implementations of any # functions which are required by the current version of AST but which were # not required by version 2.0. v2.0) args="${args} -last_grf_3.2 -last_grf_5.6";; # Default graphics (none) requires linking with all the default (null) AST # "grf" modules. *) args="${args} -last_grf_2.0 -last_grf_3.2 -last_grf_5.6";; esac # Generate arguments for linking the 3D graphics system. # ------------------------------------------------------ case "${grf3d}" in # If using Starlink PGPLOT, link with the AST 3D PGPLOT interface and # the Fortran library via the PGP link script (if found). pgp) args="${args} -last_pgplot3d `\`find pgp_link\``" f77='y';; # If using native PGPLOT, link with the AST 3D PGPLOT interface and the # Fortran library via the PGPLOT link script (if found). pgplot) args="${args} -last_pgplot3d `\`find pgplot_link\``" f77='y';; # If using own 3D graphics which conform to the requirements of the current # version of AST, do not produce any arguments. current) :;; # Default graphics (none) requires linking with all the default (null) AST # "grf3d" modules. *) args="${args} -last_grf3d";; esac # Make a second pass through the AST library. # ------------------------------------------- # This library is a link to the main AST library and results in a second # pass to resolve any backward references generated by the other modules # used above. A different library name must be used to avoid the two passes # being merged into one (either below, or by other link scripts). args="${args} -last_pass2" # Generate arguments for linking the error reporting system. # ---------------------------------------------------------- case "${err}" in # If using own error reporting, do not produce any arguments. my) :;; # Default error reporting requires linking with the AST EMS interface and # the EMS library via the link script. *) args="${args} -last_ems `ems_link_adam`";; esac # Link with the maths library. # ---------------------------- args="${args} -lm" # Link with the starmem library, if available. # -------------------------------------------- args="${args} `\`find starmem_link\``" # Pass the resulting argument list through an awk script which eliminates # all except the last reference to each library. echo "${args}" \ | awk 'BEGIN{RS=" ";FS="\n"} {if($1)f[i++]=$1} END{for(;i--;)if(!w[f[i]]++)l=f[i]" "l;print l}' # End of script. ./ast-7.3.3/cmpregion.c0000644000175000017500000054075012262533650013304 0ustar olesoles/* *class++ * Name: * CmpRegion * Purpose: * A combination of two regions within a single Frame * Constructor Function: c astCmpRegion f AST_CMPREGION * Description: * A CmpRegion is a Region which allows two component * Regions (of any class) to be combined to form a more complex * Region. This combination may be performed a boolean AND, OR * or XOR (exclusive OR) operator. If the AND operator is * used, then a position is inside the CmpRegion only if it is * inside both of its two component Regions. If the OR operator is * used, then a position is inside the CmpRegion if it is inside * either (or both) of its two component Regions. If the XOR operator * is used, then a position is inside the CmpRegion if it is inside * one but not both of its two component Regions. Other operators can * be formed by negating one or both component Regions before using * them to construct a new CmpRegion. * * The two component Region need not refer to the same coordinate * Frame, but it must be possible for the c astConvert f AST_CONVERT * function to determine a Mapping between them (an error will be * reported otherwise when the CmpRegion is created). For instance, * a CmpRegion may combine a Region defined within an ICRS SkyFrame * with a Region defined within a Galactic SkyFrame. This is * acceptable because the SkyFrame class knows how to convert between * these two systems, and consequently the c astConvert f AST_CONVERT * function will also be able to convert between them. In such cases, * the second component Region will be mapped into the coordinate Frame * of the first component Region, and the Frame represented by the * CmpRegion as a whole will be the Frame of the first component Region. * * Since a CmpRegion is itself a Region, it can be used as a * component in forming further CmpRegions. Regions of arbitrary * complexity may be built from simple individual Regions in this * way. * Inheritance: * The CmpRegion class inherits from the Region class. * Attributes: * The CmpRegion class does not define any new attributes beyond those * which are applicable to all Regions. * Functions: c The CmpRegion class does not define any new functions beyond those f The CmpRegion class does not define any new routines beyond those * which are applicable to all Regions. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 7-OCT-2004 (DSB): * Original version. * 28-MAY-2007 (DSB): * - Corrected RegBaseMesh. * - In RegBaseBox, if the CmpRegion is bounded find the box by * finding the extreme position sin a mesh covering the boundary. * 20-JAN-2009 (DSB): * Over-ride astRegBasePick. * 19-MAR-2009 (DSB): * Over-ride the astDecompose method. * 8-SEP-2009 (DSB): * Fix logic in RegTrace. * 9-SEP-2009 (DSB): * - Added astCmpRegionList * - Added support for XOR * - Override astGetObjSize. * 27-APR-2012 (DSB): * - Cache the bounded property. * - Speed up plotting of CmpRegions by using the cached negation * of a Region instead of setting the Regions's Negated flag (which * causes the Region's cache to be cleared). * 30-APR-2012 (DSB): * Use geodesic distance to measure distances around the two component * Regions when tracing the border. Previously, a distance normalised * from zero to one was used for both component Regions, but this gives * greater priority to Regions higher in the CmpRegion nesting order, * resulting in a high chance that lower Regions will not be seen. * 7-JUN-2012 (DSB): * Override astRegSplit method. * 21-NOV-2012 (DSB): * Map the regions returned by RegSplit into the current Frame of the * CmpRegion. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS CmpRegion /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "region.h" /* Regions (parent class) */ #include "channel.h" /* I/O channels */ #include "nullregion.h" /* Boundless Regions */ #include "cmpregion.h" /* Interface definition for this class */ #include "unitmap.h" /* Unit Mapings */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstRegion *(* parent_getdefunc)( AstRegion *, int * ); static void (* parent_setregfs)( AstRegion *, AstFrame *, int * ); static AstMapping *(* parent_simplify)( AstMapping *, int * ); static int (* parent_equal)( AstObject *, AstObject *, int * ); static void (* parent_setclosed)( AstRegion *, int, int * ); static void (* parent_setmeshsize)( AstRegion *, int, int * ); static void (* parent_clearclosed)( AstRegion *, int * ); static void (* parent_clearmeshsize)( AstRegion *, int * ); static double (*parent_getfillfactor)( AstRegion *, int * ); static void (*parent_regsetattrib)( AstRegion *, const char *, char **, int * ); static void (*parent_regclearattrib)( AstRegion *, const char *, char **, int * ); static void (* parent_resetcache)( AstRegion *, int * ); static int (* parent_getobjsize)( AstObject *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(CmpRegion) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(CmpRegion,Class_Init) #define class_vtab astGLOBAL(CmpRegion,Class_Vtab) #include #else /* Define the class virtual function table and its initialisation flag as static variables. */ static AstCmpRegionVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstCmpRegion *astCmpRegionId_( void *, void *, int, const char *, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstMapping *Simplify( AstMapping *, int * ); static AstPointSet *RegBaseMesh( AstRegion *, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static AstRegion *GetDefUnc( AstRegion *, int * ); static AstRegion *MatchRegion( AstRegion *, int, AstRegion *, const char *, int * ); static AstRegion *RegBasePick( AstRegion *this, int, const int *, int * ); static AstRegion **RegSplit( AstRegion *, int *, int * ); static double GetFillFactor( AstRegion *, int * ); static int CmpRegionList( AstCmpRegion *, int *, AstRegion ***, int * ); static int Equal( AstObject *, AstObject *, int * ); static int GetBounded( AstRegion *, int * ); static int GetObjSize( AstObject *, int * ); static int RegPins( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); static int RegTrace( AstRegion *, int, double *, double **, int * ); static void ClearClosed( AstRegion *, int * ); static void ClearMeshSize( AstRegion *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Decompose( AstMapping *, AstMapping **, AstMapping **, int *, int *, int *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void GetRegions( AstCmpRegion *, AstRegion **, AstRegion **, int *, int *, int *, int * ); static void RegBaseBox( AstRegion *, double *, double *, int * ); static void RegBaseBox2( AstRegion *, double *, double *, int * ); static void RegClearAttrib( AstRegion *, const char *, char **, int * ); static void RegSetAttrib( AstRegion *, const char *, char **, int * ); static void ResetCache( AstRegion *this, int * ); static void SetBreakInfo( AstCmpRegion *, int, int * ); static void SetClosed( AstRegion *, int, int * ); static void SetMeshSize( AstRegion *, int, int * ); static void SetRegFS( AstRegion *, AstFrame *, int * ); static void XORCheck( AstCmpRegion *, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ int CmpRegionList( AstCmpRegion *this, int *nreg, AstRegion ***reg_list, int *status ) { /* *+ * Name: * astCmpRegionList * Purpose: * Decompose a CmpRegion into a sequence of simpler Regions. * Type: * Protected virtual function. * Synopsis: * #include "cmpregion.h" * int astCmpRegionList( AstCmpRegion *this, int *nreg, * AstRegion ***reg_list, int *status ) * Class Membership: * CmpRegion method. * Description: * This function decomposes a CmpRegion into a sequence of simpler * Regions which may be applied in sequence to achieve the same * effect. * Parameters: * this * Pointer to the CmpRegion to be decomposed (the CmpRegion is not * actually modified by this function). * nreg * The address of an int which holds a count of the number of * individual Regions in the decomposition. On entry, this * should count the number of Regions already in the * "*reg_list" array (below). On exit, it is updated to include * any new Regions appended by this function. * reg_list * Address of a pointer to an array of Region pointers. On * entry, this array pointer should either be NULL (if no * Regions have yet been obtained) or should point at a * dynamically allocated array containing Region pointers * ("*nreg" in number) which have been obtained from a previous * invocation of this function. * * On exit, the dynamic array will be enlarged to contain any * new Region pointers that result from the decomposition * requested. These pointers will be appended to any previously * present, and the array pointer will be updated as necessary * to refer to the enlarged array (any space released by the * original array will be freed automatically). * * The new Region pointers returned will identify a sequence of * Region which, when applied in order, will represent an area * equivalent to that of the original Region. * * All the Region pointers returned by this function should be * annulled by the caller, using astAnnul, when no longer * required. The dynamic array holding these pointers should * also be freed, using astFree. * Returned Value: * An integer identifying the boolean operation that should be used to * combine the Regions returned in "reg_list". This will be AST__AND * or AST__OR. *- */ /* Local Variables: */ AstCmpRegion *cmpreg; int add; int result; /* Check the global error status. */ if ( !astOK ) return AST__AND; /* Check if this CmpRegion has an equivalent XOR representation. Is so, store details of the XOR representation in the CmpRegion. */ XORCheck( this, status ); /* The CmpRegion class only has full support for AND and OR operators. However, it can also represent XOR operators, but it does this by an equivalent set of AND and OR operators. When an XOR CmpRegion is created, the original supplied argument regions are stored in "this->xor1" and "this->xor2", and the component Regions placed in the new CmpRegion are actually CmpRegions that implement the equivalent of an XOR operation, using AND and OR operators. We want to hide this to the outside world, so if the supplied CmpRegion represents an XOR operation, add the XOR regions to the returned list, and return an XOR operator. */ if( this->xor1 ) { *reg_list = astGrow( *reg_list, *nreg + 2, sizeof( AstRegion * ) ); if( astOK ) { ( *reg_list )[ (*nreg)++ ] = astClone( this->xor1 ); ( *reg_list )[ (*nreg)++ ] = astClone( this->xor2 ); } result = AST__XOR; /* For AND and OR operators, we deal with the component Regions directly. */ } else { /* If the first component of the supplied CmpRegion is itself a CmpRegion that uses the same boolean operator as "this", call this function recursively to add its component Regions to the returned list. */ add = 1; if( astIsACmpRegion( this->region1 ) ) { cmpreg = (AstCmpRegion *) this->region1; if( cmpreg->oper == this->oper ) { (void) CmpRegionList( cmpreg, nreg, reg_list, status ); add = 0; } } /* Otherwise, add the component Region directly into the returned list of Regions. */ if( add ) { *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) ); if( astOK ) { ( *reg_list )[ *nreg ] = astClone( this->region1 ); ( *nreg )++; } } /* Do the same for the second component region */ add = 1; if( astIsACmpRegion( this->region2 ) ) { cmpreg = (AstCmpRegion *) this->region2; if( cmpreg->oper == this->oper ) { (void) CmpRegionList( cmpreg, nreg, reg_list, status ); add = 0; } } if( add ) { *reg_list = astGrow( *reg_list, *nreg + 1, sizeof( AstRegion * ) ); if( astOK ) { ( *reg_list )[ *nreg ] = astClone( this->region2 ); ( *nreg )++; } } result = this->oper; } /* Return the boolean operator used to combine the regions in the returned array. */ return result; } static void Decompose( AstMapping *this_mapping, AstMapping **map1, AstMapping **map2, int *series, int *invert1, int *invert2, int *status ) { /* * * Name: * Decompose * Purpose: * Decompose a CmpRegion into two component Regions. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void Decompose( AstMapping *this, AstMapping **map1, * AstMapping **map2, int *series, * int *invert1, int *invert2, int *status ) * Class Membership: * CmpRegion member function (over-rides the protected astDecompose * method inherited from the Mapping class). * Description: * This function returns pointers to two Mappings which, when applied * either in series or parallel, are equivalent to the supplied Mapping. * * Since the Frame class inherits from the Mapping class, Frames can * be considered as special types of Mappings and so this method can * be used to decompose either CmpMaps, CmpFrames, CmpRegions or Prisms. * Parameters: * this * Pointer to the Mapping. * map1 * Address of a location to receive a pointer to first component * Mapping. * map2 * Address of a location to receive a pointer to second component * Mapping. * series * Address of a location to receive a value indicating if the * component Mappings are applied in series or parallel. A non-zero * value means that the supplied Mapping is equivalent to applying map1 * followed by map2 in series. A zero value means that the supplied * Mapping is equivalent to applying map1 to the lower numbered axes * and map2 to the higher numbered axes, in parallel. * invert1 * The value of the Invert attribute to be used with map1. * invert2 * The value of the Invert attribute to be used with map2. * status * Pointer to the inherited status variable. * Notes: * - Any changes made to the component rames using the returned * pointers will be reflected in the supplied CmpFrame. *- */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the CmpMap structure. */ this = (AstCmpRegion *) this_mapping; /* The components Frames of a CmpRegion are considered to be series Mappings. */ if( series ) *series = 1; /* The Frames are returned in their original order whether or not the CmpRegion has been inverted. */ if( map1 ) *map1 = astClone( this->region1 ); if( map2 ) *map2 = astClone( this->region2 ); /* The invert flags dont mean anything for a Region, but we return them anyway. If the CmpRegion has been inverted, return inverted Invert flags. */ if( astGetInvert( this ) ) { if( invert1 ) *invert1 = astGetInvert( this->region1 ) ? 0 : 1; if( invert2 ) *invert2 = astGetInvert( this->region2 ) ? 0 : 1; /* If the CmpRegion has not been inverted, return the current Invert flags. */ } else { if( invert1 ) *invert1 = astGetInvert( this->region1 ); if( invert2 ) *invert2 = astGetInvert( this->region2 ); } } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two Objects are equivalent. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * int Equal( AstObject *this_object, AstObject *that_object, int *status ) * Class Membership: * CmpRegion member function (over-rides the astEqual protected * method inherited from the Region class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two CmpRegions are equivalent. * Parameters: * this * Pointer to the first CmpRegion. * that * Pointer to the second CmpRegion. * status * Pointer to the inherited status variable. * Returned Value: * One if the CmpRegions are equivalent, zero otherwise. * Notes: * - The CmpRegions are equivalent if their component Regions are * equivalent and if they have the same boolean operation, negation * and closed flags. * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstCmpRegion *that; AstCmpRegion *this; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the Equal method inherited from the parent Region class. This checks that the Objects are both of the same class, and have the same Negated and Closed flags (amongst other things). */ if( (*parent_equal)( this_object, that_object, status ) ) { /* Obtain pointers to the two CmpRegion structures. */ this = (AstCmpRegion *) this_object; that = (AstCmpRegion *) that_object; /* Test their first component Regions for equality. */ if( astEqual( this->region1, that->region1 ) ) { /* Test their second component Regions for equality. */ if( astEqual( this->region2, that->region2 ) ) { /* Test their boolean operator for equality. */ if( this->oper == that->oper ) result = 1; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } /* * Name: * MAKE_SET * Purpose: * Define a function to set an attribute value for a CmpRegion. * Type: * Private macro. * Synopsis: * #include "cmpregion.h" * MAKE_SET(attribute,lattribute,type) * Class Membership: * Defined by the CmpRegion class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Set( AstRegion *this, value ) * * that sets the value of a specified Region attribute in the parent * Region structure and also in the component Regions. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * lattribute * Name of the attribute, all in lower case. * type * The C type of the attribute. */ /* Define the macro. */ #define MAKE_SET(attribute,lattribute,type) \ static void Set##attribute( AstRegion *this_region, type value, int *status ) { \ \ /* Local Variables: */ \ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Use the parent method to set the value in the parent Region structure. */ \ (*parent_set##lattribute)( this_region, value, status ); \ \ /* Also set the value in the two component Regions. */ \ this = (AstCmpRegion *) this_region; \ astSet##attribute( this->region1, value ); \ astSet##attribute( this->region2, value ); \ } /* Use the above macro to create accessors for the MeshSize and Closed attributes. */ MAKE_SET(MeshSize,meshsize,int) MAKE_SET(Closed,closed,int) /* Undefine the macro. */ #undef MAKE_SET /* * Name: * MAKE_CLEAR * Purpose: * Define a function to clear an attribute value for a CmpRegion. * Type: * Private macro. * Synopsis: * #include "cmpregion.h" * MAKE_CLEAR(attribute,lattribute) * Class Membership: * Defined by the CmpRegion class. * Description: * This macro expands to an implementation of a private member function * of the form: * * static void Clear( AstRegion *this ) * * that sets the value of a specified Region attribute in the parent * Region structure and also in the component Regions. * Parameters: * attribute * Name of the attribute, as it appears in the function name. * lattribute * Name of the attribute, all in lower case. */ /* Define the macro. */ #define MAKE_CLEAR(attribute,lattribute) \ static void Clear##attribute( AstRegion *this_region, int *status ) { \ \ /* Local Variables: */ \ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Use the parent method to clear the value in the parent Region structure. */ \ (*parent_clear##lattribute)( this_region, status ); \ \ /* Also clear the value in the two component Regions. */ \ this = (AstCmpRegion *) this_region; \ astClear##attribute( this->region1 ); \ astClear##attribute( this->region2 ); \ } /* Use the above macro to create accessors for the MeshSize and Closed attributes. */ MAKE_CLEAR(MeshSize,meshsize) MAKE_CLEAR(Closed,closed) /* Undefine the macro. */ #undef MAKE_CLEAR static int GetBounded( AstRegion *this_region, int *status ) { /* * Name: * GetBounded * Purpose: * Is the Region bounded? * Type: * Private function. * Synopsis: * #include "cmpregion.h" * int GetBounded( AstRegion *this, int *status ) * Class Membership: * CmpRegion method (over-rides the astGetBounded method inherited from * the Region class). * Description: * This function returns a flag indicating if the Region is bounded. * The implementation provided by the base Region class is suitable * for Region sub-classes representing the inside of a single closed * curve (e.g. Circle, Ellipse, Box, etc). Other sub-classes (such as * CmpRegion, PointList, etc ) may need to provide their own * implementations. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the Region is bounded. Zero otherwise. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ int neg1; /* Negated flag to use with first component */ int neg2; /* Negated flag to use with second component */ int oper; /* Combination operator */ int overlap; /* Nature of overlap between components */ int reg1b; /* Is the first component Region bounded?*/ int reg2b; /* Is the second component Region bounded?*/ int result; /* Returned result */ /* Initialise */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Only calculated a new value if there is no cached value in the Region. */ if( this->bounded == -INT_MAX ) { /* Get the component Regions, how they should be combined, and the Negated values which should be used with them. The returned values take account of whether the supplied CmpRegion has itself been Negated or not. The returned Regions represent regions within the base Frame of the FrameSet encapsulated by the parent Region structure. */ GetRegions( this, ®1, ®2, &oper, &neg1, &neg2, status ); /* If the first component Region does not have the required value for its "Negated" attribute, use the negation of "reg1" in place of "reg1" itself. */ if( neg1 != astGetNegated( reg1 ) ) { AstRegion *tmp = astGetNegation( reg1 ); (void) astAnnul( reg1 ); reg1 = tmp; } /* If the second component Region does not have the required value for its "Negated" attribute, use the negation of "reg2" in place of "reg2" itself. */ if( neg2 != astGetNegated( reg2 ) ) { AstRegion *tmp = astGetNegation( reg2 ); (void) astAnnul( reg2 ); reg2 = tmp; } /* See if either of the component Regions is bounded. */ reg1b = astGetBounded( reg1 ); reg2b = astGetBounded( reg2 ); /* If the regions are ANDed... */ if( oper == AST__AND ) { /* If either one of the two components are bounded, then the AND region is bounded. */ if( reg1b || reg2b ) { result = 1; /* If neither of the two components is bounded, then the AND region is unbounded if there is partial or no overlap between them and is bounded otherwise. */ } else { overlap = astOverlap( reg1, reg2 ); if( overlap == 1 || overlap == 4 || overlap == 6 ) { result = 0; } else { result = 1; } } /* If the regions are ORed... */ } else { /* If either one of the two components is unbounded, then the OR region is unbounded. */ if( !reg1b || !reg2b ) { result = 0; /* If both of the two components are bounded, then the OR region is also bounded. */ } else { result = 1; } } /* Free resources. */ reg1 = astAnnul( reg1 ); reg2 = astAnnul( reg2 ); /* Cache the value in the CmpRegion. */ this->bounded = astOK ? result : -INT_MAX; } /* Return zero if an error occurred. Otherwise, return the cached value. */ if( astOK ) { result = ( this->bounded == -INT_MAX ) ? 0 : this->bounded; } else { result = 0; } /* Return the required pointer. */ return result; } static double GetFillFactor( AstRegion *this_region, int *status ) { /* * Name: * GetFillFactor * Purpose: * Obtain the value of the FillFactor attribute for a CmpRegion. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * double GetFillFactor( AstRegion *this, int *status ) * Class Membership: * CmpRegion member function (over-rides the astGetFillFactor method inherited * from the Region class). * Description: * This function returns the value of the FillFactor attribute for a * CmpRegion. A suitable default value is returned if no value has * previously been set. * Parameters: * this * Pointer to the CmpRegion. * status * Pointer to the inherited status variable. * Returned Value: * The FillFactor value to use. */ /* Local Variables: */ AstCmpRegion *this; double result; /* Check the global error status. */ if ( !astOK ) return AST__BAD; /* Initialise. */ result = AST__BAD; /* Obtain a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* See if a FillFactor value has been set. If so, use the parent astGetFillFactor method to obtain it. */ if ( astTestFillFactor( this ) ) { result = (*parent_getfillfactor)( this_region, status ); /* Otherwise, we will generate a default value equal to the FillFactor values of the first component Region. */ } else { result = astGetFillFactor( this->region1 ); } /* If an error occurred, clear the returned value. */ if ( !astOK ) result = AST__BAD; /* Return the result. */ return result; } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * CmpRegion member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied CmpRegion, * in bytes. * Parameters: * this * Pointer to the CmpRegion. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the CmpRegion structure. */ this = (AstCmpRegion *) this_object; /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by this class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astGetObjSize( this->region1 ); result += astGetObjSize( this->region2 ); if( this->xor1 ) result += astGetObjSize( this->xor1 ); if( this->xor2 ) result += astGetObjSize( this->xor2 ); /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2, int *oper, int *neg1, int *neg2, int *status ) { /* * * Name: * GetRegions * Purpose: * Get the component Regions of a CmpRegion. * Type: * Private function. * Synopsis: * #include "region.h" * void GetRegions( AstCmpRegion *this, AstRegion **reg1, AstRegion **reg2, * int *oper, int *neg1, int *neg2, int *status ) * Class Membership: * CmpRegion member function * Description: * This function returns pointers to two Regions which, when applied * using the returned boolean operator, are equivalent to the supplied * Region. If the CmpRegion has been negated, then the returned operator * and "negated" flags will be set such that they represent the * negated CmpRegion. * * The current Frames in both the returned component Regions will be * equivalent to the base Frame in the FrameSet encapsulated by the * parent Region structure. * Parameters: * this * Pointer to the CmpRegion. * reg1 * Address of a location to receive a pointer to first component * Region. The current Frame in this region will be equivalent to * the base Frame in the FrameSet * reg2 * Address of a location to receive a pointer to second component * Region. * oper * Address of a location to receive a value indicating how the * component Regions are combined together. This will be one of * AST__AND or AST__OR * neg1 * The value of the Negated attribute to be used with reg1. * neg2 * The value of the Negated attribute to be used with reg2. * status * Pointer to the inherited status variable. * Notes: * - Any changes made to the component Regions using the returned * pointers will be reflected in the supplied CmpRegion. *- */ /* Initialise */ if( reg1 ) *reg1 = NULL; if( reg2 ) *reg2 = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Return the component Region pointers. */ if( reg1 ) *reg1 = astClone( this->region1 ); if( reg2 ) *reg2 = astClone( this->region2 ); /* Initialise the other returned items. Note, the CmpRegion initialiser stored a deep copy of the supplied component Regions, and so we do not need to worry about attributes of the components having been changed after the creation of the CmpRegion. This is different to the CmpMap class which merely clones its supplied component pointers and so has to save copies of the original Invert settings within the CmpMap structure. */ if( oper ) *oper = this->oper; if( neg1 ) *neg1 = astGetNegated( this->region1 ); if( neg2 ) *neg2 = astGetNegated( this->region2 ); /* If the CmpRegion has been inverted, we modify the boolean operator and negation flags so that they reflect the inverted CmpRegion. */ if( astGetNegated( this ) ) { /* If the component Regions are combined using AND, then the negated CmpRegion combines its negated components using OR. */ if( this->oper == AST__AND ){ if( oper ) *oper = AST__OR; if( neg1 ) *neg1 = *neg1 ? 0 : 1; if( neg2 ) *neg2 = *neg2 ? 0 : 1; /* If the component Regions are combined using OR, then the negated CmpRegion combines its negated components using AND. */ } else if( this->oper == AST__OR ){ if( oper ) *oper = AST__AND; if( neg1 ) *neg1 = *neg1 ? 0 : 1; if( neg2 ) *neg2 = *neg2 ? 0 : 1; } else if( astOK ) { astError( AST__INTER, "GetRegions(%s): The %s refers to an unknown " "boolean operator with identifier %d (internal AST " "programming error).", status, astGetClass( this ), astGetClass( this ), this->oper ); } } } static AstRegion *GetDefUnc( AstRegion *this_region, int *status ) { /* * Name: * GetDefUnc * Purpose: * Obtain a pointer to the default uncertainty Region for a given Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * AstRegion *GetDefUnc( AstRegion *this ) * Class Membership: * CmpRegion method (over-rides the astGetDefUnc method inherited from * the Region class). * This function returns a pointer to a Region which represents the * default uncertainty associated with a position on the boundary of the * given Region. The returned Region refers to the base Frame within the * FrameSet encapsulated by the supplied Region. * Parameters: * this * Pointer to the Region. * Returned Value: * A pointer to the Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ AstRegion *result; /* Returned pointer */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* If the first component region has non-default uncertainty, use it as the default uncertainty for the CmpRegion. Note, the current Frame of an uncertainty Region is assumed to be the same as the base Frame in the CmpRegion. */ if( astTestUnc( this->region1 ) ) { result = astGetUncFrm( this->region1, AST__CURRENT ); /* Otherwise, if the second component region has non-default uncertainty, use it as the default uncertainty for the CmpRegion. */ } else if( astTestUnc( this->region2 ) ) { result = astGetUncFrm( this->region2, AST__CURRENT ); /* Otherwise, use the parent method to determine the default uncertainty. */ } else { result = (* parent_getdefunc)( this_region, status ); } /* Return NULL if an error occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the required pointer. */ return result; } void astInitCmpRegionVtab_( AstCmpRegionVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitCmpRegionVtab * Purpose: * Initialise a virtual function table for a CmpRegion. * Type: * Protected function. * Synopsis: * #include "cmpregion.h" * void astInitCmpRegionVtab( AstCmpRegionVtab *vtab, const char *name ) * Class Membership: * CmpRegion vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the CmpRegion class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstRegionVtab *region; /* Pointer to Region component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitRegionVtab( (AstRegionVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsACmpRegion) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstRegionVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->CmpRegionList = CmpRegionList; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; region = (AstRegionVtab *) vtab; parent_transform = mapping->Transform; mapping->Transform = Transform; parent_simplify = mapping->Simplify; mapping->Simplify = Simplify; parent_getdefunc = region->GetDefUnc; region->GetDefUnc = GetDefUnc; parent_setregfs = region->SetRegFS; region->SetRegFS = SetRegFS; parent_resetcache = region->ResetCache; region->ResetCache = ResetCache; parent_equal = object->Equal; object->Equal = Equal; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_clearclosed = region->ClearClosed; region->ClearClosed = ClearClosed; parent_clearmeshsize = region->ClearMeshSize; region->ClearMeshSize = ClearMeshSize; parent_setclosed = region->SetClosed; region->SetClosed = SetClosed; parent_setmeshsize = region->SetMeshSize; region->SetMeshSize = SetMeshSize; parent_getfillfactor = region->GetFillFactor; region->GetFillFactor = GetFillFactor; parent_regsetattrib = region->RegSetAttrib; region->RegSetAttrib = RegSetAttrib; parent_regclearattrib = region->RegClearAttrib; region->RegClearAttrib = RegClearAttrib; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ mapping->Decompose = Decompose; region->RegBaseBox = RegBaseBox; region->RegBaseBox2 = RegBaseBox2; region->RegBaseMesh = RegBaseMesh; region->RegSplit = RegSplit; region->RegPins = RegPins; region->RegTrace = RegTrace; region->GetBounded = GetBounded; region->RegBasePick = RegBasePick; /* Declare the copy constructor, destructor and class dump function. */ astSetCopy( vtab, Copy ); astSetDelete( vtab, Delete ); astSetDump( vtab, Dump, "CmpRegion", "Combination of two Regions" ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * CmpRegion member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NULL. */ if( !this_object ) return result; /* Obtain a pointers to the CmpRegion structure. */ this = (AstCmpRegion *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->region1, mode, extra, fail ); if( !result ) result = astManageLock( this->region2, mode, extra, fail ); return result; } #endif static AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that, const char *method, int *status ) { /* * Name: * MatchRegion * Purpose: * Map a Region into the Frame of another Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * AstRegion *MatchRegion( AstRegion *this, int ifrm, AstRegion *that, * const char *method, int *status ) * Class Membership: * CmpRegion method. * Description: * This function returns a pointer to a new Region which is a copy of * "that" mapped into either the base or current Frame of "this". * Parameters: * this * Pointer to a Region defining the Frame of the returned Region. * ifrm * The index of a Frame within the FrameSet encapsulated by "this". * The returned Region will refer to the requested Frame. It should * be either AST__CURRENT or AST__BASE. * that * Pointer to a Region defining the shape and extent of the * returned Region. * method * Pointer to a string holding the calling method.This is only used * in error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a new Region. This should be annulled (using astAnnul) * when no longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFrame *frm; /* Current Frame from "fs" */ AstFrameSet *fs; /* FrameSet connecting that to this */ AstMapping *map; /* Base->Current Mapping from "fs" */ AstRegion *result; /* Returned pointer */ /* Initialise */ result = NULL; /* Check the global error status. Also return NULL if no Regions were supplied. */ if ( !astOK || !this || !that ) return result; /* Temporarily invert "this" if we are matching its base Frame (since the astConvert method matches current Frames). */ if( ifrm == AST__BASE ) astInvert( this ); /* Find a FrameSet connecting the current Frames of the two Regions */ fs = astConvert( that, this, "" ); /* Re-instate the original Frame indices in "this" if required. */ if( ifrm == AST__BASE ) astInvert( this ); /* Check a conversion path was found. */ if( fs ) { /* Get the Frame and Mapping form the FrameSet. */ frm = astGetFrame( fs, AST__CURRENT ); map = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* Re-map the Region. */ result = astMapRegion( that, map, frm ); /* Free resources. */ frm = astAnnul( frm ); map = astAnnul( map ); fs = astAnnul( fs ); /* Report an error if there is no conversion between the two Frames. */ } else { astError( AST__INTER, "%s(%s): MatchRegion cannot convert between " "the two supplied coordinate Frames (internal AST " "programming error).", status, method, astGetClass( this ) ); } /* Annul the returned pointer if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static void RegBaseBox( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){ /* * Name: * RegBaseBox * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void RegBaseBox( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegBaseBox protected * method inherited from the Region class). * Description: * This function returns the upper and lower axis bounds of a Region in * the base Frame of the encapsulated FrameSet, assuming the Region * has not been negated. That is, the value of the Negated attribute * is ignored. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ AstPointSet *ps; /* Mesh pointset */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ double **ptr; /* Pointer to mesh data */ double *clbnd1; /* Point to 1st comp lower bounds array */ double *clbnd2; /* Point to 2nd comp lower bounds array */ double *cubnd1; /* Point to 1st comp upper bounds array */ double *cubnd2; /* Point to 2nd comp upper bounds array */ double *p; /* Pointer to next coordinate value */ double lb; /* Lower limit */ double ub; /* Upper limit */ int i; /* Axis index */ int icoord; /* Coordinate index */ int inc1; /* First component interval is included? */ int inc2; /* Second component interval is included? */ int ipoint; /* Point index */ int nax; /* Number of axes in Frame */ int ncoord; /* Number of coords */ int neg1; /* First component negated? */ int neg2; /* Second component negated? */ int npoint; /* Number of points */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the CmpRegion structure */ this = (AstCmpRegion *) this_region; /* If the CmpRegion is bounded, we find the bounding box using a mesh of points spread evenly over the boundary of the CmpRegion. */ if( astGetBounded( this ) ) { ps = astRegBaseMesh( this_region ); ptr = astGetPoints( ps ); ncoord = astGetNcoord( ps ); npoint = astGetNpoint( ps ); if( astOK ) { for( icoord = 0; icoord < ncoord; icoord++ ) { lbnd[ icoord ] = DBL_MAX; ubnd[ icoord ] = -DBL_MAX; p = ptr[ icoord ]; for( ipoint = 0; ipoint < npoint; ipoint++, p++ ) { if( *p != AST__BAD ) { if( *p < lbnd[ icoord ] ) lbnd[ icoord ] = *p; if( *p > ubnd[ icoord ] ) ubnd[ icoord ] = *p; } } } } ps = astAnnul( ps ); /* If the CmpRegion is not bounded we look at each axis individually. */ } else { /* Get pointers to the component Regions. */ reg1 = this->region1; reg2 = this->region2; /* Get their negated flags */ neg1 = astGetNegated( reg1 ); neg2 = astGetNegated( reg2 ); /* The base Frame of the parent Region structure is the current Frame of the component Regions. Get the no. of axes in this Frame. */ nax = astGetNaxes( reg1 ); /* Get the bounding boxes of the component Regions in this Frame. */ clbnd1 = astMalloc( sizeof( double )*(size_t) nax ); cubnd1 = astMalloc( sizeof( double )*(size_t) nax ); clbnd2 = astMalloc( sizeof( double )*(size_t) nax ); cubnd2 = astMalloc( sizeof( double )*(size_t) nax ); if( astOK ) { astGetRegionBounds( reg1, clbnd1, cubnd1 ); astGetRegionBounds( reg2, clbnd2, cubnd2 ); /* Loop round every axis. */ for( i = 0; i < nax; i++ ) { /* If the first component Region has been negated, the lower and upper bounds from the first component are the bounds of an *excluded* axis interval, not an included interval. If either of the bounds are infinite, we can swap it to an included interval. If both bounds are finite, we cannot convert to an included interval. In this case, we assume that the gap will be filled at some point on another axis, if there is more than 1 axis, and convert it to an unbouded included interval. */ inc1 = 1; if( neg1 ) { lb = clbnd1[ i ]; ub = cubnd1[ i ]; if( lb == -DBL_MAX ) clbnd1[ i ] = ub; if( ub == DBL_MAX ) cubnd1[ i ] = lb; if( lb != -DBL_MAX && ub != DBL_MAX ) { if( nax == 1 ) { inc1 = 0; } else { clbnd1[ i ] = -DBL_MAX; cubnd1[ i ] = DBL_MAX; } } } /* Likewise attempt to convert an excluded interval into an included interval for the second component Region. */ inc2 = 1; if( neg2 ) { lb = clbnd2[ i ]; ub = cubnd2[ i ]; if( lb == -DBL_MAX ) clbnd2[ i ] = ub; if( ub == DBL_MAX ) cubnd2[ i ] = lb; if( lb != -DBL_MAX && ub != DBL_MAX ) { if( nax == 1 ) { inc2 = 0; } else { clbnd2[ i ] = -DBL_MAX; cubnd2[ i ] = DBL_MAX; } } } /* If the component Regions are combined using AND, find the overlap of the axis intervals. This depends on whether the intervals are included or excluded. */ if( this->oper == AST__AND ) { if( inc1 ) { if( inc2 ) { lbnd[ i ] = MAX( clbnd1[ i ], clbnd2[ i ] ); ubnd[ i ] = MIN( cubnd1[ i ], cubnd2[ i ] ); } else { lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ]; ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ]; } } else { if( inc2 ) { lbnd[ i ] = clbnd2[ i ] < clbnd1[ i ] ? clbnd2[ i ] : cubnd1[ i ]; ubnd[ i ] = cubnd2[ i ] > cubnd1[ i ] ? cubnd2[ i ] : clbnd1[ i ]; } else { lbnd[ i ] = clbnd1[ i ] < clbnd2[ i ] ? clbnd1[ i ] : cubnd2[ i ]; ubnd[ i ] = cubnd1[ i ] > cubnd2[ i ] ? cubnd1[ i ] : clbnd2[ i ]; } } /* If the component Regions are not combined using AND, find the union of the axis intervals. */ } else { if( inc1 && inc2 ) { lbnd[ i ] = MIN( clbnd1[ i ], clbnd2[ i ] ); ubnd[ i ] = MAX( cubnd1[ i ], cubnd2[ i ] ); } else { lbnd[ i ] = -DBL_MAX; ubnd[ i ] = DBL_MAX; } } } } /* Free resources. */ clbnd1 = astFree( clbnd1 ); cubnd1 = astFree( cubnd1 ); clbnd2 = astFree( clbnd2 ); cubnd2 = astFree( cubnd2 ); } } static void RegBaseBox2( AstRegion *this_region, double *lbnd, double *ubnd, int *status ){ /* * Name: * RegBaseBox2 * Purpose: * Returns the bounding box of an un-negated Region in the base Frame of * the encapsulated FrameSet. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void RegBaseBox2( AstRegion *this, double *lbnd, double *ubnd, int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegBaseBox2 protected * method inherited from the Region class). * Description: * This function is similar to astRegBaseBox in that it returns the * upper and lower axis bounds of a Region in the base Frame of the * encapsulated FrameSet. But, in addition to assuming that the * supplied Region has not been negated, it also assumes that any * component Regions contained within the supplied Region have not been * negated. * Parameters: * this * Pointer to the Region. * lbnd * Pointer to an array in which to return the lower axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * ubnd * Pointer to an array in which to return the upper axis bounds * covered by the Region in the base Frame of the encapsulated * FrameSet. It should have at least as many elements as there are * axes in the base Frame. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ double *clbnd1; /* Point to 1st comp lower bounds array */ double *clbnd2; /* Point to 2nd comp lower bounds array */ double *cubnd1; /* Point to 1st comp upper bounds array */ double *cubnd2; /* Point to 2nd comp upper bounds array */ int i; /* Axis index */ int nax; /* Number of axes in Frame */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the CmpRegion structure */ this = (AstCmpRegion *) this_region; /* Get pointers to the component Regions. */ reg1 = this->region1; reg2 = this->region2; /* The base Frame of the parent Region structure is the current Frame of the component Regions. Get the no. of axes in this Frame. */ nax = astGetNaxes( reg1 ); /* Get the bounding boxes of the component Regions in this Frame. */ clbnd1 = astMalloc( sizeof( double )*(size_t) nax ); cubnd1 = astMalloc( sizeof( double )*(size_t) nax ); clbnd2 = astMalloc( sizeof( double )*(size_t) nax ); cubnd2 = astMalloc( sizeof( double )*(size_t) nax ); if( astOK ) { astGetRegionBounds2( reg1, clbnd1, cubnd1 ); astGetRegionBounds2( reg2, clbnd2, cubnd2 ); /* How we combine the two bounding boxes depends on the boolean operator associated with this CmpRegion. For AND find the overlap of the two bounding boxes. For other operators find the union. */ if( this->oper == AST__AND ) { for( i = 0; i < nax; i++ ) { lbnd[ i ]= MAX( clbnd1[ i ], clbnd2[ i ] ); ubnd[ i ]= MIN( cubnd1[ i ], cubnd2[ i ] ); } } else { for( i = 0; i < nax; i++ ) { lbnd[ i ]= MIN( clbnd1[ i ], clbnd2[ i ] ); ubnd[ i ]= MAX( cubnd1[ i ], cubnd2[ i ] ); } } } /* Free resources. */ clbnd1 = astFree( clbnd1 ); cubnd1 = astFree( cubnd1 ); clbnd2 = astFree( clbnd2 ); cubnd2 = astFree( cubnd2 ); } static AstPointSet *RegBaseMesh( AstRegion *this_region, int *status ){ /* * Name: * RegBaseMesh * Purpose: * Return a PointSet containing a mesh of points on the boundary of a * Region in its base Frame. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * AstPointSet *astRegBaseMesh( AstRegion *this, int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegBaseMesh protected * method inherited from the Region class). * Description: * This function returns a PointSet containing a mesh of points on the * boundary of the Region. The points refer to the base Frame of * the encapsulated FrameSet. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the PointSet. Annul the pointer using astAnnul when it * is no longer needed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstCmpRegion *this; /* The CmpRegion structure */ AstPointSet *mesh1; /* PointSet holding mesh for 1st component */ AstPointSet *mesh1b; /* Mesh for 1st component mapped by 2nd comp. */ AstPointSet *mesh2; /* PointSet holding mesh for 2nd component */ AstPointSet *mesh2b; /* Mesh for 2nd component mapped by 1st comp. */ AstPointSet *result; /* Returned pointer */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ double **ptr1; /* Pointer to array of mesh1b axis value pointers */ double **ptr2; /* Pointer to array of mesh2b axis value pointers */ double **ptr; /* Pointer to array of total axis value pointers */ double *lbnd; /* Pointer to array of bounding box lower bounds */ double *ubnd; /* Pointer to array of bounding box upper bounds */ double v; /* Axis value */ int hasMesh1; /* Does 1st component Region have a mesh? */ int hasMesh2; /* Does 2nd component Region have a mesh? */ int ic; /* Axis index */ int ip; /* Input point index */ int jp; /* Output point index */ int nc; /* No. of axis values per point */ int np1; /* No. of points in mesh1b */ int np2; /* No. of points in mesh2b */ int np; /* No. of points in returned PointSet */ int ok; /* Were all axis values good at this point? */ /* Initialise */ result= NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* If the Region structure contains a pointer to a PointSet holding a previously created mesh, return it. */ if( this_region->basemesh ) { result = astClone( this_region->basemesh ); /* Otherwise, create a new mesh. */ } else { /* Get pointers to the component regions. */ reg1 = this->region1; reg2 = this->region2; /* A mesh can only be produced for a Region if it is bounded when either negated or un-negated. See if meshes can be produced for the component Regions. */ hasMesh1 = astGetBounded( reg1 ); if( !hasMesh1 ){ astNegate( reg1 ); hasMesh1 = astGetBounded( reg1 ); astNegate( reg1 ); } hasMesh2 = astGetBounded( reg2 ); if( !hasMesh2 ){ astNegate( reg2 ); hasMesh2 = astGetBounded( reg2 ); astNegate( reg2 ); } /* If neither Region has a mesh we cannot produce a mesh. */ if( !hasMesh1 && !hasMesh2 && astOK ) { astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be " "produced for the %s bacause neither of its component " "Regions has a mesh (internal AST programming error).", status, astGetClass( this ), astGetClass( this ) ); /* If only one Region has a mesh, we can produce a mesh so long as the boolean operator is not OR. */ } else if( ( !hasMesh1 || !hasMesh2 ) && this->oper == AST__OR && astOK ) { astError( AST__INTER, "astRegBaseMesh(%s): No mesh can be produced " "for the %s bacause one its component Regions has no " "mesh and the union of the Regions is required (internal " "AST programming error).", status, astGetClass( this ), astGetClass( this ) ); } /* Allocate memory to hold a bounding box in the base Frame of the CmpRegion. */ nc = astGetNin( this_region->frameset ); lbnd = astMalloc( sizeof( double )*(size_t) nc ); ubnd = astMalloc( sizeof( double )*(size_t) nc ); /* Get current Frame meshes covering the two component Regions (the current Frame of the component Regions is the same as the base Frame of the parent Region). We now know that at least one Region has a mesh. If the other one does not have a mesh we may be able to create a mesh by taking the intersection of the Region with the bounding box of the bounded Region. */ if( hasMesh1 ) { mesh1 = astRegMesh( reg1 ); if( hasMesh2 ) { mesh2 = astRegMesh( reg2 ); } else { astGetRegionBounds( reg1, lbnd, ubnd ); mesh2 = astBndMesh( reg2, lbnd, ubnd ); } } else { mesh2 = astRegMesh( reg2 ); astGetRegionBounds( reg2, lbnd, ubnd ); mesh1 = astBndMesh( reg1, lbnd, ubnd ); } /* If the CmpRegion represents the intersection of the two component Regions (AND operator), the total mesh is the sum of the component mesh points which are inside the other component region. If the CmpRegion represents the union of the two component Regions (OR operator), the total mesh is the sum of the component mesh points which are outside the other component region. So temporarily negate the component Regions if they are combined using OR. */ if( this->oper == AST__OR ) { astNegate( reg1 ); astNegate( reg2 ); } /* Transform the mesh for the first component using the second component as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds of the second component will be set bad. */ mesh1b = astTransform( reg2, mesh1, 1, NULL ); /* Transform the mesh for the second component using the first component as a Mapping. Mesh points outside (or inside if "oper" is OR) the bounds of the first component will be set bad. */ mesh2b = astTransform( reg1, mesh2, 1, NULL ); /* If required, negate them again to bring them back to their original state.*/ if( this->oper == AST__OR ) { astNegate( reg1 ); astNegate( reg2 ); } /* The required mesh contains all the good points form both mesh1b and mesh2b (i.e. all boundary points which are inside -or inside if "oper" is OR- the other component Region). Create a PointSet assuming that all points are good. First allocate an array to hold pointers to the arrays holding coordinate values for each axis. */ nc = astGetNcoord( mesh1b ); np1 = astGetNpoint( mesh1b ); np2 = astGetNpoint( mesh2b ); np = np1 + np2; result = astPointSet( np, nc, "", status ); ptr = astGetPoints( result ); /* Get points to the axis values of the mapped meshes. */ ptr1 = astGetPoints( mesh1b ); ptr2 = astGetPoints( mesh2b ); /* Check pointers can be used safely. */ if( astOK ) { /* Initialise the index of the next point in the total mesh. */ jp = 0; /* Loop round all the points in the transformed mesh for the first component. */ for( ip = 0; ip < np1; ip++ ) { /* Assume this point has good axis values */ ok = 1; /* Copy the axis values into the total mesh. Break if a bad axis value is found. */ for( ic = 0; ic < nc; ic++ ) { v = ptr1[ ic ][ ip ]; if( v != AST__BAD ) { ptr[ ic ][ jp ] = v; } else { ok = 0; break; } } /* If no bad axis values were found, increment the index of the next point in the total mesh. */ if( ok ) jp++; } /* Now similarly copy the good values from the second transformed mesh onto the end of the total mesh array. */ for( ip = 0; ip < np2; ip++ ) { ok = 1; for( ic = 0; ic < nc; ic++ ) { v = ptr2[ ic ][ ip ]; if( v != AST__BAD ) { ptr[ ic ][ jp ] = v; } else { ok = 0; break; } } if( ok ) jp++; } /* If the total mesh contains no good points, we will create a PointSet holding a single bad position. */ if( jp == 0 ) { np = 1; for( ic = 0; ic < nc; ic++ ) ptr[ ic ][ 0 ] = AST__BAD; } else { np = jp; } /* Adjust the size of the returned PointSet to exclude the extra space caused by any axis values being bad in the transformed meshes. */ astSetNpoint( result, np ); } /* Free resources. */ mesh1 = astAnnul( mesh1 ); mesh2 = astAnnul( mesh2 ); mesh1b = astAnnul( mesh1b ); mesh2b = astAnnul( mesh2b ); lbnd = astFree( lbnd ); ubnd = astFree( ubnd ); /* Save the returned pointer in the Region structure so that it does not need to be created again next time this function is called. */ if( astOK && result ) this_region->basemesh = astClone( result ); } /* Annul the result if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return a pointer to the output PointSet. */ return result; } static AstRegion *RegBasePick( AstRegion *this_region, int naxes, const int *axes, int *status ){ /* * Name: * RegBasePick * Purpose: * Return a Region formed by picking selected base Frame axes from the * supplied Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * AstRegion *RegBasePick( AstRegion *this, int naxes, const int *axes, * int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegBasePick protected * method inherited from the Region class). * Description: * This function attempts to return a Region that is spanned by selected * axes from the base Frame of the encapsulated FrameSet of the supplied * Region. This may or may not be possible, depending on the class of * Region. If it is not possible a NULL pointer is returned. * Parameters: * this * Pointer to the Region. * naxes * The number of base Frame axes to select. * axes * An array holding the zero-based indices of the base Frame axes * that are to be selected. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the Region, or NULL if no region can be formed. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion structure */ AstFrame *frm1; /* Axes picked from the 1st encapsulated Region */ AstFrame *frm2; /* Axes picked from the 2nd encapsulated Region */ AstRegion *result; /* Returned Region */ /* Initialise */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the CmpRegion information. */ this = (AstCmpRegion *) this_region; /* Both encapsulated regions refer to the same Frame (the base Frame of the parent Region), so attempt to pick the requested axs from them. If the resulting Frames are not Regions, we cannot pick the requested axes so return the NULL Frame pointer initialised above. */ frm1 = astPickAxes( this->region1, naxes, axes, NULL ); if( astIsARegion( frm1 ) ) { frm2 = astPickAxes( this->region2, naxes, axes, NULL ); if( astIsARegion( frm2 ) ) { /* Create the new CmpRegion. */ result = (AstRegion *) astCmpRegion( (AstRegion *) frm1, (AstRegion *) frm2, this->oper, "", status ); } /* Free resources */ frm2 = astAnnul( frm2 ); } frm1 = astAnnul( frm1 ); /* Return a NULL pointer if an error has occurred. */ if( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc, int **mask, int *status ){ /* * Name: * RegPins * Purpose: * Check if a set of points fall on the boundary of a given CmpRegion. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * int RegPins( AstRegion *this, AstPointSet *pset, AstRegion *unc, * int **mask, int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegPins protected * method inherited from the Region class). * Description: * This function returns a flag indicating if the supplied set of * points all fall on the boundary of the given CmpRegion. * * Some tolerance is allowed, as specified by the uncertainty Region * stored in the supplied CmpRegion "this", and the supplied uncertainty * Region "unc" which describes the uncertainty of the supplied points. * Parameters: * this * Pointer to the CmpRegion. * pset * Pointer to the PointSet. The points are assumed to refer to the * base Frame of the FrameSet encapsulated by "this". * unc * Pointer to a Region representing the uncertainties in the points * given by "pset". The Region is assumed to represent the base Frame * of the FrameSet encapsulated by "this". Zero uncertainity is assumed * if NULL is supplied. * mask * Pointer to location at which to return a pointer to a newly * allocated dynamic array of ints. The number of elements in this * array is equal to the value of the Npoint attribute of "pset". * Each element in the returned array is set to 1 if the * corresponding position in "pset" is on the boundary of the Region * and is set to zero otherwise. A NULL value may be supplied * in which case no array is created. If created, the array should * be freed using astFree when no longer needed. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the points all fall on the boundary of the given * Region, to within the tolerance specified. Zero otherwise. */ /* Local variables: */ AstCmpRegion *this; /* Pointer to the CmpRegion structure. */ AstPointSet *pset1; /* Points masked by 1st component Region */ AstPointSet *pset2; /* Points masked by 2nd component Region */ AstPointSet *psetb1; /* Points in base Frame of 1st component Region */ AstPointSet *psetb2; /* Points in base Frame of 2nd component Region */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ AstRegion *unc1; /* Base Frame uncertainty in 1st component Region */ AstRegion *unc2; /* Base Frame uncertainty in 2nd component Region */ double **ptr1; /* Pointer to axis values in "pset1" */ double **ptr2; /* Pointer to axis values in "pset2" */ double *p1; /* Pointer to next axis zero value for pset1 */ double *p2; /* Pointer to next axis zero value for pset2 */ int *mask1; /* Mask for first component boundary */ int *mask2; /* Mask for second component boundary */ int ip; /* Point index */ int np; /* Number of points */ int result; /* Returned flag */ /* Initialise */ result = 0; if( mask ) *mask = NULL; /* Check the inherited status. */ if( !astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Get pointers to the two component Regions. */ reg1 = this->region1; reg2 = this->region2; /* Get a mask which indicates if each supplied point is on or off the boundary of the first component Region. astRegPins expects its "pset" argument to contain positions in the base Frame of the Region, so we must first transform the supplied points into the base Frame of "reg1". We must also map the uncertainty into the base Frame of the component Region. */ psetb1 = astRegTransform( reg1, pset, 0, NULL, NULL ); unc1 = MatchRegion( reg1, AST__BASE, unc, "astRegPins", status ); astRegPins( reg1, psetb1, unc1, &mask1 ); /* Likewise, get a mask which indicates if each supplied point is on or off the boundary of the second component Region. */ psetb2 = astRegTransform( reg2, pset, 0, NULL, NULL ); unc2 = MatchRegion( reg2, AST__BASE, unc, "astRegPins", status ); astRegPins( reg2, psetb2, unc2, &mask2 ); /* The criteria for a point to be on the boundary of the CmpRegion depend on the boolean operator being used. If component regions A and B are ANDed together, then a point is on the boundary of the CmpRegion if either 1) it is on the boundary of A and inside B, or 2) it is on the boundary of B and inside A. If the component regions are ORed together, then a point is on the boundary of the CmpRegion if either 1) it is on the boundary of A and outside B, or 2) it is on the boundary of B and outside A. Either we need to transform the supplied PointSet using each component Region as a Mapping. But if using OR we temporarily negate the Regions. */ if( this->oper == AST__OR ) { astNegate( reg1 ); astNegate( reg2 ); } pset1 = astTransform( reg1, pset, 1, NULL ); pset2 = astTransform( reg2, pset, 1, NULL ); if( this->oper == AST__OR ) { astNegate( reg1 ); astNegate( reg2 ); } /* Get pointers to the axis values in these PointSets */ ptr1 = astGetPoints( pset1 ); ptr2 = astGetPoints( pset2 ); /* If required, create an output mask array */ np = astGetNpoint( pset ); if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np ); /* Check pointers can be used safely. */ if( astOK ) { /* We can use the values for the first axis to indicate if a point is inside or outside a Region. So store pointers to the first axis arrays. */ p1 = ptr1[ 0 ]; p2 = ptr2[ 0 ]; /* Assume all points are on the boundary of the CmpRegion. */ result = 1; /* If we are creating an output mask, we must check every point. Otherwise we can stop checking when we find the first point which is not on the boundary of the CmpRegion. */ if( mask ) { for( ip = 0; ip < np; ip++ ) { if( ( mask1[ ip ] && p2[ ip ] != AST__BAD ) || ( mask2[ ip ] && p1[ ip ] != AST__BAD ) ){ (*mask)[ ip ] = 1; } else { (*mask)[ ip ] = 0; result = 0; } } } else { for( ip = 0; ip < np; ip++ ) { if( ( !mask1[ ip ] || p2[ ip ] == AST__BAD ) && ( !mask2[ ip ] || p1[ ip ] == AST__BAD ) ){ result = 0; break; } } } } /* Free resources */ mask1 = astFree( mask1 ); mask2 = astFree( mask2 ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); psetb1 = astAnnul( psetb1 ); psetb2 = astAnnul( psetb2 ); if( unc1 ) unc1 = astAnnul( unc1 ); if( unc2 ) unc2 = astAnnul( unc2 ); /* If an error has occurred, return zero. */ if( !astOK ) { result = 0; if( mask ) *mask = astAnnul( *mask ); } /* Return the result. */ return result; } static void RegSetAttrib( AstRegion *this_region, const char *setting, char **base_setting, int *status ) { /* * Name: * RegSetAttrib * Purpose: * Set an attribute value for a Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void RegSetAttrib( AstRegion *this, const char *setting, * char **base_setting, int *status ) * Class Membership: * CmpRegion method (over-rides the astRegSetAttrib method inherited from * the Region class). * Description: * This function assigns an attribute value to both the base and * current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * setting * Pointer to a null terminated attribute setting string. NOTE, IT * SHOULD BE ENTIRELY LOWER CASE. The supplied string will be * interpreted using the public interpretation implemented by * astSetAttrib. This can be different to the interpretation of the * protected accessor functions. For instance, the public * interpretation of an unqualified floating point value for the * Epoch attribute is to interpet the value as a gregorian year, * but the protected interpretation is to interpret the value as an * MJD. * base_setting * Address of a location at which to return a pointer to the null * terminated attribute setting string which was applied to the * base Frame of the encapsulated FrameSet. This may differ from * the supplied setting if the supplied setting contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstCmpRegion *this; char *bset; int rep; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Use the RegSetAttrib method inherited from the parent class to apply the setting to the current and base Frames in the FrameSet encapsulated by the parent Region structure. */ (*parent_regsetattrib)( this_region, setting, &bset, status ); /* Now apply the base Frame setting to the component Regions (the current Frame within the component Regions is equivalent to the base Frame in the parent Region structure). Annul any "attribute unknown" error that results from attempting to do this. */ if( astOK ) { rep = astReporting( 0 ); astRegSetAttrib( this->region1, bset, NULL ); astRegSetAttrib( this->region2, bset, NULL ); if( astStatus == AST__BADAT ) astClearStatus; astReporting( rep ); } /* If required, return the base Frame setting string, otherwise free it. */ if( base_setting ) { *base_setting = bset; } else { bset = astFree( bset ); } } static AstRegion **RegSplit( AstRegion *this_region, int *nlist, int *status ){ /* *+ * Name: * RegSplit * Purpose: * Split a Region into a list of disjoint component Regions. * Type: * Private function. * Synopsis: * #include "region.h" * AstRegion **astRegSplit( AstRegion *this, int *nlist ) * Class Membership: * CmpRegion member function (overrides the astRegSplit method * inherited from the parent Region class). * Description: * This function splits the supplied Region into a set of disjoint * component Regions. If the Region cannot be split, then the returned * array contains only one pointer - a clone of the supplied Region * pointer. * Parameters: * this * Pointer to the Region. * nlist * Pointer to an int in which to return the number of elements in * the returned array. * Returned Value: * Pointer to dynamically alloctaed memory holding an array of Region * pointers. The length of this array is given by the value returned * in "*nlist". The pointers in the returned array should be annulled * using astAnnul when no longer needed, and the memory used to hold * the array should be freed using astFree. * Notes: * - A NULL pointer is returned if an error has already occurred, or if * this function should fail for any reason. *- */ /* Local Variables; */ AstCmpRegion *new; AstCmpRegion *this; AstFrame *frm; AstFrameSet *fs; AstMapping *map; AstRegion **cmplist; AstRegion **result; AstRegion *cmpreg; AstRegion *new_reg; int icomp; int ifirst; int ilist; int iw; int jcomp; int ncomp; int nn; int unbounded; /* Initialise. */ result = NULL; *nlist = 0; /* Check the local error status. */ if ( !astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Can only split non-inverted CmpRegions that combine their components using the OR operator. */ if( this->oper == AST__OR && !astGetNegated( this->region1 ) && !astGetNegated( this->region2 ) ) { /* Indicate we have not yet found any unbounded component regions. */ unbounded = 0; /* Process each of the two component Regions in turn. */ for( icomp = 0; icomp < 2 && !unbounded; icomp++ ) { cmpreg = icomp ? this->region2 : this->region1; /* Create a set of disjoint Regions that are equivalent to the current component Region, and loop round them. */ cmplist = astRegSplit( cmpreg, &ncomp ); for( jcomp = 0; jcomp < ncomp; jcomp++ ) { /* If any of the components are unbounds, we cannot split the supplied Region. */ unbounded = unbounded || !astGetBounded( cmplist[ jcomp ] ); if( ! unbounded ) { /* Initialise the index within the returned list of the first Region that overlaps the current disjoint component Region. */ ifirst = -1; /* Loop round all the Regions currently in the returned list. */ for( ilist = 0; ilist < *nlist; ilist++ ) { if( result[ ilist ] ) { /* See if the current disjoint component overlaps the current entry in the returned list. */ if( astOverlap( cmplist[ jcomp ], result[ ilist ] ) > 1 ) { /* If this is the first overlap found for the current disjoint component, form a CmpRegion that combines the two overlapping Regions, and use it to replace the current entry in the returned list. */ if( ifirst == -1 ) { new = astCmpRegion( cmplist[ jcomp ], result[ ilist ], AST__OR, " ", status ); (void) astAnnul( result[ ilist ] ); result[ ilist ] = (AstRegion *) new; /* Note the index within the returned list of the first Region that overlaps the current disjoint component Region. */ ifirst = ilist; /* If this is the second or later overlap, add the overlapping returned Region into the CmpRegion that it is stored at index "ifirsT" in the returned list. */ } else { new = astCmpRegion( result[ ilist ], result[ ifirst ], AST__OR, " ", status ); result[ ilist ] = astAnnul( result[ ilist ] ); (void) astAnnul( result[ ifirst ] ); result[ ifirst ] = (AstRegion *) new; } } } } /* If the current disjoint component does not overlap any of the Regions already in the returned list, append the current disjoint component to the end of the returned list. */ if( ifirst == -1 ) { ilist = (*nlist)++; result = astGrow( result, *nlist, sizeof( *result ) ); if( astOK ) result[ ilist ] = astClone( cmplist[ jcomp ] ); } } /* Annul the pointer to the disjoint component Region. */ cmplist[ jcomp ] = astAnnul( cmplist[ jcomp ] ); } /* Free the mnemory holding the list of disjoint components. */ cmplist = astFree( cmplist ); } } /* If any unbounded components were found, ensure the returned list is empty. */ if( unbounded && result ) { for( ilist = 0; ilist < *nlist; ilist++ ) { if( result[ ilist ] ) result[ ilist ] = astAnnul( result[ ilist ] ); } result = astFree( result ); *nlist = 0; /* Otherwise, shuffle later entries down to fill any NULL slots in the returned list. */ } else if( result ){ nn = *nlist; iw = 0; for( ilist = 0; ilist < nn; ilist++ ) { if( result[ ilist ] ) result[ iw++ ] = result[ ilist ]; } *nlist = iw; } /* If this CmpRegion cannot be split, the returned list just holds a clone of the Region pointer. */ if( !result ) { result = astMalloc( sizeof( *result ) ); if( astOK ) { result[ 0 ] = astClone( this ); *nlist = 1; } } /* Remap any returned Regions so that they are defined within the same coordinate system as the supplied Region. */ if( result && *nlist > 0 ) { fs = this_region->frameset; map = astGetMapping( fs, AST__BASE, AST__CURRENT ); frm = astGetFrame( fs, AST__CURRENT ); for( ilist = 0; ilist < *nlist; ilist++ ) { new_reg = astMapRegion( result[ ilist ], map, frm ); (void) astAnnul( result[ ilist ] ); result[ ilist ] = new_reg; } map = astAnnul( map ); frm = astAnnul( frm ); } /* Free all returned pointers if an error has occurred. */ if( !astOK && result ) { for( ilist = 0; ilist < *nlist; ilist++ ) { result[ ilist ] = astAnnul( result[ ilist ] ); } result = astFree( result ); *nlist = 0; } /* Return the result. */ return result; } static int RegTrace( AstRegion *this_region, int n, double *dist, double **ptr, int *status ){ /* *+ * Name: * RegTrace * Purpose: * Return requested positions on the boundary of a 2D Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * int astRegTrace( AstRegion *this, int n, double *dist, double **ptr ); * Class Membership: * CmpRegion member function (overrides the astRegTrace method * inherited from the parent Region class). * Description: * This function returns positions on the boundary of the supplied * Region, if possible. The required positions are indicated by a * supplied list of scalar parameter values in the range zero to one. * Zero corresponds to some arbitrary starting point on the boundary, * and one corresponds to the end (which for a closed region will be * the same place as the start). * Parameters: * this * Pointer to the Region. * n * The number of positions to return. If this is zero, the function * returns without action (but the returned function value still * indicates if the method is supported or not). * dist * Pointer to an array of "n" scalar parameter values in the range * 0 to 1.0. * ptr * A pointer to an array of pointers. The number of elements in * this array should equal tthe number of axes in the Frame spanned * by the Region. Each element of the array should be a pointer to * an array of "n" doubles, in which to return the "n" values for * the corresponding axis. The contents of the arrays are unchanged * if the supplied Region belongs to a class that does not * implement this method. * Returned Value: * Non-zero if the astRegTrace method is implemented by the class * of Region supplied, and zero if not. * Notes: * - The current algorithm results in the boundary of the CmpRegion * being dis-contiguous - supplied distance values from zero up to some * mid-value correspond to positions on the first component Region, and * higher distance (up to 1.0) correspond to points on the second * component Region. *- */ /* Local Variables; */ AstCmpRegion *this; AstFrame *frm; AstMapping *map; AstPointSet *bpset; AstPointSet *cpset; AstRegion *ureg1; AstRegion *ureg2; double **bptr; int i; int j; int ncur; int result; double *rval; double *off; double *r1d; double *r2d; double *r1ptr[ 2 ]; double *r2ptr[ 2 ]; double **r1ptrb; double **r2ptrb; double dbreak; double dtot; double x; double x0; int r1n; int r2n; AstPointSet *r1pset; AstPointSet *r2pset; AstPointSet *r1psetb; AstPointSet *r2psetb; /* Initialise */ result = 0; /* Check inherited status. */ if( ! astOK ) return result; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Get a pointer to the base Frame in the encapsulated FrameSet. */ frm = astGetFrame( this_region->frameset, AST__BASE ); /* Check it is 2-dimensional. */ result = 1; if( astGetNaxes( frm ) != 2 ) result = 0; /* Check the component Regions can be traced. */ if( !astRegTrace( this->region1, 0, NULL, NULL ) || !astRegTrace( this->region1, 0, NULL, NULL ) ) result = 0; /* Check we have some points to find. */ if( result && n > 0 ) { /* We first determine the required positions in the base Frame of the Region, and then transform them into the current Frame. Get the base->current Mapping, and the number of current Frame axes. */ map = astGetMapping( this_region->frameset, AST__BASE, AST__CURRENT ); /* If it's a UnitMap we do not need to do the transformation, so put the base Frame positions directly into the supplied arrays. */ if( astIsAUnitMap( map ) ) { bpset = NULL; bptr = ptr; ncur = 2; /* Otherwise, create a PointSet to hold the base Frame positions. */ } else { bpset = astPointSet( n, 2, " ", status ); bptr = astGetPoints( bpset ); ncur = astGetNout( map ); } r1d = astMalloc( sizeof( double )*n ); r2d = astMalloc( sizeof( double )*n ); /* Ensure information about the breaks in the boundary of each component region is available within the CmpRegion structure. These breaks are the points at which the two boundaries cross. */ SetBreakInfo( this, 0, status ); SetBreakInfo( this, 1, status ); /* Get the constants needed to convert the supplied distances (normalised so that the border of the entire CmpRegion has a length of 1.0), into geodesic distances around the border of each component Region. */ dtot = this->d0[ 0 ] + this->d0[ 1 ]; dbreak = this->d0[ 0 ]/dtot; /* Initialise here to avoid compiler warnings. */ r1n = 0; r2n = 0; /* Check the pointers can be used safely. */ if( astOK ) { /* Loop round all supplied distances, determining if they represent a position on the first or second component Region. */ for( i = 0; i < n; i++ ) { /* If the current distance represents a point in the second component Region... */ if( dist[ i ] > dbreak ) { /* Find the correspond distance around the used sections of the second component region (normalised so that the entire border of the component region has a length of "this->d0[1]"). */ x0 = ( dist[ i ] - dbreak )*dtot; x = x0; /* Convert this into the correspond distance around the entire border of the second component region (normalised so that the entire border of the component region has unit length). */ rval = this->rvals[ 1 ]; off = this->offs[ 1 ]; for( j = 0; j < this->nbreak[ 1 ]; j++,rval++,off++ ) { if( *rval >= x0 ) break; x += *off; } /* Store this as the next distance to move around the second component Region, normalising it to the range 0 to 1 as required by astRegTrace. */ r2d[ r2n++ ] = x/this->dtot[ 1 ]; /* Now we do the same if the current distance corresponds to a position in the first component Region. */ } else { x0 = dist[ i ]*dtot; x = x0; rval = this->rvals[ 0 ]; off = this->offs[ 0 ]; for( j = 0; j < this->nbreak[ 0 ]; j++,rval++,off++ ) { if( *rval >= x0 ) break; x += *off; } r1d[ r1n++ ] = x/this->dtot[ 0 ]; } } } /* Allocate memory to hold the axis values at the corresponding positions in the first component Region. */ r1ptr[ 0 ] = astMalloc( sizeof( double )*r1n ); r1ptr[ 1 ] = astMalloc( sizeof( double )*r1n ); /* Allocate memory to hold the axis values at the corresponding positions in the second component Region. */ r2ptr[ 0 ] = astMalloc( sizeof( double )*r2n ); r2ptr[ 1 ] = astMalloc( sizeof( double )*r2n ); /* Check the pointers can be used safely. */ if( astOK ) { /* Find the axis values at each of the required positions that fall in the first component Region. Negate it first if needed to ensure the Region is bounded (not guaranteed, but likely). */ if( astGetBounded( this->region1 ) ) { (void) astRegTrace( this->region1, r1n, r1d, r1ptr ); } else { AstRegion *negation = astGetNegation( this->region1 ); (void) astRegTrace( negation, r1n, r1d, r1ptr ); negation = astAnnul( negation ); } /* Do the same for the second component Region. */ if( astGetBounded( this->region2 ) ) { (void) astRegTrace( this->region2, r2n, r2d, r2ptr ); } else { AstRegion *negation = astGetNegation( this->region2 ); (void) astRegTrace( negation, r2n, r2d, r2ptr ); negation = astAnnul( negation ); } /* The arrays of positions returned by the above calls to astRegTrace may include points that should not be there (e.g. points on the boundary of one component region that should have been blanked due to being inside the second component region - if the regions are ORed together). This is a consequence of the relatively low value of the "NP" local constant in function SetBreakInfo. So we now refine the positions to exclude any such unwanted positions. If the two component Regions are ANDed together, we want to remove the positions from the boundary of the required component Region that fall outside the other region. We can do this by simply using the other Region as a Mapping. If the two component Regions are ORed together, we want to remove the position that fall within (rather than outside) the other Region. To do this we need to negate the other region first. */ if( this->oper == AST__OR ) { ureg1 = astGetNegation( this->region1 ); ureg2 = astGetNegation( this->region2 ); } else { ureg1 = astClone( this->region1 ); ureg2 = astClone( this->region2 ); } /* Now transform the points on the boundary of the first Region in order to set invalid those positions which are not on the boundary of the supplied CmpRegion. */ if( r1n > 0 ) { r1pset = astPointSet( r1n, 2, " ", status ); astSetPoints( r1pset, r1ptr ); r1psetb = astTransform( ureg2, r1pset, 1, NULL ); r1ptrb = astGetPoints( r1psetb ); } else { r1pset = NULL; r1psetb = NULL; r1ptrb = NULL; } /* Now transform the points on the boundary of the second Region in order to set invalid those positions which are not on the boundary of the supplied CmpRegion. */ if( r2n > 0 ) { r2pset = astPointSet( r2n, 2, " ", status ); astSetPoints( r2pset, r2ptr ); r2psetb = astTransform( ureg1, r2pset, 1, NULL ); r2ptrb = astGetPoints( r2psetb ); } else { r2pset = NULL; r2psetb = NULL; r2ptrb = NULL; } /* Free the begation pointers. */ ureg1 = astAnnul( ureg1 ); ureg2 = astAnnul( ureg2 ); /* Check pointer can be used safely. */ if( astOK ) { /* Copy the boundary positions from each component Region into a single PointSet. These positions are in the base Frame of the CmpRegion. */ r1n = 0; r2n = 0; for( i = 0; i < n; i++ ) { if( dist[ i ] > dbreak ) { bptr[ 0 ][ i ] = r2ptrb[ 0 ][ r2n ]; bptr[ 1 ][ i ] = r2ptrb[ 1 ][ r2n++ ]; } else { bptr[ 0 ][ i ] = r1ptrb[ 0 ][ r1n ]; bptr[ 1 ][ i ] = r1ptrb[ 1 ][ r1n++ ]; } } } /* Free resources. */ if( r1pset ) r1pset = astAnnul( r1pset ); if( r2pset ) r2pset = astAnnul( r2pset ); if( r1psetb ) r1psetb = astAnnul( r1psetb ); if( r2psetb ) r2psetb = astAnnul( r2psetb ); } /* If required, transform the base frame positions into the current Frame of the CmpRegion, storing them in the supplied array. Then free resources. */ if( bpset ) { cpset = astPointSet( n, ncur, " ", status ); astSetPoints( cpset, ptr ); (void) astTransform( map, bpset, 1, cpset ); cpset = astAnnul( cpset ); bpset = astAnnul( bpset ); } /* Free remaining resources. */ map = astAnnul( map ); } frm = astAnnul( frm ); /* Return the result. */ return result; } static void RegClearAttrib( AstRegion *this_region, const char *attrib, char **base_attrib, int *status ) { /* * Name: * RegClearAttrib * Purpose: * Clear an attribute value for a Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void RegClearAttrib( AstRegion *this, const char *attrib, * char **base_attrib, int *status ) * Class Membership: * CmpRegion member function (over-rides the astRegClearAttrib method * inherited from the Region class). * Description: * This function clears the value of a named attribute in both the base * and current Frame in the FrameSet encapsulated within a Region, without * remapping either Frame. * * No error is reported if the attribute is not recognised by the base * Frame. * Parameters: * this * Pointer to the Region. * attrib * Pointer to a null terminated string holding the attribute name. * NOTE, IT SHOULD BE ENTIRELY LOWER CASE. * base_attrib * Address of a location at which to return a pointer to the null * terminated string holding the attribute name which was cleared in * the base Frame of the encapsulated FrameSet. This may differ from * the supplied attribute if the supplied attribute contains an axis * index and the current->base Mapping in the FrameSet produces an * axis permutation. The returned pointer should be freed using * astFree when no longer needed. A NULL pointer may be supplied in * which case no pointer is returned. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstCmpRegion *this; char *batt; int rep; /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Use the RegClearAttrib method inherited from the parent class to clear the attribute in the current and base Frames in the FrameSet encapsulated by the parent Region structure. */ (*parent_regclearattrib)( this_region, attrib, &batt, status ); /* Now clear the base Frame attribute to the component Regions (the current Frame within the component Regions is equivalent to the base Frame in the parent Region structure). Annul any "attribute unknown" error that results from attempting to do this. */ if( astOK ) { rep = astReporting( 0 ); astRegClearAttrib( this->region1, batt, NULL ); astRegClearAttrib( this->region2, batt, NULL ); if( astStatus == AST__BADAT ) astClearStatus; astReporting( rep ); } /* If required, return the base Frame attribute name, otherwise free it. */ if( base_attrib ) { *base_attrib = batt; } else { batt = astFree( batt ); } } static void ResetCache( AstRegion *this_region, int *status ){ /* * Name: * ResetCache * Purpose: * Clear cached information within the supplied Region. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void ResetCache( AstRegion *this, int *status ) * Class Membership: * Region member function (overrides the astResetCache method * inherited from the parent Region class). * Description: * This function clears cached information from the supplied Region * structure. * Parameters: * this * Pointer to the Region. * status * Pointer to the inherited status variable. */ /* Local Variables *: */ AstCmpRegion *this; int i; /* Check a Region was supplied. */ if( this_region ) { /* Get a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_region; /* Clear information cached in the CmpRegion structure. */ for( i = 0; i < 2; i++ ) { this->rvals[ i ] = astFree( this->rvals[ i ] ); this->offs[ i ] = astFree( this->offs[ i ] ); this->nbreak[ i ] = 0; this->d0[ i ] = AST__BAD; this->dtot[ i ] = AST__BAD; } this->bounded = -INT_MAX; /* Clear information cached in the component regions. */ if( this->region1 ) astResetCache( this->region1 ); if( this->region2 ) astResetCache( this->region2 ); /* Clear information cached in the parent Region structure. */ (*parent_resetcache)( this_region, status ); } } static void SetBreakInfo( AstCmpRegion *this, int comp, int *status ){ /* * Name: * SetBreakInfo * Purpose: * Ensure that a CmpRegion has information about the breaks in the * boundaries of one of the two component Regions. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void SetBreakInfo( AstCmpRegion *this, int comp, int *status ) * Class Membership: * CmpRegion method. * Description: * This function returns without action if the supplied CmpRegion * already contains break information for the specified component Region. * Otherwise, it creates the required information and stores it in the * CmpRegion. * * Each component Region in the CmpRegion has a boundary. But in * general only part of the boundary of a component Region will also * be included in the CmpRegion boundary. Thus the component Region * boundary can be broken up into sections; sections that form part * of the CmpRegion boundary, and sections that do not. This function * stores information about the breaks between these sections. * * The complete boundary of a component Region is parameterised by a * geodesic distance that goes from 0.0 to the value found by this * function and stored in this->dtot (the total geodesic distance * around the border). This function find the ranges of this parameter * that correspond to the sections of the boundary that are also on the * CmpRegion boundary, and thus finds the total length that the component * boundary contributes to the CmpRegion boundary. This length is stored * in "this->d0" (a two element array, one for each component Region). * * It also find two arrays "this->rvals" and "this->offs" that allow a * distance value in the range 0.0 to "this->d0" (i.e. a distance * measured by skipping over the parts of the component boundary that * are not on the CmpRegion boundary), to be converted into the * corresponding distance value in the range 0.0 to "this->dtot" (i.e. a * distance measured round the complete component boundary, including the * parts not on the CmpRegion boundary). * Parameters: * this * Pointer to a CmpRegion. * comp * Zero or one, indicating which component Region is to be checked. * status * Pointer to the inherited status variable. */ /* The number of points to be spread evenly over the entire boundary of the component Region. */ #define NP 101 /* Local Variables: */ AstFrame *frm; AstPointSet *pset1; AstPointSet *pset2; AstRegion *other; AstRegion *reg; AstRegion *uother; double **ptr2; double **ptr1; double *d; double *offs; double *p0; double *p1; double *p; double *q; double *rvals; double delta; double dist; double pnt1[ 2 ]; double pnt2[ 2 ]; double rbad; double rval; double totdist; int i; int j; int nn; int prevgood; /* Check inherited status */ if( !astOK ) return; /* If the information describing breaks in the component boundary has not yet been set up, do so now. */ if( this->d0[ comp ] == AST__BAD ) { /* Get a pointer to the component Region for which break information is required. */ reg = comp ? this->region2 : this->region1; /* Check the component class implements the astRegTrace method. */ if( astRegTrace( reg, 0, NULL, NULL ) ) { /* Create a pointSet to hold axis values at evenly spaced positions along the entire boundary of the selected component region. */ pset1 = astPointSet( NP, 2, " ", status ); ptr1 = astGetPoints( pset1 ); /* Allocate memory to hold an array of corresponding scalar distances around the boundary. */ d = astMalloc( NP*sizeof( double ) ); /* Check pointers can be used safely. */ if( astOK ) { /* Get the distance increment between points (at this point the distances are normalised so that the entire boundary has unit length, as required by astRegTrace). */ delta = 1.0/( NP - 1 ); /* Set up the array of evenly spaced distances around the boundary of the component region. */ for( i = 0; i < NP; i++ ) d[ i ] = i*delta; /* Get the corresponding Frame positions. If the Region is unbounded (e.g. a negated circle, etc), then negate it first in the hope that this may produced a bounded Region. */ if( astGetBounded( reg ) ) { (void) astRegTrace( reg, NP, d, ptr1 ); } else { AstRegion *negation = astGetNegation( reg ); (void) astRegTrace( negation, NP, d, ptr1 ); negation = astAnnul( negation ); } /* Get a pointer to the other component Region. */ other = comp ? this->region1 : this->region2; /* If the two component Regions are ANDed together, we want to remove the positions from the boundary of the required component Region that fall outside the other region. We can do this by simply using the other Region as a Mapping. If the two component Regions are ORed together, we want to remove the position that fall within (rather than outside) the other Region. To do this we need to negate the other region first. */ if( this->oper == AST__OR ) { uother = astGetNegation( other ); } else { uother = astClone( other ); } /* Now transform the points on the boundary of the selected Region in order to set invalid those positions which are not on the boundary of the supplied CmpRegion. */ pset2 = astTransform( uother, pset1, 1, NULL ); /* Annul the negation pointer */ uother = astAnnul( uother ); /* Modify the distance array by setting invalid each element that is not on the boundary of the CmpRegion. */ ptr2 = astGetPoints( pset2 ); if( astOK ) { p = ptr2[ 0 ]; q = ptr2[ 1 ]; for( i = 0; i < NP; i++,p++,q++ ) { if( *p == AST__BAD || *q == AST__BAD ) d[ i ] = AST__BAD; } /* At each good/bad junction in this list, extend the good section by one point. This ensures that the good sections of the curve do in fact touch each other (they may in fact overlap a little but that does not matter). */ prevgood = ( d[ 0 ] != AST__BAD ); for( i = 1; i < NP; i++,p++,q++ ) { if( d[ i ] == AST__BAD ) { if( prevgood ) d[ i ] = i*delta; prevgood = 0; } else { if( !prevgood ) d[ i - 1 ] = ( i - 1 )*delta; prevgood = 1; } } /* Find the total geodesic distance around the border. This is only an approximation but it is only used to give a relative weight to this component within the CmpFrame, and so does not need to be very accurate. */ frm = astGetFrame( reg->frameset, AST__CURRENT ); p0 = ptr1[ 0 ]; p1 = ptr1[ 1 ]; totdist = 0; pnt1[ 0 ] = *(p0++); pnt1[ 1 ] = *(p1++); for( i = 1; i < NP; i++ ) { pnt2[ 0 ] = *(p0++); pnt2[ 1 ] = *(p1++); dist = astDistance( frm, pnt1, pnt2 ); if( dist != AST__BAD ) totdist += dist; pnt1[ 0 ] = pnt2[ 0 ]; pnt1[ 1 ] = pnt2[ 1 ]; } /* Change delta so that it represents a geodesic distance, rather than a normalised distance in the range zero to one. Working in geodesic distance (e.g. Radians on a SkyFrame) prevents Regions higher up in a complex nested CmpRegion being given higher priority than a lower Region. */ delta *= totdist; /* Now create two arrays - "rvals" holds the distance travelled around the used parts of the border at which breaks occur, "offs" holds the jump in distance around the complete border at each break. The distance around the complete border is normalised to the range [0.0,1.0]. Therefore the total distance around the used parts of the border will in general be less than 1.0 */ if( d[ 0 ] == AST__BAD ) { nn = 1; j = 0; rvals = astMalloc( sizeof( double ) ); offs = astMalloc( sizeof( double ) ); if( astOK ) rvals[ 0 ] = -0.5*delta; rbad = 0.5; prevgood = 0; rval = -0.5*delta; } else { nn = 0; rvals = NULL; offs = NULL; prevgood = 1; rbad = 0.0; rval = 0.0; } for( i = 1; i < NP; i++,p++,q++ ) { if( d[ i ] == AST__BAD ) { if( prevgood ) { j = nn++; rvals = astGrow( rvals, nn, sizeof( double ) ); offs = astGrow( offs, nn, sizeof( double ) ); if( astOK ) { rvals[ j ] = rval + 0.5*delta; rbad = 0.0; } else { break; } prevgood = 0; } rbad += 1.0; } else { if( !prevgood ) { offs[ j ] = rbad*delta; prevgood = 1; } rval += delta; } } if( !prevgood ) { rval += 0.5*delta; offs[ j ] = rbad*delta; } /* Record the information in the CmpRegion structure. */ this->rvals[ comp ] = rvals; this->offs[ comp ] = offs; this->nbreak[ comp ] = nn; this->d0[ comp ] = rval; this->dtot[ comp ] = totdist; } /* Free resources. */ pset2 = astAnnul( pset2 ); } pset1 = astAnnul( pset1 ); d = astFree( d ); } } } #undef NP static void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) { /* * Name: * SetRegFS * Purpose: * Stores a new FrameSet in a Region * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void SetRegFS( AstRegion *this_region, AstFrame *frm, int *status ) * Class Membership: * CmpRegion method (over-rides the astSetRegFS method inherited from * the Region class). * Description: * This function creates a new FrameSet and stores it in the supplied * Region. The new FrameSet contains two copies of the supplied * Frame, connected by a UnitMap. * Parameters: * this * Pointer to the Region. * frm * The Frame to use. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRegion *creg; /* Pointer to component Region structure */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the parent method to store the FrameSet in the parent Region structure. */ (* parent_setregfs)( this_region, frm, status ); /* If either component Region has a dummy FrameSet use this method recursively to give them the same FrameSet. */ creg = ((AstCmpRegion *) this_region )->region1; if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm ); creg = ((AstCmpRegion *) this_region )->region2; if( creg && !astGetRegionFS( creg ) ) astSetRegFS( creg, frm ); } static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { /* * Name: * Simplify * Purpose: * Simplify a Region. * Type: * Private function. * Synopsis: * #include "region.h" * AstMapping *Simplify( AstMapping *this, int *status ) * Class Membership: * CmpRegion method (over-rides the astSimplify method inherited from * the Region class). * Description: * This function simplifies a CmpRegion to eliminate redundant * computational steps, or to merge separate steps which can be * performed more efficiently in a single operation. * Parameters: * this * Pointer to the original Region. * status * Pointer to the inherited status variable. * Returned Value: * A new pointer to the (possibly simplified) Region. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the AST error status set, or if it should fail for * any reason. * Deficiencies: * - Currently, this function does not attempt to map the component * Regions into the current Frame of the parent Region structure. * Both components should be mapped into the current Frame, and if the * resulting base->current Mappings in *both* remapped component Regions are * UnitMaps, then a new CmpRegion should be created from the re-mapped * Regions. */ /* Local Variables: */ AstCmpRegion *newb; /* New CmpRegion defined in base Frame */ AstCmpRegion *newc; /* New CmpRegion defined in current Frame */ AstFrame *frm; /* Current Frame */ AstMapping *map; /* Base->current Mapping */ AstMapping *result; /* Result pointer to return */ AstRegion *csreg1; /* Copy of simplified first component Region */ AstRegion *csreg2; /* Copy of simplified second component Region */ AstRegion *nullreg; /* Null or infinfite Region */ AstRegion *othereg; /* Non-Null and non-infinfite Region */ AstRegion *reg1; /* First component Region */ AstRegion *reg2; /* Second component Region */ AstRegion *sreg1; /* Simplified first component Region */ AstRegion *sreg2; /* Simplified second component Region */ int neg1; /* Negated flag to use with first component */ int neg2; /* Negated flag to use with second component */ int oper; /* Boolean operator used to combine components */ int overlap; /* Nature of overlap between components */ int simpler; /* Has any simplification taken place? */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the parent Simplify method inherited from the Region class. This will simplify the encapsulated FrameSet and uncertainty Region. The returned pointer identifies a region within the current Frame of the FrameSet encapsulated by the parent Region structure. Note this by storing the pointer in the "newc" ("c" for "current") variable. */ newc = (AstCmpRegion *) (*parent_simplify)( this_mapping, status ); /* Note if any simplification took place. This is assumed to be the case if the pointer returned by the above call is different to the supplied pointer. */ simpler = ( (AstMapping *) newc != this_mapping ); /* Below we may create a new simplified region which identifies a region within the base Frame of the FrameSet encapsulated by the parent Region structure. Such a result will need to be mapped into the current Frame before being returned. The "newb" variable ("b" for "base") will be used to store a pointer to such a result. Initialise this variable to indicate that we do not yet have a base Frame result. */ newb = NULL; /* Get the component Regions, how they should be combined, and the Negated values which should be used with them. The returned values take account of whether the supplied CmpRegion has itself been Negated or not. The returned Regions represent regions within the base Frame of the FrameSet encapsulated by the parent Region structure. */ GetRegions( newc, ®1, ®2, &oper, &neg1, &neg2, status ); /* If the first component Region does not have the required value for its "Negated" attribute, use the negation of "reg1" in place of "reg1" itself. */ if( neg1 != astGetNegated( reg1 ) ) { AstRegion *tmp = astGetNegation( reg1 ); (void) astAnnul( reg1 ); reg1 = tmp; } /* If the second component Region does not have the required value for its "Negated" attribute, use the negation of "reg2" in place of "reg2" itself. */ if( neg2 != astGetNegated( reg2 ) ) { AstRegion *tmp = astGetNegation( reg2 ); (void) astAnnul( reg2 ); reg2 = tmp; } /* Simplify each of the two components. */ sreg1 = astSimplify( reg1 ); sreg2 = astSimplify( reg2 ); /* Note if any simplification took place. */ simpler = simpler || ( sreg1 != reg1 || sreg2 != reg2 ); /* If either component is null or infinite we can exclude it from the returned Region. */ if( astIsANullRegion( sreg1 ) || astIsANullRegion( sreg2 ) ) { /* Get a pointer to the non-null Region. The following is still valid even if both regions are null or infinite. */ if( astIsANullRegion( sreg1 ) ){ nullreg = sreg1; othereg = sreg2; } else { nullreg = sreg2; othereg = sreg1; } /* If null.. */ if( !astGetNegated( nullreg ) ){ if( oper == AST__AND ) { newb = (AstCmpRegion *) astNullRegion( othereg, astGetUnc( othereg, 0 ), "", status ); } else if( oper == AST__OR ) { newb = astCopy( othereg ); } else { astError( AST__INTER, "astSimplify(%s): The %s refers to an " "unknown boolean operator with identifier %d (internal " "AST programming error).", status, astGetClass( newc ), astGetClass( newc ), oper ); } /* If infinite.. */ } else { if( oper == AST__AND ) { newb = astCopy( othereg ); } else if( oper == AST__OR ) { newb = (AstCmpRegion *) astNullRegion( othereg, astGetUnc( othereg, 0 ), "negated=1", status ); } else { astError( AST__INTER, "astSimplify(%s): The %s refers to an " "unknown boolean operator with identifier %d (internal " "AST programming error).", status, astGetClass( newc ), astGetClass( newc ), oper ); } } /* Flag that we have done some simplication.*/ simpler = 1; /* If neither component is null or infinite, see if it is possible to remove one or both of the components on the basis of the overlap between them. */ } else { overlap = astOverlap( sreg1, sreg2 ); /* If the components have no overlap, and they are combined using AND, then the CmpRegion is null. */ if( ( overlap == 1 || overlap == 6 ) && oper == AST__AND ) { newb = (AstCmpRegion *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ), "", status ); simpler = 1; /* If one component is the negation of the other component, and they are combined using OR, then the CmpRegion is infinite. This is represented by a negated null region.*/ } else if( overlap == 6 && oper == AST__OR ) { newb = (AstCmpRegion *) astNullRegion( sreg1, astGetUnc( sreg1, 0 ), "negated=1", status ); simpler = 1; /* If the two components are identical... */ } else if( overlap == 5 ) { simpler = 1; /* If combined with AND or OR, the CmpRegion can be replaced by the first (or second) component Region. */ if( oper == AST__AND || oper == AST__OR ) { newb = astCopy( sreg1 ); } else { astError( AST__INTER, "astSimplify(%s): The %s refers to an " "unknown boolean operator with identifier %d (internal " "AST programming error).", status, astGetClass( newc ), astGetClass( newc ), oper ); } /* If the first component is entirely contained within the second component, and they are combined using AND or OR, then the CmpRegion can be replaced by the first or second component. */ } else if( overlap == 2 && ( oper == AST__AND || oper == AST__OR ) ){ newb = astCopy( ( oper == AST__AND ) ? sreg1 : sreg2 ); simpler = 1; /* If the second component is entirely contained within the first component, and they are combined using AND or OR, then the CmpRegion can be replaced by the second or first component. */ } else if( overlap == 3 && ( oper == AST__AND || oper == AST__OR ) ){ newb = astCopy( ( oper == AST__AND ) ? sreg2 : sreg1 ); simpler = 1; /* Otherwise, no further simplication is possible, so either create a new CmpRegion or leave the "newb" pointer NULL (which will cause "newc" to be used), depending on whether the components were simplified. */ } else if( simpler ){ csreg1 = astCopy( sreg1 ); csreg2 = astCopy( sreg2 ); newb = astCmpRegion( csreg1, csreg2, oper, "", status ); csreg1 = astAnnul( csreg1 ); csreg2 = astAnnul( csreg2 ); } } /* If any simplification took place, decide whether to use the "newc" or "newb" pointer for the returned Mapping. If "newb" is non-NULL we use it, otherwise we use "newc". If "newb" is used we must first map the result Region from the base Frame of the FrameSet encapsulated by the parent Region structure, to the current Frame. */ if( simpler ) { if( newb ){ frm = astGetFrame( ((AstRegion *) newc)->frameset, AST__CURRENT ); map = astGetMapping( ((AstRegion *) newc)->frameset, AST__BASE, AST__CURRENT ); result = astMapRegion( newb, map, frm ); frm = astAnnul( frm ); map = astAnnul( map ); newb = astAnnul( newb ); } else { result = astClone( newc ); } /* If no simplification took place, return a clone of the supplied pointer. */ } else { result = astClone( this_mapping ); } /* Free resources. */ reg1 = astAnnul( reg1 ); reg2 = astAnnul( reg2 ); sreg1 = astAnnul( sreg1 ); sreg2 = astAnnul( sreg2 ); newc = astAnnul( newc ); /* If an error occurred, annul the returned Mapping. */ if ( !astOK ) result = astAnnul( result ); /* Return the result. */ return result; } static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a CmpRegion to transform a set of points. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status ) * Class Membership: * CmpRegion member function (over-rides the astTransform method inherited * from the Region class). * Description: * This function takes a CmpRegion and a set of points encapsulated in a * PointSet and transforms the points so as to apply the required Region. * This implies applying each of the CmpRegion's component Regions in turn, * either in series or in parallel. * Parameters: * this * Pointer to the CmpRegion. * in * Pointer to the PointSet associated with the input coordinate values. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the CmpRegion being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ AstPointSet *ps1; /* Pointer to PointSet for first component */ AstPointSet *ps2; /* Pointer to PointSet for second component */ AstPointSet *pset_tmp; /* Pointer to PointSet holding base Frame positions*/ AstPointSet *result; /* Pointer to output PointSet */ AstRegion *reg1; /* Pointer to first component Region */ AstRegion *reg2; /* Pointer to second component Region */ double **ptr1; /* Pointer to first component axis values */ double **ptr2; /* Pointer to second component axis values */ double **ptr_out; /* Pointer to output coordinate data */ int coord; /* Zero-based index for coordinates */ int good; /* Is the point inside the CmpRegion? */ int ncoord_out; /* No. of coordinates per output point */ int ncoord_tmp; /* No. of coordinates per base Frame point */ int neg1; /* Negated value for first component Region */ int neg2; /* Negated value for second component Region */ int npoint; /* No. of points */ int oper; /* Boolean operator to use */ int point; /* Loop counter for points */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a Pointer to the CmpRegion structure */ this = (AstCmpRegion *) this_mapping; /* Get the component Regions, how they should be combined, and the Negated values which should be used with them. The returned values take account of whether the supplied CmpRegion has itself been Negated or not. The returned Regions represent regions within the base Frame of the FrameSet encapsulated by the parent Region structure. */ GetRegions( this, ®1, ®2, &oper, &neg1, &neg2, status ); /* If the first component Region does not have the required value for its "Negated" attribute, use the negation of "reg1" in place of "reg1" itself. */ if( neg1 != astGetNegated( reg1 ) ) { AstRegion *tmp = astGetNegation( reg1 ); (void) astAnnul( reg1 ); reg1 = tmp; } /* If the second component Region does not have the required value for its "Negated" attribute, use the negation of "reg2" in place of "reg2" itself. */ if( neg2 != astGetNegated( reg2 ) ) { AstRegion *tmp = astGetNegation( reg2 ); (void) astAnnul( reg2 ); reg2 = tmp; } /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Region class. This function validates all arguments and generates an output PointSet if necessary, containing a copy of the input PointSet. */ result = (*parent_transform)( this_mapping, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* First use the encapsulated FrameSet in the parent Region structure to transform the supplied positions from the current Frame in the encapsulated FrameSet (the Frame represented by the CmpRegion), to the base Frame (the Frame in which the component Regions are defined). Note, the returned pointer may be a clone of the "in" pointer, and so we must be carefull not to modify the contents of the returned PointSet. */ pset_tmp = astRegTransform( this, in, 0, NULL, NULL ); /* Now transform this PointSet using each of the two component Regions in turn. */ ps1 = astTransform( reg1, pset_tmp, 0, NULL ); ps2 = astTransform( reg2, pset_tmp, 0, NULL ); /* Determine the numbers of points and coordinates per point for these base Frame PointSets and obtain pointers for accessing the base Frame and output coordinate values. */ npoint = astGetNpoint( pset_tmp ); ncoord_tmp = astGetNcoord( pset_tmp ); ptr1 = astGetPoints( ps1 ); ptr2 = astGetPoints( ps2 ); ncoord_out = astGetNcoord( result ); ptr_out = astGetPoints( result ); /* Perform coordinate arithmetic. */ /* ------------------------------ */ if ( astOK ) { /* First deal with ANDed Regions */ if( oper == AST__AND ) { for ( point = 0; point < npoint; point++ ) { good = 0; for ( coord = 0; coord < ncoord_tmp; coord++ ) { if( ptr1[ coord ][ point ] != AST__BAD && ptr2[ coord ][ point ] != AST__BAD ) { good = 1; break; } } if( !good ) { for ( coord = 0; coord < ncoord_out; coord++ ) { ptr_out[ coord ][ point ] = AST__BAD; } } } /* Now deal with ORed Regions */ } else if( oper == AST__OR ) { for ( point = 0; point < npoint; point++ ) { good = 0; for ( coord = 0; coord < ncoord_tmp; coord++ ) { if( ptr1[ coord ][ point ] != AST__BAD || ptr2[ coord ][ point ] != AST__BAD ) { good = 1; break; } } if( !good ) { for ( coord = 0; coord < ncoord_out; coord++ ) { ptr_out[ coord ][ point ] = AST__BAD; } } } /* Report error for any unknown operator. */ } else if( astOK ) { astError( AST__INTER, "astTransform(%s): The %s refers to an unknown " "boolean operator with identifier %d (internal AST " "programming error).", status, astGetClass( this ), astGetClass( this ), oper ); } } /* Free resources. */ reg1 = astAnnul( reg1 ); reg2 = astAnnul( reg2 ); ps1 = astAnnul( ps1 ); ps2 = astAnnul( ps2 ); pset_tmp = astAnnul( pset_tmp ); /* If an error occurred, clean up by deleting the output PointSet (if allocated by this function) and setting a NULL result pointer. */ if ( !astOK ) { if ( !out ) result = astDelete( result ); result = NULL; } /* Return a pointer to the output PointSet. */ return result; } static void XORCheck( AstCmpRegion *this, int *status ) { /* * Name: * XORCheck * Purpose: * Check if the supplied CmpRegion represents an XOR operation. * Type: * Private function. * Synopsis: * #include "cmpregion.h" * void XORCheck( AstCmpRegion *this, int *status ) * Class Membership: * CmpRegion method * Decription: * This function analyses the component Regions within the supplied * CmpRegion to see if the CmpRegion is equivalent to an XOR operation * on two other Regions. If it is, teh Regions that are XORed are * stored in the supplied CmpRegion. * Parameters: * this * Pointer to the CmpRegion. */ /* Local Variables: */ AstCmpRegion *cmpreg1; AstCmpRegion *cmpreg2; int xor; /* Check the global error status. */ if ( !astOK ) return; /* If the CmpRegion is already known to be an XOR operation, return without action. */ if( this->xor1 ) return; /* To be equivalent to an XOR operation, the supplied CmpRegion must be an OR operation and each component Region must be a CmpRegion. */ if( this->oper == AST__OR && astIsACmpRegion( this->region1 ) && astIsACmpRegion( this->region2 ) ) { cmpreg1 = (AstCmpRegion *) this->region1; cmpreg2 = (AstCmpRegion *) this->region2; /* Each component CmpRegion must be an AND operation. */ if( cmpreg1->oper == AST__AND && cmpreg2->oper == AST__AND ) { /* Temporarily negate the first component of the first CmpRegion. */ astNegate( cmpreg1->region1 ); /* Initially, assume the supplied CmpRegion is not equivalent to an XOR operation. */ xor = 0; /* This negated region must be equal to one of the two component Regions in the second component CmpRegion. Check the first. */ if( astEqual( cmpreg1->region1, cmpreg2->region1 ) ) { /* We now check that the other two Regions are equal (after negating the first). If so, set "xor" non-zero. */ astNegate( cmpreg1->region2 ); if( astEqual( cmpreg1->region2, cmpreg2->region2 ) ) xor = 1; astNegate( cmpreg1->region2 ); /* Do equiovalent checks the other way round. */ } else if( astEqual( cmpreg1->region1, cmpreg2->region2 ) ) { astNegate( cmpreg1->region2 ); if( astEqual( cmpreg1->region2, cmpreg2->region1 ) ) xor = 1; astNegate( cmpreg1->region2 ); } /* Re-instate the original state of the Negated attribute in the first component of the first CmpRegion. */ astNegate( cmpreg1->region1 ); /* If the supplied CmpRegion is equivalent to an XOR operation, store copies of the components in the supplied CmpRegion. */ if( xor ) { this->xor1 = astCopy( cmpreg1->region1 ); this->xor2 = astCopy( cmpreg1->region2 ); /* We need to negate one of these two Region (it doesn't matter which), and we choose to negate which ever of them is already negated (so that it becomes un-negated). */ if( astGetNegated( this->xor1 ) ) { astNegate( this->xor1 ); } else { astNegate( this->xor2 ); } } } } } /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for CmpRegion objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for CmpRegion objects. * Parameters: * objin * Pointer to the object to be copied. * objout * Pointer to the object being constructed. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * - This constructor makes a deep copy, including a copy of the component * Regions within the CmpRegion. */ /* Local Variables: */ AstCmpRegion *in; /* Pointer to input CmpRegion */ AstCmpRegion *out; /* Pointer to output CmpRegion */ int i; /* Loop count */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain pointers to the input and output CmpRegions. */ in = (AstCmpRegion *) objin; out = (AstCmpRegion *) objout; /* For safety, start by clearing any memory references in the output Region that were copied from the input Region. */ out->region1 = NULL; out->region2 = NULL; out->xor1 = NULL; out->xor2 = NULL; for( i = 0; i < 2; i++ ) { out->rvals[ i ] = NULL; out->offs[ i ] = NULL; } /* Make copies of these Regions and store pointers to them in the output CmpRegion structure. */ out->region1 = astCopy( in->region1 ); out->region2 = astCopy( in->region2 ); if( in->xor1 ) out->xor1 = astCopy( in->xor1 ); if( in->xor2 ) out->xor2 = astCopy( in->xor2 ); /* Copy cached arrays. */ for( i = 0; i < 2; i++ ) { out->rvals[ i ] = astStore( NULL, in->rvals[ i ], in->nbreak[ i ]*sizeof( **in->rvals ) ); out->offs[ i ] = astStore( NULL, in->offs[ i ], in->nbreak[ i ]*sizeof( **in->offs ) ); } } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for CmpRegion objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for CmpRegion objects. * Parameters: * obj * Pointer to the object to be deleted. * status * Pointer to the inherited status variable. * Returned Value: * void * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstCmpRegion *this; /* Pointer to CmpRegion */ int i; /* Obtain a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) obj; /* Free arrays holding cached information. */ for( i = 0; i < 2; i++ ) { this->rvals[ i ] = astFree( this->rvals[ i ] ); this->offs[ i ] = astFree( this->offs[ i ] ); } /* Annul the pointers to the component Regions. */ this->region1 = astAnnul( this->region1 ); this->region2 = astAnnul( this->region2 ); if( this->xor1 ) this->xor1 = astAnnul( this->xor1 ); if( this->xor2 ) this->xor2 = astAnnul( this->xor2 ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for CmpRegion objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the CmpRegion class to an output Channel. * Parameters: * this * Pointer to the CmpRegion whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstRegion *reg1; /* First Region to include in dump */ AstRegion *reg2; /* Second Region to include in dump */ AstCmpRegion *this; /* Pointer to the CmpRegion structure */ const char *comment; /* Pointer to comment string */ int ival; /* Integer value */ int oper; /* The operator to include in the dump */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the CmpRegion structure. */ this = (AstCmpRegion *) this_object; /* Check if this CmpRegion has an equivalent XOR representation. Is so, store details of the XOR representation in the CmpRegion. */ XORCheck( this, status ); /* Choose the operator and component regions to include in the dump. If the CmpRegion originally used an XOR operator, then save the XORed regions. Otherwise, store the real component Regions. */ if( this->xor1 ) { oper = AST__XOR; reg1 = this->xor1; reg2 = this->xor2; } else { oper = this->oper; reg1 = this->region1; reg2 = this->region2; } /* Write out values representing the instance variables for the CmpRegion class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* Oper */ /* ------- */ ival = oper; if( ival == AST__AND ) { comment = "Regions combined using Boolean AND"; } else if( ival == AST__OR ) { comment = "Regions combined using Boolean OR"; } else if( ival == AST__XOR ) { comment = "Regions combined using Boolean XOR"; } else { comment = "Regions combined using unknown operator"; } astWriteInt( channel, "Operator", 1, 0, ival, comment ); /* First Region. */ /* -------------- */ astWriteObject( channel, "RegionA", 1, 1, reg1, "First component Region" ); /* Second Region. */ /* --------------- */ astWriteObject( channel, "RegionB", 1, 1, reg2, "Second component Region" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsACmpRegion and astCheckCmpRegion functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(CmpRegion,Region) astMAKE_CHECK(CmpRegion) AstCmpRegion *astCmpRegion_( void *region1_void, void *region2_void, int oper, const char *options, int *status, ...) { /* *+ * Name: * astCmpRegion * Purpose: * Create a CmpRegion. * Type: * Protected function. * Synopsis: * #include "cmpregion.h" * AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2, * int oper, const char *options, ..., int *status ) * Class Membership: * CmpRegion constructor. * Description: * This function creates a new CmpRegion and optionally initialises its * attributes. * Parameters: * region1 * Pointer to the first Region. * region2 * Pointer to the second Region. * oper * The boolean operator with which to combine the two Regions. Either * AST__AND or AST__OR. * options * Pointer to a null terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new CmpRegion. The syntax used is the same as for the * astSet method and may include "printf" format specifiers identified * by "%" symbols in the normal way. * status * Pointer to the inherited status variable. * ... * If the "options" string contains "%" format specifiers, then an * optional list of arguments may follow it in order to supply values to * be substituted for these specifiers. The rules for supplying these * are identical to those for the astSet method (and for the C "printf" * function). * Returned Value: * A pointer to the new CmpRegion. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- * Implementation Notes: * - This function implements the basic CmpRegion constructor which is * available via the protected interface to the CmpRegion class. A * public interface is provided by the astCmpRegionId_ function. * - Because this function has a variable argument list, it is * invoked by a macro that evaluates to a function pointer (not a * function invocation) and no checking or casting of arguments is * performed before the function is invoked. Because of this, the * "region1" and "region2" parameters are of type (void *) and are * converted and validated within the function itself. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstCmpRegion *new; /* Pointer to new CmpRegion */ AstRegion *region1; /* Pointer to first Region structure */ AstRegion *region2; /* Pointer to second Region structure */ va_list args; /* Variable argument list */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return new; /* Obtain and validate pointers to the Region structures provided. */ region1 = astCheckRegion( region1_void ); region2 = astCheckRegion( region2_void ); if ( astOK ) { /* Initialise the CmpRegion, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init, &class_vtab, "CmpRegion", region1, region2, oper ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new CmpRegion's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return a pointer to the new CmpRegion. */ return new; } AstCmpRegion *astCmpRegionId_( void *region1_void, void *region2_void, int oper, const char *options, ... ) { /* *++ * Name: c astCmpRegion f AST_CMPREGION * Purpose: * Create a CmpRegion. * Type: * Public function. * Synopsis: c #include "cmpregion.h" c AstCmpRegion *astCmpRegion( AstRegion *region1, AstRegion *region2, c int oper, const char *options, ... ) f RESULT = AST_CMPREGION( REGION1, REGION2, OPER, OPTIONS, STATUS ) * Class Membership: * CmpRegion constructor. * Description: * This function creates a new CmpRegion and optionally initialises * its attributes. * * A CmpRegion is a Region which allows two component * Regions (of any class) to be combined to form a more complex * Region. This combination may be performed a boolean AND, OR * or XOR (exclusive OR) operator. If the AND operator is * used, then a position is inside the CmpRegion only if it is * inside both of its two component Regions. If the OR operator is * used, then a position is inside the CmpRegion if it is inside * either (or both) of its two component Regions. If the XOR operator * is used, then a position is inside the CmpRegion if it is inside * one but not both of its two component Regions. Other operators can * be formed by negating one or both component Regions before using * them to construct a new CmpRegion. * * The two component Region need not refer to the same coordinate * Frame, but it must be possible for the c astConvert f AST_CONVERT * function to determine a Mapping between them (an error will be * reported otherwise when the CmpRegion is created). For instance, * a CmpRegion may combine a Region defined within an ICRS SkyFrame * with a Region defined within a Galactic SkyFrame. This is * acceptable because the SkyFrame class knows how to convert between * these two systems, and consequently the c astConvert f AST_CONVERT * function will also be able to convert between them. In such cases, * the second component Region will be mapped into the coordinate Frame * of the first component Region, and the Frame represented by the * CmpRegion as a whole will be the Frame of the first component Region. * * Since a CmpRegion is itself a Region, it can be used as a * component in forming further CmpRegions. Regions of arbitrary * complexity may be built from simple individual Regions in this * way. * Parameters: c region1 f REGION1 = INTEGER (Given) * Pointer to the first component Region. c region2 f REGION2 = INTEGER (Given) * Pointer to the second component Region. This Region will be * transformed into the coordinate Frame of the first region before * use. An error will be reported if this is not possible. c oper f OPER = INTEGER (Given) * The boolean operator with which to combine the two Regions. This * must be one of the symbolic constants AST__AND, AST__OR or AST__XOR. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new CmpRegion. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new CmpRegion. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astCmpRegion() f AST_CMPREGION = INTEGER * A pointer to the new CmpRegion. * Notes: * - If one of the supplied Regions has an associated uncertainty, * that uncertainty will also be used for the returned CmpRegion. * If both supplied Regions have associated uncertainties, the * uncertainty associated with the first Region will be used for the * returned CmpRegion. * - Deep copies are taken of the supplied Regions. This means that * any subsequent changes made to the component Regions using the * supplied pointers will have no effect on the CmpRegion. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- * Implementation Notes: * - This function implements the external (public) interface to * the astCmpRegion constructor function. It returns an ID value * (instead of a true C pointer) to external users, and must be * provided because astCmpRegion_ has a variable argument list which * cannot be encapsulated in a macro (where this conversion would * otherwise occur). * - Because no checking or casting of arguments is performed * before the function is invoked, the "region1" and "region2" parameters * are of type (void *) and are converted from an ID value to a * pointer and validated within the function itself. * - The variable argument list also prevents this function from * invoking astCmpRegion_ directly, so it must be a re-implementation * of it in all respects, except for the conversions between IDs * and pointers on input/output of Objects. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstCmpRegion *new; /* Pointer to new CmpRegion */ AstRegion *region1; /* Pointer to first Region structure */ AstRegion *region2; /* Pointer to second Region structure */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise. */ new = NULL; /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return new; /* Obtain the Region pointers from the ID's supplied and validate the pointers to ensure they identify valid Regions. */ region1 = astVerifyRegion( astMakePointer( region1_void ) ); region2 = astVerifyRegion( astMakePointer( region2_void ) ); if ( astOK ) { /* Initialise the CmpRegion, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitCmpRegion( NULL, sizeof( AstCmpRegion ), !class_init, &class_vtab, "CmpRegion", region1, region2, oper ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new CmpRegion's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } } /* Return an ID value for the new CmpRegion. */ return astMakeId( new ); } AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init, AstCmpRegionVtab *vtab, const char *name, AstRegion *region1, AstRegion *region2, int oper, int *status ) { /* *+ * Name: * astInitCmpRegion * Purpose: * Initialise a CmpRegion. * Type: * Protected function. * Synopsis: * #include "cmpregion.h" * AstCmpRegion *astInitCmpRegion_( void *mem, size_t size, int init, * AstCmpRegionVtab *vtab, const char *name, * AstRegion *region1, AstRegion *region2, * int oper ) * Class Membership: * CmpRegion initialiser. * Description: * This function is provided for use by class implementations to initialise * a new CmpRegion object. It allocates memory (if necessary) to * accommodate the CmpRegion plus any additional data associated with the * derived class. It then initialises a CmpRegion structure at the start * of this memory. If the "init" flag is set, it also initialises the * contents of a virtual function table for a CmpRegion at the start of * the memory passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the CmpRegion is to be initialised. * This must be of sufficient size to accommodate the CmpRegion data * (sizeof(CmpRegion)) plus any data used by the derived class. If a * value of NULL is given, this function will allocate the memory itself * using the "size" parameter to determine its size. * size * The amount of memory used by the CmpRegion (plus derived class * data). This will be used to allocate memory if a value of NULL is * given for the "mem" parameter. This value is also stored in the * CmpRegion structure, so a valid value must be supplied even if not * required for allocating memory. * init * A logical flag indicating if the CmpRegion's virtual function table * is to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new CmpRegion. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the Object * astClass function). * region1 * Pointer to the first Region. * region2 * Pointer to the second Region. * oper * The boolean operator to use. Must be one of AST__AND, AST__OR or * AST__XOR. * Returned Value: * A pointer to the new CmpRegion. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstCmpRegion *new; /* Pointer to new CmpRegion */ AstFrame *frm; /* Frame encapsulated by first Region */ AstFrameSet *fs; /* FrameSet connecting supplied Regions */ AstMapping *map; /* Mapping between two supplied Regions */ AstMapping *smap; /* Simplified Mapping between two supplied Regions */ AstRegion *new_reg1; /* Replacement for first region */ AstRegion *new_reg2; /* Replacement for second region */ AstRegion *reg1; /* First Region to store in the CmpRegion */ AstRegion *reg2; /* Second Region to store in the CmpRegion */ AstRegion *xor1; /* Copy of first supplied Region or NULL */ AstRegion *xor2; /* Copy of second supplied Region or NULL */ int i; /* Loop count */ int used_oper; /* The boolean operation actually used */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitCmpRegionVtab( vtab, name ); /* Initialise. */ new = NULL; /* Check the supplied oper value. */ if( oper != AST__AND && oper != AST__OR && oper != AST__XOR && astOK ) { astError( AST__INTRD, "astInitCmpRegion(%s): Illegal " "boolean operator value (%d) supplied.", status, name, oper ); } /* Take copies of the supplied Regions. */ reg1 = astCopy( region1 ); reg2 = astCopy( region2 ); /* Get the Mapping from the second to the first Region. */ fs = astConvert( reg2, reg1, "" ); /* Report an error if not possible. */ if( fs == NULL ) { frm = NULL; if( astOK ) astError( AST__INTRD, "astInitCmpRegion(%s): No Mapping can " "be found between the two supplied Regions.", status, name ); /* Otherwise, map the second Region into the Frame of the first (unless they are already in the same Frame). This results in both component Frames having the same current Frame. This current Frame is used as the encapsulated Frame within the parent Region structure. */ } else { frm = astGetFrame( fs, AST__CURRENT ); map = astGetMapping( fs, AST__BASE, AST__CURRENT ); smap = astSimplify( map ); if( !astIsAUnitMap( smap ) ) { new_reg2 = astMapRegion( reg2, smap, frm ); (void) astAnnul( reg2 ); reg2 = new_reg2; } smap = astAnnul( smap ); map = astAnnul( map ); fs = astAnnul( fs ); } /* The CmpRegion class does not implement XOR directly (as it does for AND and OR). Instead, when requested to create an XOR CmpRegion, it creates a CmpRegion that uses AND and OR to simulate XOR. The top level XOR CmpRegion actually uses AST__OR and the two component regions within it are CmpRegions formed by combing the two supplied Regions (one being negated first) using AND. Create the required component Regions. */ if( oper == AST__XOR ) { astNegate( reg1 ); new_reg1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ", status ); astNegate( reg1 ); astNegate( reg2 ); new_reg2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ", status ); astNegate( reg2 ); xor1 = reg1; xor2 = reg2; reg1 = new_reg1; reg2 = new_reg2; used_oper = AST__OR; /* For AND and OR, use the supplied operator. */ } else { xor1 = NULL; xor2 = NULL; used_oper = oper; } /* Initialise a Region structure (the parent class) as the first component within the CmpRegion structure, allocating memory if necessary. A NULL PointSet is suppled as the two component Regions will perform the function of defining the Region shape. The base Frame of the FrameSet in the parent Region structure will be the same as the current Frames of the FrameSets in the two component Regions. */ if ( astOK ) { new = (AstCmpRegion *) astInitRegion( mem, size, 0, (AstRegionVtab *) vtab, name, frm, NULL, NULL ); /* Initialise the CmpRegion data. */ /* --------------------------- */ /* Store pointers to the component Regions. */ new->region1 = astClone( reg1 ); new->region2 = astClone( reg2 ); /* Note the operator used to combine the somponent Regions. */ new->oper = used_oper; /* If we are creating an XOR CmpRegion, save copies of the supplied Regions (i.e. the supplied Regions which are XORed). These will not be the same as "reg1" and "reg2" since each of those two regions will be CmpRegions that combine the supplied Regions using AST__AND. */ if( oper == AST__XOR ) { new->xor1 = xor1; new->xor2 = xor2; } else { new->xor1 = NULL; new->xor2 = NULL; } /* Initialised cached values to show they have not yet been found. */ for( i = 0; i < 2; i++ ) { new->rvals[ i ] = NULL; new->offs[ i ] = NULL; new->nbreak[ i ] = 0; new->d0[ i ] = AST__BAD; new->dtot[ i ] = AST__BAD; } new->bounded = -INT_MAX; /* If the base->current Mapping in the FrameSet within each component Region is a UnitMap, then the FrameSet does not need to be included in the Dump of the new CmpRegion. Set the RegionFS attribute of the component Region to zero to flag this. */ map = astGetMapping( reg1->frameset, AST__BASE, AST__CURRENT ); if( astIsAUnitMap( map ) ) astSetRegionFS( reg1, 0 ); map = astAnnul( map ); map = astGetMapping( reg2->frameset, AST__BASE, AST__CURRENT ); if( astIsAUnitMap( map ) ) astSetRegionFS( reg2, 0 ); map = astAnnul( map ); /* Copy attribute values from the first component Region to the parent Region. */ if( astTestMeshSize( new->region1 ) ) { astSetMeshSize( new, astGetMeshSize( new->region1 ) ); } if( astTestClosed( new->region1 ) ) { astSetClosed( new, astGetClosed( new->region1 ) ); } /* If an error occurred, clean up by annulling the Region pointers and deleting the new object. */ if ( !astOK ) { new->region1 = astAnnul( new->region1 ); new->region2 = astAnnul( new->region2 ); new = astDelete( new ); } } /* Free resources */ reg1 = astAnnul( reg1 ); reg2 = astAnnul( reg2 ); if( frm ) frm = astAnnul( frm ); /* Return a pointer to the new object. */ return new; } AstCmpRegion *astLoadCmpRegion_( void *mem, size_t size, AstCmpRegionVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadCmpRegion * Purpose: * Load a CmpRegion. * Type: * Protected function. * Synopsis: * #include "cmpregion.h" * AstCmpRegion *astLoadCmpRegion( void *mem, size_t size, * AstCmpRegionVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * CmpRegion loader. * Description: * This function is provided to load a new CmpRegion using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * CmpRegion structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a CmpRegion at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the CmpRegion is to be * loaded. This must be of sufficient size to accommodate the * CmpRegion data (sizeof(CmpRegion)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the CmpRegion (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the CmpRegion structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstCmpRegion) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new CmpRegion. If this is NULL, a pointer to * the (static) virtual function table for the CmpRegion class is * used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "CmpRegion" is used instead. * Returned Value: * A pointer to the new CmpRegion. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstCmpRegion *new; /* Pointer to the new CmpRegion */ AstRegion *reg1; /* First Region read from dump */ AstRegion *reg2; /* Second Region read from dump */ AstFrame *f1; /* Base Frame in parent Region */ AstRegion *creg; /* Pointer to component Region */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ int i; /* Loop count */ int oper; /* The operator to include in the dump */ /* Initialise. */ new = NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* Check the global error status. */ if ( !astOK ) return new; /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this CmpRegion. In this case the CmpRegion belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstCmpRegion ); vtab = &class_vtab; name = "CmpRegion"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitCmpRegionVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built CmpRegion. */ new = astLoadRegion( mem, size, (AstRegionVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "CmpRegion" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* Operator */ /* -------- */ oper = astReadInt( channel, "operator", AST__AND ); /* First Region. */ /* -------------- */ reg1 = astReadObject( channel, "regiona", NULL ); /* Second Region. */ /* --------------- */ reg2 = astReadObject( channel, "regionb", NULL ); /* Initialised cached values to show they have not yet been found. */ for( i = 0; i < 2; i++ ) { new->rvals[ i ] = NULL; new->offs[ i ] = NULL; new->nbreak[ i ] = 0; new->d0[ i ] = AST__BAD; new->dtot[ i ] = AST__BAD; } new->bounded = -INT_MAX; /* The CmpRegion class does not implement XOR directly (as it does for AND and OR). Instead, when requested to create an XOR CmpRegion, it creates a CmpRegion that uses AND and OR to simulate XOR. The top level XOR CmpRegion actually uses AST__OR and the two component regions within it are CmpRegions formed by combing the two supplied Regions (one being negated first) using AND. Create the required component Regions. */ if( oper == AST__XOR ) { astNegate( reg1 ); new->region1 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ", status ); astNegate( reg1 ); astNegate( reg2 ); new->region2 = (AstRegion *) astCmpRegion( reg1, reg2, AST__AND, " ", status ); astNegate( reg2 ); new->xor1 = reg1; new->xor2 = reg2; new->oper = AST__OR; /* For AND and OR, use the supplied Regions and operator. */ } else { new->region1 = reg1; new->region2 = reg2; new->xor1 = NULL; new->xor2 = NULL; new->oper = oper; } /* If either component Region has a dummy FrameSet rather than the correct FrameSet, the correct FrameSet will have copies of the base Frame of the new CmpRegion as both its current and base Frames, connected by a UnitMap (this is equivalent to a FrameSet containing a single Frame). However if the new CmpRegion being loaded has itself got a dummy FrameSet, then we do not do this since we do not yet know what the correct FrameSet is. In this case we wait until the parent Region invokes the astSetRegFS method on the new CmpRegion. */ if( !astRegDummyFS( new ) ) { f1 = astGetFrame( ((AstRegion *) new)->frameset, AST__BASE ); creg = new->region1; if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 ); creg = new->region2; if( astRegDummyFS( creg ) ) astSetRegFS( creg, f1 ); f1 = astAnnul( f1 ); } /* If an error occurred, clean up by deleting the new CmpRegion. */ if ( !astOK ) new = astDelete( new ); } /* Return the new CmpRegion pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ int astCmpRegionList_( AstCmpRegion *this, int *nreg, AstRegion ***reg_list, int *status ) { if ( !astOK ) return AST__AND; return (**astMEMBER(this,CmpRegion,CmpRegionList))( this, nreg, reg_list, status ); } ./ast-7.3.3/slamap.h0000644000175000017500000002450612262533650012577 0ustar olesoles#if !defined( SLAMAP_INCLUDED ) /* Include this file only once */ #define SLAMAP_INCLUDED /* *+ * Name: * slamap.h * Type: * C include file. * Purpose: * Define the interface to the SlaMap class. * Invocation: * #include "slamap.h" * Description: * This include file defines the interface to the SlaMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The SlaMap class encapsulates the conversions provided by the * SLALIB library (SUN/67) for converting between different sky * coordinate systems. Since, typically, a sequence of these * SLALIB conversions is required, an SlaMap can be used to * accumulate a series of conversions which it then applies in * sequence. * Inheritance: * The SlaMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * astTransform * Use an SlaMap to transform a set of points. * Protected: * astMapMerge * Simplify a sequence of Mappings containing an SlaMap. * New Methods Defined: * Public: * astSlaAdd * Add a coordinate conversion step to an SlaMap. * Private: * None. * Other Class Functions: * Public: * astIsASlaMap * Test class membership. * astSlaMap * Create an SlaMap. * Protected: * astCheckSlaMap * Validate class membership. * astInitSlaMap * Initialise an SlaMap. * astLoadSlaMap * Load an SlaMap. * Macros: * None. * Type Definitions: * Public: * AstSlaMap * SlaMap object type. * Protected: * AstSlaMapVtab * SlaMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * DSB: David S. Berry (Starlink) * History: * 26-APR-1996 (RFWS): * Original version. * 26-SEP-1996 (RFWS): * Added external interface and I/O facilities. * 23-MAY-1997 (RFWS): * Over-ride the astMapMerge method. * 15-OCT-2002 (DSB): * Added astSTPConv, astSTPConv1, and STP coordinate system macros. * 8-JAN-2003 (DSB): * Added protected astInitSlaMapVtab method. * 22-FEB-2006 (DSB): * Added cvtextra to the AstSlaMap structure. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate mappings (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ #if defined(astCLASS) /* Protected */ #define AST__NOSTP -1 /* An invalid value for an STP coordinate system */ #define AST__HAE 0 /* Heliocentric-aries-ecliptic spherical coordinates */ #define AST__HAEC 1 /* Heliocentric-aries-ecliptic cartesian coordinates */ #define AST__HAQ 2 /* Heliocentric-aries-equatorial spherical coordinates */ #define AST__HAQC 3 /* Heliocentric-aries-equatorial cartesian coordinates */ #define AST__HG 4 /* Heliographic spherical coordinates */ #define AST__HGC 5 /* Heliographic cartesian coordinates */ #define AST__HPC 6 /* Helioprojective-cartesian spherical coordinates */ #define AST__HPCC 7 /* Helioprojective-cartesian cartesian coordinates */ #define AST__HPR 8 /* Helioprojective-radial spherical coordinates */ #define AST__HPRC 9 /* Helioprojective-radial cartesian coordinates */ #define AST__GSE 10 /* Geocentric-solar-ecliptic spherical coordinates */ #define AST__GSEC 11 /* Geocentric-solar-ecliptic cartesian coordinates */ #endif /* One IAU astronomical unit, in metres. */ #define AST__AU 1.49597870E11 /* One solar radius (top of photosphere?), in metres (from "The Explanatory Supplement to the Astronomical Almanac"). */ #define AST__SOLRAD 6.96E8 /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* SlaMap structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstSlaMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ int *cvttype; /* Pointer to array of conversion types */ double **cvtargs; /* Pointer to argument list pointer array */ double **cvtextra; /* Pointer to intermediate values pointer array */ int ncvt; /* Number of conversions to perform */ } AstSlaMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstSlaMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ void (* SlaAdd)( AstSlaMap *, const char *, const double[], int * ); } AstSlaMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstSlaMapGlobals { AstSlaMapVtab Class_Vtab; int Class_Init; double Eq_Cache; double Ep_Cache; double Amprms_Cache[ 21 ]; } AstSlaMapGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(SlaMap) /* Check class membership */ astPROTO_ISA(SlaMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstSlaMap *astSlaMap_( int, const char *, int *, ...); #else AstSlaMap *astSlaMapId_( int, const char *, ... )__attribute__((format(printf,2,3))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstSlaMap *astInitSlaMap_( void *, size_t, int, AstSlaMapVtab *, const char *, int, int * ); /* Vtab initialiser. */ void astInitSlaMapVtab_( AstSlaMapVtab *, const char *, int * ); /* Loader. */ AstSlaMap *astLoadSlaMap_( void *, size_t, AstSlaMapVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitSlaMapGlobals_( AstSlaMapGlobals * ); #endif /* Other functions. */ void astSTPConv1_( double, int, double[3], double[3], int, double[3], double[3], int * ); void astSTPConv_( double, int, int, double[3], double *[3], int, double[3], double *[3], int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ void astSlaAdd_( AstSlaMap *, const char *, const double[], int * ); /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckSlaMap(this) astINVOKE_CHECK(SlaMap,this,0) #define astVerifySlaMap(this) astINVOKE_CHECK(SlaMap,this,1) /* Test class membership. */ #define astIsASlaMap(this) astINVOKE_ISA(SlaMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astSlaMap astINVOKE(F,astSlaMap_) #else #define astSlaMap astINVOKE(F,astSlaMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitSlaMap(mem,size,init,vtab,name,flags) \ astINVOKE(O,astInitSlaMap_(mem,size,init,vtab,name,flags,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitSlaMapVtab(vtab,name) astINVOKE(V,astInitSlaMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadSlaMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadSlaMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckSlaMap to validate SlaMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #define astSlaAdd(this,cvt,args) \ astINVOKE(V,astSlaAdd_(astCheckSlaMap(this),cvt,args,STATUS_PTR)) #if defined(astCLASS) /* Protected */ #define astSTPConv astSTPConv_ #define astSTPConv1 astSTPConv1_ #endif #endif ./ast-7.3.3/fslamap.c0000644000175000017500000000675212262533650012743 0ustar olesoles/* *+ * Name: * fslamap.c * Purpose: * Define a FORTRAN 77 interface to the AST SlaMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the SlaMap class. * Routines Defined: * AST_ISASLAMAP * AST_SLAADD * AST_SLAMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 28-MAY-1997 (RFWS): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "slamap.h" /* C interface to the SlaMap class */ F77_LOGICAL_FUNCTION(ast_isaslamap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISASLAMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsASlaMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_SUBROUTINE(ast_slaadd)( INTEGER(THIS), CHARACTER(CVT), DOUBLE_ARRAY(ARGS), INTEGER(STATUS) TRAIL(CVT) ) { GENPTR_INTEGER(THIS) GENPTR_CHARACTER(CVT) GENPTR_DOUBLE_ARRAY(ARGS) char *cvt; astAt( "AST_SLAADD", NULL, 0 ); astWatchSTATUS( cvt = astString( CVT, CVT_length ); astSlaAdd( astI2P( *THIS ), cvt, ARGS ); astFree( cvt ); ) } F77_INTEGER_FUNCTION(ast_slamap)( INTEGER(FLAGS), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(FLAGS) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_SLAMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astSlaMap( *FLAGS, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/flutmap.c0000644000175000017500000000632612262533650012765 0ustar olesoles/* *+ * Name: * flutmap.c * Purpose: * Define a FORTRAN 77 interface to the AST LutMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the LutMap class. * Routines Defined: * AST_ISALUTMAP * AST_LUTMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 8-JUL-1997 (RFWS): * Original version. *- */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "lutmap.h" /* C interface to the LutMap class */ F77_LOGICAL_FUNCTION(ast_isalutmap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISALUTMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsALutMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_lutmap)( INTEGER(NLUT), DOUBLE_ARRAY(LUT), DOUBLE(START), DOUBLE(INC), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NLUT) GENPTR_DOUBLE_ARRAY(LUT) GENPTR_DOUBLE(START) GENPTR_DOUBLE(INC) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; astAt( "AST_LUTMAP", NULL, 0 ); astWatchSTATUS( char *options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astLutMap( *NLUT, LUT, *START, *INC, "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/region.h0000644000175000017500000006472112262533650012610 0ustar olesoles#if !defined( REGION_INCLUDED ) /* Include this file only once */ #define REGION_INCLUDED /* *+ * Name: * region.h * Type: * C include file. * Purpose: * Define the interface to the Region class. * Invocation: * #include "region.h" * Description: * This include file defines the interface to the Region class and * provides the type definitions, function prototypes and macros, etc. * needed to use this class. * Inheritance: * The Region class inherits from the Frame class. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 5-DEC-2003 (DSB): * Original version. * 2-MAR-2006 (DSB): * Changed AST_LONG_DOUBLE to HAVE_LONG_DOUBLE. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "frame.h" /* Parent Frame class */ /* Macros. */ /* ======= */ /* Type Definitions. */ /* ================= */ /* Region structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif typedef struct AstRegion { /* Attributes inherited from the parent class. */ AstFrame parent; /* Parent class structure */ /* Attributes specific to objects in this class. */ AstFrameSet *frameset; /* FrameSet holding original and current Frames */ AstPointSet *points; /* Points defining region location and extent */ struct AstRegion *unc; /* Region specifying position uncertainties */ double fillfactor; /* Fill factor (0.0->1.0) */ int regionfs; /* Include FrameSet in dump? */ int negated; /* Has the Region been negated? */ int closed; /* Is the boundary part of the Region? */ int meshsize; /* No. of points on boundary mesh */ struct AstRegion *defunc; /* Default uncertainty Region */ AstPointSet *basemesh; /* Base frame mesh covering the boundary */ AstPointSet *basegrid; /* Base frame grid covering the boundary */ int adaptive; /* Does the Region adapt to coord sys changes? */ int nomap; /* Ignore the Region's FrameSet? */ struct AstRegion *negation;/* Negated copy of "this" */ } AstRegion; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstRegionVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstFrameVtab frame_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ int (* Overlap)( AstRegion *, AstRegion *, int * ); int (* OverlapX)( AstRegion *, AstRegion *, int * ); AstRegion *(* MapRegion)( AstRegion *, AstMapping *, AstFrame *, int * ); AstFrame *(* GetRegionFrame)( AstRegion *, int * ); AstFrameSet *(* GetRegionFrameSet)( AstRegion *, int * ); AstFrame *(* RegFrame)( AstRegion *, int * ); AstFrameSet *(* GetRegFS)( AstRegion *, int * ); AstPointSet *(* RegTransform)( AstRegion *, AstPointSet *, int, AstPointSet *, AstFrame **, int * ); AstPointSet *(* BTransform)( AstRegion *, AstPointSet *, int, AstPointSet *, int * ); void (* Negate)( AstRegion *, int * ); void (* RegBaseBox)( AstRegion *, double *, double *, int * ); void (* RegBaseBox2)( AstRegion *, double *, double *, int * ); void (* RegSetAttrib)( AstRegion *, const char *, char **, int * ); void (* RegClearAttrib)( AstRegion *, const char *, char **, int * ); void (* GetRegionBounds)( AstRegion *, double *, double *, int * ); void (* ShowMesh)( AstRegion *, int, const char *, int * ); void (* GetRegionBounds2)( AstRegion *, double *, double *, int * ); void (* ClearUnc)( AstRegion *, int * ); void (* RegOverlay)( AstRegion *, AstRegion *, int, int * ); void (* GetRegionMesh)( AstRegion *, int, int, int, int *, double *, int * ); void (* GetRegionPoints)( AstRegion *, int, int, int *, double *, int * ); int (* GetBounded)( AstRegion *, int * ); int (* TestUnc)( AstRegion *, int * ); int (* RegDummyFS)( AstRegion *, int * ); int (* RegPins)( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); AstMapping *(* RegMapping)( AstRegion *, int * ); AstPointSet *(* RegMesh)( AstRegion *, int * ); AstPointSet *(* RegGrid)( AstRegion *, int * ); AstPointSet *(* RegBaseMesh)( AstRegion *, int * ); AstPointSet *(* RegBaseGrid)( AstRegion *, int * ); AstRegion **(* RegSplit)( AstRegion *, int *, int * ); AstPointSet *(* BndBaseMesh)( AstRegion *, double *, double *, int * ); AstPointSet *(* BndMesh)( AstRegion *, double *, double *, int * ); AstRegion *(* GetNegation)( AstRegion *, int * ); AstRegion *(* GetUncFrm)( AstRegion *, int, int * ); AstRegion *(* GetUnc)( AstRegion *, int, int * ); AstRegion *(* GetDefUnc)( AstRegion *, int * ); AstRegion *(* RegBasePick)( AstRegion *this, int, const int *, int * ); void (* ResetCache)( AstRegion *, int * ); int (* RegTrace)( AstRegion *, int, double *, double **, int * ); void (* SetUnc)( AstRegion *, AstRegion *, int * ); void (* SetRegFS)( AstRegion *, AstFrame *, int * ); double *(* RegCentre)( AstRegion *, double *, double **, int, int, int * ); #if HAVE_LONG_DOUBLE /* Not normally implemented */ int (* MaskLD)( AstRegion *, AstMapping *, int, int, const int[], const int ubnd[], long double [], long double, int * ); #endif int (* MaskB)( AstRegion *, AstMapping *, int, int, const int[], const int[], signed char[], signed char, int * ); int (* MaskD)( AstRegion *, AstMapping *, int, int, const int[], const int[], double[], double, int * ); int (* MaskF)( AstRegion *, AstMapping *, int, int, const int[], const int[], float[], float, int * ); int (* MaskI)( AstRegion *, AstMapping *, int, int, const int[], const int[], int[], int, int * ); int (* MaskL)( AstRegion *, AstMapping *, int, int, const int[], const int[], long int[], long int, int * ); int (* MaskS)( AstRegion *, AstMapping *, int, int, const int[], const int[], short int[], short int, int * ); int (* MaskUB)( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned char[], unsigned char, int * ); int (* MaskUI)( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned int[], unsigned int, int * ); int (* MaskUL)( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned long int[], unsigned long int, int * ); int (* MaskUS)( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned short int[], unsigned short int, int * ); int (* GetNegated)( AstRegion *, int * ); int (* TestNegated)( AstRegion *, int * ); void (* ClearNegated)( AstRegion *, int * ); void (* SetNegated)( AstRegion *, int, int * ); int (* GetRegionFS)( AstRegion *, int * ); int (* TestRegionFS)( AstRegion *, int * ); void (* ClearRegionFS)( AstRegion *, int * ); void (* SetRegionFS)( AstRegion *, int, int * ); int (* GetClosed)( AstRegion *, int * ); int (* TestClosed)( AstRegion *, int * ); void (* ClearClosed)( AstRegion *, int * ); void (* SetClosed)( AstRegion *, int, int * ); int (* GetMeshSize)( AstRegion *, int * ); int (* TestMeshSize)( AstRegion *, int * ); void (* ClearMeshSize)( AstRegion *, int * ); void (* SetMeshSize)( AstRegion *, int, int * ); double (* GetFillFactor)( AstRegion *, int * ); int (* TestFillFactor)( AstRegion *, int * ); void (* ClearFillFactor)( AstRegion *, int * ); void (* SetFillFactor)( AstRegion *, double, int * ); int (* GetAdaptive)( AstRegion *, int * ); int (* TestAdaptive)( AstRegion *, int * ); void (* ClearAdaptive)( AstRegion *, int * ); void (* SetAdaptive)( AstRegion *, int, int * ); } AstRegionVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstRegionGlobals { AstRegionVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstRegionGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Region) /* Check class membership */ astPROTO_ISA(Region) /* Test class membership */ #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstRegion *astInitRegion_( void *, size_t, int, AstRegionVtab *, const char *, AstFrame *, AstPointSet *, AstRegion *, int * ); /* Vtab initialiser. */ void astInitRegionVtab_( AstRegionVtab *, const char *, int * ); /* Loader. */ AstRegion *astLoadRegion_( void *, size_t, AstRegionVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitRegionGlobals_( AstRegionGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ AstFrame *astGetRegionFrame_( AstRegion *, int * ); AstFrameSet *astGetRegionFrameSet_( AstRegion *, int * ); int astOverlap_( AstRegion *, AstRegion *, int * ); void astNegate_( AstRegion *, int * ); #if HAVE_LONG_DOUBLE /* Not normally implemented */ int astMaskLD_( AstRegion *, AstMapping *, int, int, const int[], const int[], long double [], long double, int * ); #endif int astMaskB_( AstRegion *, AstMapping *, int, int, const int[], const int[], signed char[], signed char, int * ); int astMaskD_( AstRegion *, AstMapping *, int, int, const int[], const int[], double[], double, int * ); int astMaskF_( AstRegion *, AstMapping *, int, int, const int[], const int[], float[], float, int * ); int astMaskI_( AstRegion *, AstMapping *, int, int, const int[], const int[], int[], int, int * ); int astMaskL_( AstRegion *, AstMapping *, int, int, const int[], const int[], long int[], long int, int * ); int astMaskS_( AstRegion *, AstMapping *, int, int, const int[], const int[], short int[], short int, int * ); int astMaskUB_( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned char[], unsigned char, int * ); int astMaskUI_( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned int[], unsigned int, int * ); int astMaskUL_( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned long int[], unsigned long int, int * ); int astMaskUS_( AstRegion *, AstMapping *, int, int, const int[], const int[], unsigned short int[], unsigned short int, int * ); void astSetUnc_( AstRegion *, AstRegion *, int * ); AstRegion *astGetNegation_( AstRegion *, int * ); AstRegion *astGetUnc_( AstRegion *, int, int * ); void astGetRegionBounds_( AstRegion *, double *, double *, int * ); void astShowMesh_( AstRegion *, int, const char *, int * ); void astGetRegionMesh_( AstRegion *, int, int, int, int *, double *, int * ); void astGetRegionPoints_( AstRegion *, int, int, int *, double *, int * ); #if defined(astCLASS) /* Protected */ void astGetRegionBounds2_( AstRegion *, double *, double *, int * ); AstRegion *astMapRegion_( AstRegion *, AstMapping *, AstFrame *, int * ); AstFrame *astRegFrame_( AstRegion *, int * ); AstPointSet *astRegTransform_( AstRegion *, AstPointSet *, int, AstPointSet *, AstFrame **, int * ); AstPointSet *astBTransform_( AstRegion *, AstPointSet *, int, AstPointSet *, int * ); void astRegBaseBox_( AstRegion *, double *, double *, int * ); void astRegBaseBox2_( AstRegion *, double *, double *, int * ); void astRegSetAttrib_( AstRegion *, const char *, char **, int * ); void astRegClearAttrib_( AstRegion *, const char *, char **, int * ); void astClearUnc_( AstRegion *, int * ); void astRegOverlay_( AstRegion *, AstRegion *, int, int * ); int astGetBounded_( AstRegion *, int * ); int astTestUnc_( AstRegion *, int * ); int astRegDummyFS_( AstRegion *, int * ); int astRegPins_( AstRegion *, AstPointSet *, AstRegion *, int **, int * ); AstMapping *astRegMapping_( AstRegion *, int * ); AstPointSet *astRegMesh_( AstRegion *, int * ); AstPointSet *astRegGrid_( AstRegion *, int * ); AstPointSet *astRegBaseMesh_( AstRegion *, int * ); AstPointSet *astRegBaseGrid_( AstRegion *, int * ); AstPointSet *astBndBaseMesh_( AstRegion *, double *, double *, int * ); AstRegion **astRegSplit_( AstRegion *, int *, int * ); AstPointSet *astBndMesh_( AstRegion *, double *, double *, int * ); AstRegion *astGetUncFrm_( AstRegion *, int, int * ); AstRegion *astGetDefUnc_( AstRegion *, int * ); AstRegion *astRegBasePick_( AstRegion *this, int, const int *, int * ); int astOverlapX_( AstRegion *, AstRegion *, int * ); AstFrameSet *astGetRegFS_( AstRegion *, int * ); void astSetRegFS_( AstRegion *, AstFrame *, int * ); double *astRegCentre_( AstRegion *, double *, double **, int, int, int * ); double *astRegTranPoint_( AstRegion *, double *, int, int, int * ); void astResetCache_( AstRegion *, int * ); int astRegTrace_( AstRegion *, int, double *, double **, int * ); int astGetNegated_( AstRegion *, int * ); int astTestNegated_( AstRegion *, int * ); void astClearNegated_( AstRegion *, int * ); void astSetNegated_( AstRegion *, int, int * ); int astGetRegionFS_( AstRegion *, int * ); int astTestRegionFS_( AstRegion *, int * ); void astClearRegionFS_( AstRegion *, int * ); void astSetRegionFS_( AstRegion *, int, int * ); int astGetMeshSize_( AstRegion *, int * ); int astTestMeshSize_( AstRegion *, int * ); void astClearMeshSize_( AstRegion *, int * ); void astSetMeshSize_( AstRegion *, int, int * ); int astGetClosed_( AstRegion *, int * ); int astTestClosed_( AstRegion *, int * ); void astClearClosed_( AstRegion *, int * ); void astSetClosed_( AstRegion *, int, int * ); double astGetFillFactor_( AstRegion *, int * ); int astTestFillFactor_( AstRegion *, int * ); void astClearFillFactor_( AstRegion *, int * ); void astSetFillFactor_( AstRegion *, double, int * ); int astGetAdaptive_( AstRegion *, int * ); int astTestAdaptive_( AstRegion *, int * ); void astClearAdaptive_( AstRegion *, int * ); void astSetAdaptive_( AstRegion *, int, int * ); #else /* Public only */ AstRegion *astMapRegionId_( AstRegion *, AstMapping *, AstFrame *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckRegion(this) astINVOKE_CHECK(Region,this,0) #define astVerifyRegion(this) astINVOKE_CHECK(Region,this,1) /* Test class membership. */ #define astIsARegion(this) astINVOKE_ISA(Region,this) #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitRegion(mem,size,init,vtab,name,frame,pset,acc)\ astINVOKE(O,astInitRegion_(mem,size,init,vtab,name,astCheckFrame(frame),pset,acc,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitRegionVtab(vtab,name) astINVOKE(V,astInitRegionVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadRegion(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadRegion_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckRegion to validate Region pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #define astGetRegionFrame(this) \ astINVOKE(O,astGetRegionFrame_(astCheckRegion(this),STATUS_PTR)) #define astGetRegionFrameSet(this) \ astINVOKE(O,astGetRegionFrameSet_(astCheckRegion(this),STATUS_PTR)) #define astNegate(this) \ astINVOKE(V,astNegate_(astCheckRegion(this),STATUS_PTR)) #define astOverlap(this,that) \ astINVOKE(V,astOverlap_(astCheckRegion(this),astCheckRegion(that),STATUS_PTR)) #if HAVE_LONG_DOUBLE /* Not normally implemented */ #define astMaskLD(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskLD_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #endif #define astMaskB(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskB_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskD(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskD_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskF(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskF_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskI(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskI_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskL(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskL_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskS(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskS_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskUB(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskUB_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskUI(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskUI_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskUL(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskUL_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astMaskUS(this,map,inside,ndim,lbnd,ubnd,in,val) \ astINVOKE(V,astMaskUS_(astCheckRegion(this),(map?astCheckMapping(map):NULL),inside,ndim,lbnd,ubnd,in,val,STATUS_PTR)) #define astSetUnc(this,unc) astINVOKE(V,astSetUnc_(astCheckRegion(this),unc?astCheckRegion(unc):NULL,STATUS_PTR)) #define astGetUnc(this,def) astINVOKE(O,astGetUnc_(astCheckRegion(this),def,STATUS_PTR)) #define astGetRegionBounds(this,lbnd,ubnd) astINVOKE(V,astGetRegionBounds_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astShowMesh(this,format,ttl) astINVOKE(V,astShowMesh_(astCheckRegion(this),format,ttl,STATUS_PTR)) #define astGetRegionMesh(this,surface,maxpoint,maxcoord,npoint,points) \ astINVOKE(V,astGetRegionMesh_(astCheckRegion(this),surface,maxpoint,maxcoord,npoint,points,STATUS_PTR)) #define astGetRegionPoints(this,maxpoint,maxcoord,npoint,points) \ astINVOKE(V,astGetRegionPoints_(astCheckRegion(this),maxpoint,maxcoord,npoint,points,STATUS_PTR)) /* Interfaces to protected member functions. */ /* ----------------------------------------- */ #if defined(astCLASS) /* Protected */ #define astGetNegation(this) astINVOKE(O,astGetNegation_(astCheckRegion(this),STATUS_PTR)) #define astGetRegionBounds2(this,lbnd,ubnd) astINVOKE(V,astGetRegionBounds2_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astClearUnc(this) astINVOKE(V,astClearUnc_(astCheckRegion(this),STATUS_PTR)) #define astGetBounded(this) astINVOKE(V,astGetBounded_(astCheckRegion(this),STATUS_PTR)) #define astGetUncFrm(this,ifrm) astINVOKE(O,astGetUncFrm_(astCheckRegion(this),ifrm,STATUS_PTR)) #define astGetDefUnc(this) astINVOKE(O,astGetDefUnc_(astCheckRegion(this),STATUS_PTR)) #define astMapRegion(this,map,frame) astINVOKE(O,astMapRegion_(astCheckRegion(this),astCheckMapping(map),astCheckFrame(frame),STATUS_PTR)) #define astOverlapX(that,this) astINVOKE(V,astOverlapX_(astCheckRegion(that),astCheckRegion(this),STATUS_PTR)) #define astRegBaseBox(this,lbnd,ubnd) astINVOKE(V,astRegBaseBox_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astRegBaseBox2(this,lbnd,ubnd) astINVOKE(V,astRegBaseBox2_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astRegSetAttrib(this,setting,bset) astINVOKE(V,astRegSetAttrib_(astCheckRegion(this),setting,bset,STATUS_PTR)) #define astRegClearAttrib(this,setting,batt) astINVOKE(V,astRegClearAttrib_(astCheckRegion(this),setting,batt,STATUS_PTR)) #define astRegBaseMesh(this) astINVOKE(O,astRegBaseMesh_(astCheckRegion(this),STATUS_PTR)) #define astRegBasePick(this,naxes,axes) astINVOKE(O,astRegBasePick_(astCheckRegion(this),naxes,axes,STATUS_PTR)) #define astRegBaseGrid(this) astINVOKE(O,astRegBaseGrid_(astCheckRegion(this),STATUS_PTR)) #define astRegSplit(this,nlist) astINVOKE(V,astRegSplit_(astCheckRegion(this),nlist,STATUS_PTR)) #define astBndBaseMesh(this,lbnd,ubnd) astINVOKE(O,astBndBaseMesh_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astBndMesh(this,lbnd,ubnd) astINVOKE(O,astBndMesh_(astCheckRegion(this),lbnd,ubnd,STATUS_PTR)) #define astRegCentre(this,cen,ptr,index,ifrm) astINVOKE(V,astRegCentre_(astCheckRegion(this),cen,ptr,index,ifrm,STATUS_PTR)) #define astRegFrame(this) astINVOKE(O,astRegFrame_(astCheckRegion(this),STATUS_PTR)) #define astRegGrid(this) astINVOKE(O,astRegGrid_(astCheckRegion(this),STATUS_PTR)) #define astRegMesh(this) astINVOKE(O,astRegMesh_(astCheckRegion(this),STATUS_PTR)) #define astRegOverlay(this,that,unc) astINVOKE(V,astRegOverlay_(astCheckRegion(this),astCheckRegion(that),unc,STATUS_PTR)) #define astRegDummyFS(this) astINVOKE(V,astRegDummyFS_(astCheckRegion(this),STATUS_PTR)) #define astRegMapping(this) astINVOKE(O,astRegMapping_(astCheckRegion(this),STATUS_PTR)) #define astRegPins(this,pset,unc,mask) astINVOKE(V,astRegPins_(astCheckRegion(this),astCheckPointSet(pset),unc?astCheckRegion(unc):unc,mask,STATUS_PTR)) #define astRegTranPoint(this,in,np,forward) astRegTranPoint_(this,in,np,forward,STATUS_PTR) #define astGetRegFS(this) astINVOKE(O,astGetRegFS_(astCheckRegion(this),STATUS_PTR)) #define astSetRegFS(this,frm) astINVOKE(V,astSetRegFS_(astCheckRegion(this),astCheckFrame(frm),STATUS_PTR)) #define astTestUnc(this) astINVOKE(V,astTestUnc_(astCheckRegion(this),STATUS_PTR)) #define astResetCache(this) astINVOKE(V,astResetCache_(astCheckRegion(this),STATUS_PTR)) #define astRegTrace(this,n,dist,ptr) astINVOKE(V,astRegTrace_(astCheckRegion(this),n,dist,ptr,STATUS_PTR)) /* Since a NULL PointSet pointer is acceptable for "out", we must omit the argument checking in that case. (But unfortunately, "out" then gets evaluated twice - this is unlikely to matter, but is there a better way?) */ #define astRegTransform(this,in,forward,out,frm) \ astINVOKE(O,astRegTransform_(astCheckRegion(this),in?astCheckPointSet(in):NULL,forward,(out)?astCheckPointSet(out):NULL,frm,STATUS_PTR)) #define astBTransform(this,in,forward,out) \ astINVOKE(O,astBTransform_(astCheckRegion(this),in?astCheckPointSet(in):NULL,forward,(out)?astCheckPointSet(out):NULL,STATUS_PTR)) #define astClearNegated(this) astINVOKE(V,astClearNegated_(astCheckRegion(this),STATUS_PTR)) #define astGetNegated(this) astINVOKE(V,astGetNegated_(astCheckRegion(this),STATUS_PTR)) #define astSetNegated(this,negated) astINVOKE(V,astSetNegated_(astCheckRegion(this),negated,STATUS_PTR)) #define astTestNegated(this) astINVOKE(V,astTestNegated_(astCheckRegion(this),STATUS_PTR)) #define astClearAdaptive(this) astINVOKE(V,astClearAdaptive_(astCheckRegion(this),STATUS_PTR)) #define astGetAdaptive(this) astINVOKE(V,astGetAdaptive_(astCheckRegion(this),STATUS_PTR)) #define astSetAdaptive(this,adaptive) astINVOKE(V,astSetAdaptive_(astCheckRegion(this),adaptive,STATUS_PTR)) #define astTestAdaptive(this) astINVOKE(V,astTestAdaptive_(astCheckRegion(this),STATUS_PTR)) #define astClearRegionFS(this) astINVOKE(V,astClearRegionFS_(astCheckRegion(this),STATUS_PTR)) #define astGetRegionFS(this) astINVOKE(V,astGetRegionFS_(astCheckRegion(this),STATUS_PTR)) #define astSetRegionFS(this,fs) astINVOKE(V,astSetRegionFS_(astCheckRegion(this),fs,STATUS_PTR)) #define astTestRegionFS(this) astINVOKE(V,astTestRegionFS_(astCheckRegion(this),STATUS_PTR)) #define astClearMeshSize(this) astINVOKE(V,astClearMeshSize_(astCheckRegion(this),STATUS_PTR)) #define astGetMeshSize(this) astINVOKE(V,astGetMeshSize_(astCheckRegion(this),STATUS_PTR)) #define astSetMeshSize(this,meshsize) astINVOKE(V,astSetMeshSize_(astCheckRegion(this),meshsize,STATUS_PTR)) #define astTestMeshSize(this) astINVOKE(V,astTestMeshSize_(astCheckRegion(this),STATUS_PTR)) #define astClearClosed(this) astINVOKE(V,astClearClosed_(astCheckRegion(this),STATUS_PTR)) #define astGetClosed(this) astINVOKE(V,astGetClosed_(astCheckRegion(this),STATUS_PTR)) #define astSetClosed(this,closed) astINVOKE(V,astSetClosed_(astCheckRegion(this),closed,STATUS_PTR)) #define astTestClosed(this) astINVOKE(V,astTestClosed_(astCheckRegion(this),STATUS_PTR)) #define astClearFillFactor(this) astINVOKE(V,astClearFillFactor_(astCheckRegion(this),STATUS_PTR)) #define astGetFillFactor(this) astINVOKE(V,astGetFillFactor_(astCheckRegion(this),STATUS_PTR)) #define astSetFillFactor(this,ff) astINVOKE(V,astSetFillFactor_(astCheckRegion(this),ff,STATUS_PTR)) #define astTestFillFactor(this) astINVOKE(V,astTestFillFactor_(astCheckRegion(this),STATUS_PTR)) #else /* Public only */ #define astMapRegion(this,map,frame) astINVOKE(O,astMapRegionId_(astCheckRegion(this),astCheckMapping(map),astCheckFrame(frame),STATUS_PTR)) #endif #endif ./ast-7.3.3/dssmap.h0000644000175000017500000003214512262533650012607 0ustar olesoles#if !defined( DSSMAP_INCLUDED ) /* Include this file only once */ #define DSSMAP_INCLUDED /* *+ * Name: * dssmap.h * Type: * C include file. * Purpose: * Define the interface to the DssMap class. * Invocation: * #include "dssmap.h" * Description: * This include file defines the interface to the DssMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The DssMap class implements Mappings which use a Digitised Sky * Survey plate fit to transform between pixel coordinates and * Equatorial coordinates. * Inheritance: * The DssMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * None. * * Protected: * astTransform * Apply a DssMap to transform a set of points. * New Methods Defined: * Public: * astDssFits * Create a FitsChan holding a FITS description of the DSS plate fit. * * Protected: * None. * Other Class Functions: * Public: * astIsADssMap * Test class membership. * astDssMap * Create a DssMap. * * Protected: * astCheckDssMap * Validate class membership. * astInitDssMap * Initialise a DssMap. * astInitDssMapVtab * Initialise the virtual function table for the DssMap class. * astLoadDssMap * Load a DssMap. * Macros: * None. * Type Definitions: * Public: * AstDssMap * DssMap object type. * * Protected: * AstDssMapVtab * DssMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * (except for code supplied by Doug Mink, as noted in this file) * Authors: * DSB: D.S. Berry (Starlink) * History: * 18-FEB-1997 (DSB): * Original version. * 30-JUN-1997 (DSB): * All public functions made protected. * 4-NOV-1997 (DSB): * Removed copy of supplied FitsChan from DssMap structure. * 8-JAN-2003 (DSB): * Added protected astInitDssMapVtab method. * 21-OCT-2004 (DSB): * Removed wcstools prototypes which clash with the MS Windows * runtime library. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #if defined(astCLASS) /* Protected */ /* The code within this #if...#endif block is covered by the following statement of terms and conditions, which differ from the terms and conditions which apply elsewhere in this file. *************************************************************************** * * Copyright: 1988 Smithsonian Astrophysical Observatory * You may do anything you like with these files except remove * this copyright. The Smithsonian Astrophysical Observatory * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * ***************************************************************************** */ /* >>>>>>>>>>>>>>>>>> SAOimage wcs.h header file <<<<<<<<<<<<<<<<<< */ /* libwcs/wcs.h November 1, 1996 By Doug Mink, Harvard-Smithsonian Center for Astrophysics */ struct WorldCoor { double xref; /* x reference coordinate value (deg) */ double yref; /* y reference coordinate value (deg) */ double xrefpix; /* x reference pixel */ double yrefpix; /* y reference pixel */ double xinc; /* x coordinate increment (deg) */ double yinc; /* y coordinate increment (deg) */ double rot; /* rotation (deg) (from N through E) */ double crot,srot; /* Cosine and sine of rotation angle */ double cd11,cd12,cd21,cd22; /* rotation matrix */ double dc11,dc12,dc21,dc22; /* inverse rotation matrix */ double equinox; /* Equinox of coordinates default to 1950.0 */ double epoch; /* Epoch of coordinates default to equinox */ double nxpix; /* Number of pixels in X-dimension of image */ double nypix; /* Number of pixels in Y-dimension of image */ double plate_ra; /* Right ascension of plate center */ double plate_dec; /* Declination of plate center */ double plate_scale; /* Plate scale in arcsec/mm */ double x_pixel_offset; /* X pixel offset of image lower right */ double y_pixel_offset; /* Y pixel offset of image lower right */ double x_pixel_size; /* X pixel_size */ double y_pixel_size; /* Y pixel_size */ double ppo_coeff[6]; double amd_x_coeff[20]; /* X coefficients for plate model */ double amd_y_coeff[20]; /* Y coefficients for plate model */ double xpix; /* x (RA) coordinate (pixels) */ double ypix; /* y (dec) coordinate (pixels) */ double xpos; /* x (RA) coordinate (deg) */ double ypos; /* y (dec) coordinate (deg) */ int pcode; /* projection code (1-8) */ int changesys; /* 1 for FK4->FK5, 2 for FK5->FK4 */ /* 3 for FK4->galactic, 4 for FK5->galactic */ int printsys; /* 1 to print coordinate system, else 0 */ int ndec; /* Number of decimal places in PIX2WCST */ int degout; /* 1 to always print degrees in PIX2WCST */ int tabsys; /* 1 to put tab between RA & Dec, else 0 */ int rotmat; /* 0 if CDELT, CROTA; 1 if CD */ int coorflip; /* 0 if x=RA, y=Dec; 1 if x=Dec, y=RA */ int offscl; /* 0 if OK, 1 if offscale */ int plate_fit; /* 1 if plate fit, else 0 */ int wcson; /* 1 if WCS is set, else 0 */ char c1type[8]; /* 1st coordinate type code: RA--, GLON, ELON */ char c2type[8]; /* 2nd coordinate type code: DEC-, GLAT, ELAT */ char ptype[8]; /* projection type code: -SIN, -TAN, -ARC, -NCP, -GLS, -MER, -AIT */ char radecsys[16]; /* Reference frame: FK4, FK4-NO-E, FK5, GAPPT*/ char sysout[16]; /* Reference frame for output: FK4, FK5 */ char center[32]; /* Center coordinates (with frame) */ char search_format[120]; /* search command format */ /* where %s is replaced by WCS coordinates */ }; #ifndef PI #define PI 3.141592653589793 #endif /* Conversions among hours of RA, degrees and radians. */ #define degrad(x) ((x)*PI/180.) #define raddeg(x) ((x)*180./PI) #define hrdeg(x) ((x)*15.) #define deghr(x) ((x)/15.) #define hrrad(x) degrad(hrdeg(x)) #define radhr(x) deghr(raddeg(x)) /* WCS subroutines in wcs.c */ /* >>>>> DSB: Prototypes for "subroutines in wcs.c" have been removed since they clash with prototypes defined by the MS windows runtime library and are not needed by AST. */ /* Oct 26 1994 New file * Dec 21 1994 Add rotation matrix * Dec 22 1994 Add flag for coordinate reversal * Mar 6 1995 Add parameters for Digital Sky Survey plate fit * Jun 8 1995 Add parameters for coordinate system change * Jun 21 1995 Add parameter for plate scale * Jul 6 1995 Add parameter to note whether WCS is set * Aug 8 1995 Add parameter to note whether to print coordinate system * Oct 16 1995 Add parameters to save image dimensions and center coordinates * Feb 15 1996 Add coordinate conversion functions * Feb 20 1996 Add flag for tab tables * Apr 26 1996 Add epoch of positions (actual date of image) * Jul 5 1996 Add subroutine declarations * Jul 19 1996 Add WCSFULL declaration * Aug 5 1996 Add WCSNINIT to initialize WCS for non-terminated header * Oct 31 1996 Add DCnn inverse rotation matrix * Nov 1 1996 Add NDEC number of decimal places in output */ /* >>>>>>>>>>>>>>>>>>>> End of SAOimage wcs.h header file <<<<<<<<<<<<<<<< */ #endif #include "mapping.h" /* Coordinate mappings (parent class) */ #include "fitschan.h" /* Storage for FITS header cards */ /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Type Definitions. */ /* ================= */ /* DssMap structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstDssMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ void *wcs; /* Pointer to structure holding plate fit info */ } AstDssMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstDssMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ AstFitsChan *(* DssFits)( AstDssMap *, int * ); } AstDssMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstDssMapGlobals { AstDssMapVtab Class_Vtab; int Class_Init; } AstDssMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitDssMapGlobals_( AstDssMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(DssMap) /* Check class membership */ astPROTO_ISA(DssMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstDssMap *astDssMap_( void *, const char *, int *, ...); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstDssMap *astInitDssMap_( void *, size_t, int, AstDssMapVtab *, const char *, AstFitsChan *, int * ); /* Vtab initialiser. */ void astInitDssMapVtab_( AstDssMapVtab *, const char *, int * ); /* Loader. */ AstDssMap *astLoadDssMap_( void *, size_t, AstDssMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ # if defined(astCLASS) /* Protected */ AstFitsChan *astDssFits_( AstDssMap *, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckDssMap(this) astINVOKE_CHECK(DssMap,this,0) #define astVerifyDssMap(this) astINVOKE_CHECK(DssMap,this,1) /* Test class membership. */ #define astIsADssMap(this) astINVOKE_ISA(DssMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astDssMap astINVOKE(F,astDssMap_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitDssMap(mem,size,init,vtab,name,fits) \ astINVOKE(O,astInitDssMap_(mem,size,init,vtab,name,astCheckFitsChan(fits),STATUS_PTR)) /* Vtab Initialiser. */ #define astInitDssMapVtab(vtab,name) astINVOKE(V,astInitDssMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadDssMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadDssMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckDssMap to validate DssMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ #if defined(astCLASS) /* Protected */ #define astDssFits(this) astINVOKE(O,astDssFits_(astCheckDssMap(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/fitschan.c0000644000175000017500000602517612262533650013126 0ustar olesoles/* *class++ * Name: * FitsChan * Purpose: * I/O Channel using FITS header cards to represent Objects. * Constructor Function: c astFitsChan f AST_FITSCHAN * Description: * A FitsChan is a specialised form of Channel which supports I/O * operations involving the use of FITS (Flexible Image Transport * System) header cards. Writing an Object to a FitsChan (using c astWrite) will, if the Object is suitable, generate a f AST_WRITE) will, if the Object is suitable, generate a * description of that Object composed of FITS header cards, and * reading from a FitsChan will create a new Object from its FITS * header card description. * * While a FitsChan is active, it represents a buffer which may * contain zero or more 80-character "header cards" conforming to * FITS conventions. Any sequence of FITS-conforming header cards * may be stored, apart from the "END" card whose existence is * merely implied. The cards may be accessed in any order by using * the FitsChan's integer Card attribute, which identifies a "current" * card, to which subsequent operations apply. Searches c based on keyword may be performed (using astFindFits), new c cards may be inserted (astPutFits, astPutCards, astSetFits) and c existing ones may be deleted (astDelFits), extracted (astGetFits), c or changed (astSetFits). f based on keyword may be performed (using AST_FINDFITS), new f cards may be inserted (AST_PUTFITS, AST_PUTCARDS, AST_SETFITS) and f existing ones may be deleted (AST_DELFITS), extracted f (AST_GETFITS) or changed (AST_SETFITS). * * When you create a FitsChan, you have the option of specifying * "source" and "sink" functions which connect it to external data * stores by reading and writing FITS header cards. If you provide * a source function, it is used to fill the FitsChan with header cards * when it is accessed for the first time. If you do not provide a * source function, the FitsChan remains empty until you explicitly enter c data into it (e.g. using astPutFits, astPutCards, astWrite f data into it (e.g. using AST_PUTFITS, AST_PUTCARDS, AST_WRITE * or by using the SourceFile attribute to specifying a text file from * which headers should be read). When the FitsChan is deleted, any * remaining header cards in the FitsChan can be saved in either of * two ways: 1) by specifying a value for the SinkFile attribute (the * name of a text file to which header cards should be written), or 2) * by providing a sink function (used to to deliver header cards to an * external data store). If you do not provide a sink function or a * value for SinkFile, any header cards remaining when the FitsChan * is deleted will be lost, so you should arrange to extract them * first if necessary c (e.g. using astFindFits or astRead). f (e.g. using AST_FINDFITS or AST_READ). * * Coordinate system information may be described using FITS header * cards using several different conventions, termed * "encodings". When an AST Object is written to (or read from) a * FitsChan, the value of the FitsChan's Encoding attribute * determines how the Object is converted to (or from) a * description involving FITS header cards. In general, different * encodings will result in different sets of header cards to * describe the same Object. Examples of encodings include the DSS * encoding (based on conventions used by the STScI Digitised Sky * Survey data), the FITS-WCS encoding (based on a proposed FITS * standard) and the NATIVE encoding (a near loss-less way of * storing AST Objects in FITS headers). * * The available encodings differ in the range of Objects they can * represent, in the number of Object descriptions that can coexist * in the same FitsChan, and in their accessibility to other * (external) astronomy applications (see the Encoding attribute * for details). Encodings are not necessarily mutually exclusive * and it may sometimes be possible to describe the same Object in * several ways within a particular set of FITS header cards by * using several different encodings. * c The detailed behaviour of astRead and astWrite, when used with f The detailed behaviour of AST_READ and AST_WRITE, when used with * a FitsChan, depends on the encoding in use. In general, however, c all successful use of astRead is destructive, so that FITS header cards f all successful use of AST_READ is destructive, so that FITS header cards * are consumed in the process of reading an Object, and are * removed from the FitsChan (this deletion can be prevented for * specific cards by calling the c astRetainFits function). f AST_RETAINFITS routine). * An unsuccessful call of c astRead f AST_READ * (for instance, caused by the FitsChan not containing the necessary * FITS headers cards needed to create an Object) results in the * contents of the FitsChan being left unchanged. * * If the encoding in use allows only a single Object description * to be stored in a FitsChan (e.g. the DSS, FITS-WCS and FITS-IRAF c encodings), then write operations using astWrite will f encodings), then write operations using AST_WRITE will * over-write any existing Object description using that * encoding. Otherwise (e.g. the NATIVE encoding), multiple Object * descriptions are written sequentially and may later be read * back in the same sequence. * Inheritance: * The FitsChan class inherits from the Channel class. * Attributes: * In addition to those attributes common to all Channels, every * FitsChan also has the following attributes: * * - AllWarnings: A list of the available conditions * - Card: Index of current FITS card in a FitsChan * - CardComm: The comment of the current FITS card in a FitsChan * - CardName: The keyword name of the current FITS card in a FitsChan * - CardType: The data type of the current FITS card in a FitsChan * - CarLin: Ignore spherical rotations on CAR projections? * - CDMatrix: Use a CD matrix instead of a PC matrix? * - Clean: Remove cards used whilst reading even if an error occurs? * - DefB1950: Use FK4 B1950 as default equatorial coordinates? * - Encoding: System for encoding Objects as FITS headers * - FitsDigits: Digits of precision for floating-point FITS values * - Iwc: Add a Frame describing Intermediate World Coords? * - Ncard: Number of FITS header cards in a FitsChan * - Nkey: Number of unique keywords in a FitsChan * - TabOK: Should the FITS "-TAB" algorithm be recognised? * - PolyTan: Use PVi_m keywords to define distorted TAN projection? * - Warnings: Produces warnings about selected conditions * Functions: c In addition to those functions applicable to all Channels, the c following functions may also be applied to all FitsChans: f In addition to those routines applicable to all Channels, the f following routines may also be applied to all FitsChans: * c - astDelFits: Delete the current FITS card in a FitsChan c - astEmptyFits: Delete all cards in a FitsChan c - astFindFits: Find a FITS card in a FitsChan by keyword c - astGetFits: Get a keyword value from a FitsChan c - astGetTables: Retrieve any FitsTables from a FitsChan c - astPurgeWCS: Delete all WCS-related cards in a FitsChan c - astPutCards: Stores a set of FITS header card in a FitsChan c - astPutFits: Store a FITS header card in a FitsChan c - astPutTable: Store a single FitsTable in a FitsChan c - astPutTables: Store multiple FitsTables in a FitsChan c - astReadFits: Read cards in through the source function c - astRemoveTables: Remove one or more FitsTables from a FitsChan c - astRetainFits: Ensure current card is retained in a FitsChan c - astSetFits: Store a new keyword value in a FitsChan c - astShowFits: Display the contents of a FitsChan on standard output c - astTableSource: Register a source function for FITS table access c - astTestFits: Test if a keyword has a defined value in a FitsChan c - astWriteFits: Write all cards out to the sink function f - AST_DELFITS: Delete the current FITS card in a FitsChan f - AST_EMPTYFITS: Delete all cards in a FitsChan f - AST_FINDFITS: Find a FITS card in a FitsChan by keyword f - AST_GETFITS: Get a keyword value from a FitsChan f - AST_GETTABLES: Retrieve any FitsTables from a FitsChan f - AST_PURGEWCS: Delete all WCS-related cards in a FitsChan f - AST_PUTCARDS: Stores a set of FITS header card in a FitsChan f - AST_PUTFITS: Store a FITS header card in a FitsChan f - AST_PUTTABLE: Store a single FitsTables in a FitsChan f - AST_PUTTABLES: Store multiple FitsTables in a FitsChan f - AST_READFITS: Read cards in through the source function f - AST_REMOVETABLES: Remove one or more FitsTables from a FitsChan f - AST_RETAINFITS: Ensure current card is retained in a FitsChan f - AST_SETFITS: Store a new keyword value in a FitsChan c - AST_SHOWFITS: Display the contents of a FitsChan on standard output f - AST_TABLESOURCE: Register a source function for FITS table access f - AST_TESTFITS: Test if a keyword has a defined value in a FitsChan f - AST_WRITEFITS: Write all cards out to the sink function * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2008-2011 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * RFWS: R.F. Warren-Smith (Starlink, RAL) * TIMJ: Tim Jenness (JAC, Hawaii) * History: * 11-DEC-1996 (DSB): * Original version. * 20-MAR-1997 (DSB): * Made keyword setting and getting functions protected instead of * public. Renamed public methods. Added Ncard attribute. * 20-MAY-1997 (RFWS): * Tidied public prologues. * 30-JUN-1997 (DSB): * Added support for reading post-2000 DATE-OBS strings. Reading DSS * or FITS-WCS objects now returns NULL unless the FitsChan is * positioned at the start-of-file prior to the read. Bug fixed * which caused Ncard to be returned too large by one. Removed * dependancy on hard-wired header and footer text in Native * FitsChans. * 18-AUG-1997 (DSB): * Bug fixed in WcsNative which caused incorrect CRVAL values * to be used if the axes needed permuting. Values assigned to the * Projection attribute fo the SkyFrames created by astRead. * 2-SEP-1997 (DSB): * Added the IRAF convention that EPOCH=0.0 really means EPOCH=1950.0 * (the EPOCH keyword is deprecated in the new FITS-WCS conventions * and is taken always as a Besselian epoch). * 19-SEP-1997 (DSB): * Corrected interpretation of the FITS CD matrix. * 25-SEP-1997 (DSB): * o Fix bug in LinearMap which caused it always to detect a linear * mapping. For instance, this allowed DssMaps to be erroneously * written out using FITS-WCS encoding with a CAR projection. * o Assign a full textual description to SkyFrame's Projection * attribute instead of a 3 letter acronym. * o If DATE-OBS >= 1999.0 then DATE-OBS is now written in new * Y2000 format. For DATE-OBS < 1999.0, the old format is written. * o Add new attribute CDMatrix to determine whether PC or CD * matrices should be used when writing objects using FITS-WCS * encoding. * o Modified the way floating point values are formatted to omit * unnecessary leading zeros from the exponent (i.e. E-5 instead of * E-05). * o New-line characters at the end of supplied header cards are now * ignored. * o Cater for EQUINOX specified as a string prefixed by B or J * rather than as a floating point value (some HST data does this). * o Corrected SetValue so that it always inserts comment cards * rather than over-write existing comment cards. Previously, * writing a FrameSet to a DSS encoded FitsChan resulted in all * comments cards being stripped except for the last one. * o Reading a FrameSet from a DSS-encoded FrameSet now only * removes the keywords actually required to construct the FrameSet. * Previously, all keywords were removed. * o The EPOCH and EQUINOX keywords created when a FrameSet is * written to a DSS-encoded FitsChan are now determined from the * epoch and equinox of the current Frame, instead of from a copy * of the original FitsChan stored within the DssMap. * o The Encoding and CDMatrix attributes, and keyword types are * now stored as strings externally instead of integers. * 11-NOV-1997 (DSB): * o Assume default of j2000 for DSS EQUINOX value. * o Check for null object pointers in the interfaces for * virtual functions which execute even if an error has previously * occurred. Otherwise, a segmentation violation can occur when * trying to find the member function pointer. * o Trailing spaces ignored in Encoding attribute. * o Bugs fixed in FindWcs and SetValue which resulted in WCS cards * being written at the wrong place if the supplied FitsChan does not * contain any WCS keywords. * o Default for CDMatrix (if no axis rotation keywords can be found) * changed to 2 (i.e. use "CDi_j" form keywords). * o Write now leaves the current card unchanged if nothing is * written to the FitsChan. * 17-NOV-1997 (RFWS): * Disabled use of CDmatrix. Fixed initialisation problems in * astLoadFitsChan. * 24-NOV-1997 (DSB): * Replace references to error code AST__OPT with AST__RDERR. * 28-NOV-1997 (DSB): * o Function WcsValues modified to prevent it from changing the * current card. Previously, this could cause new cards to be * written to the wrong place in a FITS-WCS encoded FitsChan. * o Description of argument "value" corrected in prologue of * function SetFits. * o Argument "lastkey" removed from function SetValue since it * was never used (it was a relic from a previous method of * determining where to store new cards). Corresponding changes * have been made to all the functions which create "lastkey" values * or pass them on to SetValue (i.e DescWcs, WcsPrimary, WcsSecondary, * WriteWcs and WriteDss). * 10-DEC-1997 (DSB): * Bug fixed which caused the initial character designating the system * within CTYPE value (eg E in ELON, G in GLON, etc) to be omitted. * 1-JUN-1998 (DSB): * CDELT values of zero are now replaced by a small non-zero value * when creating the "pixel-to-relative physical" transformation * matrix. Previously, zero CDELT values could cause the matrix to * be non-invertable. * 4-SEP-1998 (DSB): * - Indicate that SphMaps created by this class when using FITS-WCS * encoding all operate on the unit sphere. This aids simplification. * - Fix a bug in StoreFits which caused CD matrices to be indexed * incorrectly (sometimes causing floating exceptions) if they do not * describe a celestial longitude/latitude system. * - Changed astFindFits to ignore trailing spaces in the keyword * template. * - astSplit changed so that an error is not reported if a textual * keyword value ends before column 20. * 7-OCT-1998 (DSB): * - Corrected test for linearity in LinearMap to include a factor * of the test vector length. Also LinearMap now uses a simplified * Mapping. * 5-NOV-1998 (DSB): * Added FITS-IRAF encoding. * 9-NOV-1998 (DSB): * - Corrected values of macros DSS_ENCODING and MAX_ENCODING. * - Corrected erroneous success indication in IrafStore. * - Included checks for bad values in function LinearMap. * 17-NOV-1998 (DSB): * The Domain name GRID is now given to the Base Frame in any FrameSets * created by astRead when using FitsChans with DSS, FITS-WCS or * FITS-IRAF encodings. * 18-DEC-1998 (DSB): * Check for "D" exponents in floating point keyword strings. * 12-FEB-1998 (DSB): * Modified EncodeFloat to avoid exceeding the 20 character FITS * limit wherever possible if FitsDigits is positive. * 10-MAY-1998 (DSB): * Bug fixed in astSplit which caused comments associated with string * keywords to be lost when storing the card in a FitsChan. * 15-JUN-1999 (DSB): * Report an error if an unrecognised projection name is supplied. * 9-DEC-1999 (DSB): * - Fixed bug in WcsNatPole which could result in longitude values * being out by 180 degrees for cylindrical projections such as CAR. * - Only report an "unrecognised projection" error for CTYPE values * which look like celestial longitude or latitude axes (i.e. if the * first 4 characters are "RA--", "DEC-", "xLON" or "xLAT", and the * fifth character is "-"). * - Added function SpecTrans to translated keywords related to the * IRAF ZPX projection into keyword for the standard ZPN projection. * - Add ICRS as a valid value for the RADECSYS keyword. Since the * SkyFrame class does not yet support ICRS, an FK5 SkyFrame is * created if RADECSYS=ICRS. * 16-DEC-1999 (DSB): * - Modified SpecTrans so that all keywords used to created a * standard WCS representation from a non-standard one are consumed * by the astRead operation. * - Changed the text of ASTWARN cards added to the FitsChan if an * IRAF ZPX projection is found to require unsupported corrections. * - Simplified the documentation describing the handling of the IRAF * ZPX projection. * - Fixed code which assumed that the 10 FITS-WCS projection * parameters were PROJP1 -> PROJP10. In fact they are PROJP0 - * PROJP9. This could cause projection parameter values to be * incorrectly numbered when they are written out upon deletion of * the FitsChan. * 1-FEB-2000 (DSB): * Check that FITS_IRAF encoding is not being used before using a * PC matrix when reading WCS information from a header. This is * important if the header contains both PC and CD matrices. * 8-FEB-2000 (DSB): * - Header cards are now only consumed by an astRead operation if the * operation succeeds (i.e. returns a non-null Object). * - The original FITS-WCS encoding has been renamed as FITS-PC (to * indicate the use of a PCiiijjj matrix), and a new FITS-WCS * encoding has been added. * - The disabled CDMatrix attribute has been removed. * - Bug in LinearMap corrected which prevented genuinely linear * Mappings from being judged to be linear. This bug was previously * fudged (so it now appears) by the introduction of the test vector * length factor (see History entry for 7-OCT-1998). This test * vector length scale factor has consequently now been removed. * - Added FITS-AIPS encoding. * - The critical keywords used to select default encoding have been * changed. * - Support for common flavours of IRAF TNX projections added. * - The algorithm used to find a WcsMap in the supplied FrameSet * has been improved so that compound Mappings which contain complex * mixtures of parallel and serial Mappings can be translated into * FITS-WCS encoding. * - Trailing white space in string keyword values is now retained * when using foreign encodings to enable correct concatenation where * a string has been split over several keywords. E.g. if 2 string * keywords contain a list of formatted numerical values (e.g. IRAF * WAT... keywords), and the 1st one ends "0.123 " and the next one * begins "1234.5 ", the trailing space at the end of the first keyword * is needed to prevent the two numbers being merged into "0.1231234.5". * Trailing spaces in native encodings is still protected by enclosing * the whole string in double quotes. * - The Channel methods WriteString and GetNextData can now save * and restore strings of arbitary length. This is done by storing * as much of the string as possible in the usual way, and then * storing any remaining characters in subsequent CONTINUE cards, * using the FITSIO conventions. This storage and retrieval of long * strings is only available for native encodings. * 19-MAY-2000 (DSB): * Added attribute Warnings. Lowered DSS in the priority list * of encodings implemented by GetEncoding. * 6-OCT-2000 (DSB): * Increased size of buffers used to store CTYPE values to take * account of the possiblity of lots of trailing spaces. * 5-DEC-2000 (DSB): * Add support for the WCSNAME FITS keyword. * 12-DEC-2000 (DSB): * Add a title to each physical, non-celestial coord Frame based on * its Domain name (if any). * 3-APR-2001 (DSB): * - Use an "unknown" celestial coordinate system, instead of a * Cartesian coordinate system, if the CTYPE keywords specify an * unknown celestial coordinate system. * - Do not report an error if there are no CTYPE keywords in the * header (assume a unit mapping, like in La Palma FITS files). * - Add a NoCTYPE warning condition. * - Added AllWarnings attribute. * - Ensure multiple copies of identical warnings are not produced. * - Use the Object Ident attribute to store the identifier letter * associated with each Frame read from a secondary axis description, * so that they can be given the same letter when they are written * out to a new FITS file. * 10-AUG-2001 (DSB): * - Corrected function value returned by SkySys to be 1 unless an * error occurs. This error resulted in CAR headers being produced * by astWrite with CRVAL and CD values till in radians rather than * degrees. * - Introduced SplitMap2 in order to guard against producing * celestial FITS headers for a Mapping which includes more than * one WcsMap. * 13-AUG-2001 (DSB): * - Modified FixNew so that it retains the current card index if possible. * This fixed a bug which could cause headers written out using Native * encodings to be non-contiguous. * - Corrected ComBlock to correctly remove AST comment blocks in * native encoded fitschans. * 14-AUG-2001 (DSB): * - Modified FixUsed so that it it does not set the current card * back to the start of file if the last card in the FitsChan is * deleted. * 16-AUG-2001 (DSB): * Modified WcsNative to limit reference point latitude to range * +/-90 degs (previously values outside this range were wrapped * round onto the opposite meridian). Also added new warning * condition "badlat". * 23-AUG-2001 (DSB): * - Re-write LinearMap to use a least squares fit. * - Check that CDj_i is not AST__BAD within WcsWithWcs when * forming the increments along each physical axis. * 28-SEP-2001 (DSB): * GoodWarns changed so that no error is reported if a blank list * of conditions is supplied. * 12-OCT-2001 (DSB): * - Added DefB1950 attribute. * - Corrected equations which calculate CROTA when writing * FITS-AIPS encodings. * - Corrected equations which turn a CROTA value into a CD matrix. * 29-NOV-2001 (DSB): * Corrected use of "_" and "-" characters when referring to FK4-NO-E * system in function SkySys. * 20-FEB-2002 (DSB) * Added CarLin attribute. * 8-MAY-2002 (DSB): * Correct DSSToStore to ignore trailing blanks in the PLTDECSN * keyword value. * 9-MAY-2002 (DSB): * Correct GetCard to avoid infinite loop if the current card has * been marked as deleted. * 25-SEP-2002 (DSB): * AIPSFromStore: use larger of coscro and sincro when determining * CDELT values. Previously a non-zero coscro was always used, even * if it was a s small as 1.0E-17. * 3-OCT-2002 (DSB): * - SkySys: Corrected calculation of longitude axis index for unknown * celestial systems. * - SpecTrans: Corrected check for latcor terms for ZPX projections. * - WcsFrame: Only store an explicit equinox value in a skyframe if * it needs one (i.e. if the system is ecliptic or equatorial). * - WcsWithWcs: For Zenithal projections, always use the default * LONPOLE value, and absorb any excess rotation caused by this * into the CD matrix. * - WcsWithWcs: Improve the check that the native->celestial mapping * is a pure rotation, allowing for rotations which change the * handed-ness of the system (if possible). * - WcsWithWcs: Avoid using LONPOLE keywords when creating headers * for a zenithal projection. Instead, add the corresponding rotation * into the CD matrix. * 22-OCT-2002 (DSB): * - Retain leading and trailing white space within COMMENT cards. * - Only use CTYPE comments as axis labels if all non-celestial * axes have a unique non-blank comment (otherwise use CTYPE * values as labels). * - Updated to use latest FITS-WCS projections. This means that the * "TAN with projection terms" is no longer a standard FITS * projection. It is now represented using the AST-specific TPN * projection (until such time as FITS-WCS paper IV is finished). * - Remove trailing "Z" from DATE-OBS values created by astWrite. * 14-NOV-2002 (DSB): * - WcsWithWcs: Corrected to ignore longitude axis returned by * astPrimaryFrame since it does not take into account any axis * permutation. * 26-NOV-2002 (DSB): * - SpecTrans: Corrected no. of characters copied from CTYPE to PRJ, * (from 5 to 4), and terminate PRJ correctly. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitFitsChanVtab * method. * 22-JAN-2003 (DSB): * Restructured the functions used for reading FITS_WCS headers to * make the distinction between the generic parts (pixel->intermediate * world coordinates) and the specialised parts (e.g. celestial, * spectral, etc) clearer. * 31-JAN-2003 (DSB) * - Added Clean attribute. * - Corrected initialisation and defaulting of CarLin and DefB1950 * attributes. * - Extensive changes to allow foreign encodings to be produced in * cases where the Base Frame has fewer axes than the Current Frame. * 12-FEB-2003 (DSB) * - Modified SetFits so that the existing card comment is retained * if the new data value equals the existing data value. * 30-APR-2003 (DSB): * - Revert to standard "TAN" code for distorted tan projections, * rather than using the "TPN" code. Also recognise QVi_m (produced * by AUTOASTROM) as an alternative to PVi_m when reading distorted * TAN headers. * 22-MAY-2003 (DSB): * Modified GetEncoding so that the presence of RADECSYS and/or * PROJPm is only considered significant if the modern equivalent * keyword (REDESYS or PVi_m) is *NOT* present. * 2-JUN-2003 (DSB): * - Added support for PCi_j kewwords within FITS-WCS encoding * - Added CDMatrix attribute * - Changed internal FitsStore usage to use PC/CDELT instead of CD * (as preparation for FITS-WCS paper IV). * - Added warning "BadMat". * 11-JUN-2003 (DSB): * - Modified WcsNative to use the new SphMap PolarLong attribute * in order to ensure correct propagation of the longitude CRVAL * value in cases where the fiducial point is coincident with a pole. * - Use PVi_3 and PVi_4 for longitude axis "i" (if present) in * preference to LONPOLE and LATPOLE when reading a FITS-WCS header. * Note, these projection values are never written out (LONPOLE and * LATPOLE are written instead). * - Associate "RADESYS=ICRS" with SkyFrame( "System=ICRS" ), rather * than SkyFrame( "System=FK5" ). * - If DefB1950 is zero, use ICRS instead of FK5 as the default RADESYS * if no EQUINOX is present. * 1-SEP-2003 (DSB): * - Modify Dump so that it dumps all cards including those flagged as * having been read. * - Added "reset" parameter to FixUsed. * - WcsMapFrm: store an Ident of ' ' for the primary coordinate * description (previously Ident was left unset) * - Default value for DefB1950 attribute now depends on the value * of the Encoding attribute. * 15-SEP-2003 (DSB): * - Added Warnings "BadVal", "Distortion". * - Ignore FITS-WCS paper IV CTYPE distortion codes (except for * "-SIP" which is interpreted correctly on reading). * 22-OCT-2003 (DSB): * - GetEncoding: If the header contains CDi_j but does not contain * any of the old IRAF keywords (RADECSYS, etc) then assume FITS-WCS * encoding. This allows a FITS-WCS header to have both CDi_j *and* * CROTA keywords. * 5-JAN-2004 (DSB): * - SpecTrans: Use 1.0 (instead of the CDELT value) as the * diagonal PCi_j term for non-celestial axes with associated CROTA * values. * 12-JAN-2004 (DSB): * - CelestialAxes: Initialise "tmap1" pointer to NULL in case of error * (avoids a segvio happening in the case of an error). * - AddVersion: Do not attempt to add a Frame into the FITS header * if the mapping from grid to frame is not invertable. * - WorldAxes: Initialise the returned "perm" values to safe values, * and return these values if no basis vectors cen be created. * 19-JAN-2004 (DSB): * - When reading a FITS-WCS header, allow all keywords to be defaulted * as decribed in paper I. * 27-JAN-2004 (DSB): * - Modify FitLine to use correlation between actual and estimated * axis value as the test for linearity. * - Modify RoundFString to avoid writing beyond the end of the * supplied buffer if the supplied string contains a long list of 9's. * 11-MAR-2004 (DSB): * - Modified SpecTrans to check all axis descriptions for keywords * to be translated. * 19-MAR-2004 (DSB): * - Added astPutCards to support new fits_hdr2str function in * CFITSIO. * 25-MAR-2004 (DSB): * - Corrected bug in astSplit which causes legal cards to be * rejected because characters beyond the 80 char limit are being * considered significant. * - Corrected bug in SpecTrans which caused QV keywords to be * ignored. * 15-APR-2004 (DSB): * - SpecTrans modified to include translation of old "-WAV", "-FRQ" * and "-VEL" spectral algorithm codes to modern "-X2P" form. * - WcsFromStore modified to supress creation of WCSAXES keywords * for un-used axis versions. * - IsMapLinear modified to improve fit by doing a second least * squares fit to the residualleft by the first least squares fit. * 16-APR-2004 (DSB): * - NonLinSpecWcs: Issue a warning if an illegal non-linear * spectral code is encountered. * - Add a BadCTYPE warning condition. * - Corrected default value for Clean so that it is zero (as * documented). * 21-APR-2004 (DSB): * - FindWcs: Corrected to use correct OBSGEO template. This bug * caused OBSGEO keywords to be misplaced in written headers. * 23-APR-2004 (DSB): * - SplitMap: Modified so that a Mapping which has celestial axes * with constant values (such as produced by a PermMap) are treated * as a valid sky coordinate Mapping. * - AddFrame modified so that WCS Frames with a different number * of axes ot the pixel Frame can be added into the FrameSet. * - IRAFFromStore and AIPSFromStore modified so that they do not * create any output keywords if the number of WCS axes is different * to the number of pixel axes. * - Handling of OBSGEO-X/Y/Z corrected again. * - WCSFromStore modified to avouid writing partial axis descriptions. * 26-APR-2004 (DSB): * - Corrected text of output SPECSYS keyword values. * 17-MAY-2004 (DSB): * - Added IWC attribute. * 15-JUN-2004 (DSB): * - Ensure out-of-bounds longitude CRPIX values for CAR * projections are wrapped back into bounds. * 21-JUN-2004 (DSB): * - Ensure primary MJD-OBS value is used when reading foreign FITS * headers. * 7-JUL-2004 (DSB): * - Issue errors if an un-invertable PC/CD matrix is supplied in a * FITS-WCS Header. * 11-JUL-2004 (DSB): * - Re-factor code for checking spectral axis CTYPE values into * new function IsSpectral. * - Modify AIPSFromSTore to create spectral axis keywords if * possible. * - Modify SpecTrans to recognize AIPS spectral axis keywords, and * to convert "HZ" to "Hz". * - Added FITS-AIPS++ encoding. * 12-AUG-2004 (DSB): * - Convert GLS projection codes to equivalent SFL in SpecTrans. * - Added FITS-CLASS encoding. * 16-AUG-2004 (DSB): * - Removed support for paper III keyword VSOURCE, and added * support for SSYSSRC keyword. * - Added initial support for CLASS encoding. * - In FitOK: Changed tolerance for detecting constant values * from 1.0E-10 to 1.0E-8. * 17-AUG-2004 (DSB): * Correct GetFiducialNSC so that the stored values for longitude * parameters 1 and 2 are ignored unless the value of parameter 0 is * not zero. * 19-AUG-2004 (DSB): * Modify SpecTrans to ignore any CDELT values if the header * includes some CDi_j values. * 26-AUG-2004 (DSB): * Modify astSplit_ to allow floating point keyword values which * include an exponent to be specified with no decimal point * (e.g. "2E-4"). * 27-AUG-2004 (DSB): * Completed initial attempt at a FITS-CLASS encoding. * 9-SEP-2004 (DSB): * Fixed usage of uninitialised values within ReadCrval. * 13-SEP-2004 (DSB): * Check the "text" pointer can be used safely before using it in * DSSToStore. * 27-SEP-2004 (DSB): * In SpecTrans, before creating new PCi_j values, check that no * PCi_j values have been created via an earlier translation. * 28-SEP-2004 (DSB): * In AIPSPPFromStore only get projection parameters values if there * are some celestialaxes. Also allow CROTA to describe rotation of * non-celestial axes (same for AIPSFromSTore). * 4-OCT-2004 (DSB): * Correct rounding of CRPIX in AddVersion to avoid integer overflow. * 11-NOV-2004 (DSB): * - WcsFcRead: Avoid issuing warnings about bad keywords which * have already been translated into equivalent good forms. * - SpecTrans: If both PROJP and PV keywords are present, use PV * in favour of PROJP only if the PV values look correct. * 17-NOV-2004 (DSB): * - Make astSetFits public. * 16-MAR-2005 (DSB): * - Primary OBSGEO-X/Y/Z, MJD-AVG and MJDOBS keywords are associated * with all axis descriptions and should not have a trailing single * character indicating an alternate axis set. * 9-AUG-2005 (DSB): * In WcsMapFrm, check reffrm is used before annulling it. * 8-SEP-2005 (DSB): * - Change "if( a < b < c )" constructs to "if( a < b && b < c )" * - DSBSetup: correct test on FrameSet pointer state * - Ensure CLASS keywords written to a FitsChan do not come before * the final fixed position keyword. * 9-SEP-2005 (DSB): * - Added "AZ--" and "EL--" as allowed axis types in FITS-WCS * ctype values. * 12-SEP-2005 (DSB): * - Cast difference between two pointers to (int) * - CLASSFromStore:Check source velocity is defined before * storing it in the output header. * 13-SEP-2005 (DSB): * - Corrected B1940 to B1950 in AddEncodingFrame. This bug * prevented some FrameSets being written out using FITS-CLASS. * - Rationalise the use of the "mapping" pointer in AddVersion. * - WcsCelestial: Modified so that the FITS reference point is * stored as the SkyFrame SkyRef attribute value. * 7-OCT-2005 (DSB): * Make astGetFits public. * 30-NOV-2005 (DSB): * Add support for undefined FITS keyword values. * 5-DEC-2005 (DSB): * - Include an IMAGFREQ keyword in the output when writing a * DSBSpecFrame out using FITS-WCS encoding. * - Correct test for constant values in FitOK. * 7-DEC-2005 (DSB): * Free memory allocated by calls to astReadString. * 30-JAN-2006 (DSB): * Modify astSplit so that it does no read the supplied card beyond * column 80. * 14-FEB-2006 (DSB): * Override astGetObjSize. * 28-FEB-2006 (DSB): * Correct documentation typo ("NCards" -> "Ncard"). * 5-APR-2006 (DSB): * Modify SpecTrans to convert CTYPE="LAMBDA" to CTYPE="WAVE". * 26-MAY-2006 (DSB): * Guard against NULL comment pointer when converting RESTFREQ to * RESTFRQ in SpecTrans. * 29-JUN-2006 (DSB): * - Added astRetainFits. * - Consume VELOSYS FITS-WCS keywords when reading an object. * - Write out VELOSYS FITS-WCS keywords when writing an object. * 7-AUG-2006 (DSB): * Remove trailing spaces from the string returned by astGetFitsS * if the original string contains 8 or fewer characters. * 16-AUG-2006 (DSB): * Document non-destructive nature of unsuccessful astRead calls. * 17-AUG-2006 (DSB): * Fix bugs so that the value of the Clean attribute is honoured * even if an error has occurred. * 4-SEP-2006 (DSB): * Modify GetClean so that it ignores the inherited status. * 20-SEP-2006 (DSB): * Fix memory leak in WcsSpectral. * 6-OCT-2006 (DSB): * Modify IsSpectral and IsAIPSSpectral to allow for CTYPE values that * are shorter than eight characters. * 13-OCT-2006 (DSB): * - Ensure SpecFrames and SkyFrames created from a foreign FITS header * are consistent in their choice of Epoch. * - Convert MJD-OBS and MJD-AVG values from TIMESYS timescale to * TDB before using as the Epoch value in an AstFrame. Use UTC if * TIMESYS is absent. * - Convert Epoch values from TDB to UTC before storing as the * value of an MJD-OBS or MJD-AVG keyword (no TIMESYS keyword is * written). * 23-OCT-2006 (DSB): * Prefer MJD-AVG over MJD-OBS. * 30-OCT-2006 (DSB): * In FitOK: Changed lower limit on acceptbale correlation from * 0.999999 to 0.99999. * 1-NOV-2006 (DSB): * - When reading a foreign header that contains a DUT1 keyword, * use it to set the Dut1 attribute in the SkyFrame. Note, JACH * store DUT1 in units of days. This may clash with the FITS-WCS * standard (when its produced). Also note that DUT1 is not written * out as yet when writing a FrameSet to a foreign FITS header. * - Correct bug that prevented ZSOURCE keyword being added to the * output header if the source velocity was negative. * 9-NOV-2006 (DSB): * Add STATUS argument to docs for F77 AST_SETx. * 20-DEC-2006 (DSB): * Correct FK5 to ICRS in error message issued if no RADESYS or * EQUINOX is found. * 16-JAN-2007 (DSB): * Cast ignored function return values to (void) to avoid compiler * warnings. * 31-JAN-2007 (DSB): * Change SpecTrans to ignore blank unit strings (previously * converted them to "Hz"). * 16-APR-2007 (DSB): * In SplitMat, increase the allowed level of rounding erros from * 1.0E-10 to 1.0E-7 (to avoid spurious low CDi_j values being * created that should be zero). * 30-APR-2007 (DSB): * - Change DSBSetup so that the central DSBSpecFrame frequency is * CRVAL and the IF is the difference between CRVAL and LO. * - Change tolerance in FitOK from 0.99999 to 0.995 to handle data from Nicolas * Peretto. * 1-MAY-2007 (DSB): * - In astSplit, if a keyword value looks like an int but is too long to * fit in an int, then treat it as a float instead. * 18-MAY-2007 (DSB): * In CnvType, use input type rather than output type when checking * for a COMMENT card. Also, return a null data value buffer for a * COMMENT card. * 4-JUN-2007 (DSB): * In CLASSFromStore, create a DELTAV header even if it is equal to * the spectral CDELT value. Also, convert spatial reference point * to (az,el) and write out as headers AZIMUTH and ELEVATIO. * 9-JUL-2007 (DSB): * Fixed bug in DSBSetUp - previously, this function assumed that * the supplied DSBSpecFrame represented frequency, and so gave * incorrect values for IF and DSBCentre if the header described * velocity. * 9-AUG-2007 (DSB): * Changed GetEncoding so that critcal keywords are ignored if * there are no CTYPE, CRPIX or CRVAL keywords in the header. * 10-AUG-2007 (DSB): * - Changed GetEncoding so that FITS_PC is not returned if there are * any CDi_j or PCi_j keywords in the header. * - Added astPurgeWCS method. * 13-AUG-2007 (DSB): * - Include the DSS keywords AMDX%d and AMDY%d in FindWCS. * 16-AUG-2007 (DSB): * - Force all FITS-CLASS headers to contain frequency axes * (velocity axes seem not to be recognised properly by CLASS). * - Change the CLASS "VELO-LSR" header to be the velocity at the * reference channel, not the source velocity. * 22-AUG-2007 (DSB): * - Remove debugging printf statements. * 20-SEP-2007 (DSB): * Changed FitOK to check that the RMS residual is not more than * a fixed small fraction of the pixel size. * 4-DEC-2007 (DSB): * Changed CreateKeyword so that it uses a KeyMap to search for * existing keywords. This is much faster than checking every * FitsCard in the FitsChan explicitly. * 18-DEC-2007 (DSB): * Add keyword VLSR to the CLASS encoding. It holds the same value * as VELO-LSR, but different versions of class use different names. * Also write out the DELTAV keyword in the LSR rest frame rather * than the source rest frame. * 31-JAN-2008 (DSB): * Correct calculation of redshift from radio velocity in ClassTrans. * 25-FEB-2008 (DSB): * Ensure a SkyFrame represents absolute (rather than offset) * coords before writing it out in any non-native encoding. * 28-FEB-2008 (DSB): * Test for existing of SkyRefIs attribute before accessing it. * 2-APR-2008 (DSB): * In CLASSFromStore, adjust the spatial CRVAL and CRPIX values to be * the centre of the first pixel if the spatial axes are degenerate. * 17-APR-2008 (DSB): * Ignore latitude axis PV terms supplied in a TAN header * (previously, such PV terms were used as polynomial correction * terms in a TPN projection). * 30-APR-2008 (DSB): * SetValue changed so that new keywords are inserted before the * current card. * 1-MAY-2008 (DSB): * Added UndefRead warning. * 7-MAY-2008 (DSB): * Correct conversion of CDi_j to PCi_j/CDELT in SpecTrans. * 8-MAY-2008 (DSB): * When writing out a FITS-WCS header, allow linear grid->WCS * mapping to be represented by a CAR projection. * 9-MAY-2008 (DSB): * Make class variables IgnoreUsed and MarkNew static. * 30-JUN-2008 (DSB): * Improve efficiency of FindWcs. * 2-JUL-2008 (DSB): * FitsSof now returns non-zero if the FitsChan is empty. * 16-JUL-2008 (DSB): * Plug memory leak caused by failure to free the Warnings * attribute string when a FitsChan is deleted. * 24-JUL-2008 (TIMJ): * Fix buffer overrun in astGetFits when writing the keyword * to the buffer (occurred if the input string was 80 characters). * 1-OCT-2008 (DSB): * When reading a FITS-WCS header, spurious PVi_j keywords no * longer generate an error. Instead they generate warnings via the * new "BadPV" warning type. * 21-NOV-2008 (DSB): * Do not remove keywords from read headers if they may be of * relevance to things other than WCS (e.g. MJD-OBS, OBSGEO, etc). * 2-DEC-2008 (DSB): * - astGetFits now reports an error if the keyword value is undefined. * - Add new functions astTestFits and astSetFitsU. * - Remove use of AST__UNDEF constants. * - Remove "undefread" warning. * 16-JAN-2009 (DSB): * Use astAddWarning to store each warning in the parent Channel * structure. * 4-MAR-2009 (DSB): * DATE-OBS and MJD-OBS cannot have an axis description character. * 13-MAR-2009 (DSB): * The VELOSYS value read from the header is never used, so do not * report an error if VELOSYS has an undefined value. * 11-JUN-2009 (DSB): * Delay reading cards from the source until they are actually * needed. Previously, the source function was called in the * FitsChan initialiser, but this means it is not possible for * application code to call astPutChannelData before the source * function is called. The ReadFromSource function is now called * at the start of each (nearly) public or protected function to * ensure the source function has been called (the source function * pointer in the FitsChan is then nullified to ensure it is not * called again). * 18-JUN-2009 (DSB): * Include the effect of observer height (in the ObsAlt attribute) * when creating OBSGEO-X/Y/Z headers, and store a value for * ObsAlt when reading a set of OBSGEO-X/Y/Z headers. * 2-JUL-2009 (DSB): * Check FitsChan is not empty at start of FindWcs. * 7-JUL-2009 (DSB): * Add new function astSetFitsCM. * 30-JUL-2009 (DSB): * Fix axis numbering in SkyPole. * 12-FEB-2010 (DSB): * Use "" to represent AST__BAD externally. * 25-JUN-2010 (DSB): * Fix problem rounding lots of 9's in RoundFString. The problem * only affected negative values, and could lead to an extra zero * being included in the integer part. * 28-JUN-2010 (DSB): * Another problem in RoundFString! If the value has a series of * 9's followed by a series of zeros, with no decimal point (e.g. * "260579999000"), then the trailing zeros were being lost. * 16-JUL-2010 (DSB): * In SpecTrans, avoid over-writing the spatial projection code * with the spectral projection code. * 20-JUL-2010 (DSB): * Correct interpretation of NCP projection code. * 14-OCT-2010 (DSB): * - Correct loading of FitsChans that contain UNDEF keywords. * - Correct translation of spectral units with non-standard * capitalisation in SpecTrans. * 10-JAN-2011 (DSB): * Fix memory leak in MakeIntWorld. * 13-JAN-2011 (DSB): * Rename astEmpty ast astEmptyFits and make public. * 20-JAN-2011 (DSB): * - Extensive changes to support -TAB algorithm * - Recovery from a major unrequested reformatting of whitespace by * my editor! * 7-FEB-2011 (DSB): * Put a space between keyword value and slash that starts a comment * when formatting a FITS header card. * 11-FEB-2011 (DSB): * Change meaning of TabOK attribute. It is no longer a simple * boolean indicating if the -TAB algorithm is supported. Instead * it gives the value to be used for the EXTVER header - i.e. the * version number to store with any binary table created as a * result of calling astWrite. If TabOK is zero or begative, then * the -TAB algorithm is not supported. This is so that there is * some way of having multiple binary table extensions with the same * name (but different EXTVER values). * 14-FEB-2011 (DSB): * - Spectral reference point CRVAL records the obs. centre. So for -TAB * (when CRVAL is set to zero) we need to record the obs centre some * other way (use the AST-specific AXREF keywords, as for spatial axes). * - Whether to scale spatial axes from degs to rads depends on * whether the spatial axes are descirbed by -TAB or not. * - Relax the linearity requirement in IsMapLinear by a factor of * 10 to prevent a change in rest frame resulting in a non-linear * mapping. * 17-FEB-2011 (DSB): * Fix bug in axis linearity check (IsMapLinear). * 22-FEB-2011 (DSB): * The translations of AIPS non-standard CTYPE values were always * stored as primary axis description keywords, even if the original * non-standard CTYPE values were read from an alternative axis * descriptions. * 5-APR-2011 (DSB): * In SpecTrans, correct the MSX CAR projection translation. The * first pixel starts at GRID=0.5, not GRID=0.0. So the CRPIX value * needs to be reduced by 0.5 prior to normalisation, and then * increased by 0.5 after normalisation. * 23-MAY-2011 (DSB): * Add support for TNX projections that use Chebyshev polynomials. * 24-MAY-2011 (DSB): * - Add support for ZPX projections that include IRAF polynomial * corrections. * - Add PolyTan attribute. * - Fix interpretation of -SIP headers that have no inverse. * 1-JUN-2011 (DSB): * In astInitFitsChanVtab, only create the two TimeFrames if they * have not already been created (fixes scuba2 trac ticket #666). * 9-JUN-2011 (DSB): * In WCSFcRead, ignore trailing spaces when reading string values * for WCS keywords. * 23-JUN-2011 (DSB): * - Override the parent astSetSourceFile method so that it reads * headers from the SourceFile and appends them to the end of the * FitsChan. * - On deletion, write out the FitsChan contents to the file * specified by the SinkFile attribute. If no file is specified, * use the sink function specified when the FitsChan was created. * 30-AUG-2011 (DSB): * - Added astWriteFits and astReadFits. * - Move the deletion of tables and warnings from Delete to * EmptyFits. * 21-SEP-2011 (DSB): * - In RoundFString, remember to update the pointer to the exponent. * This bug caused parts of the exponent to dissappear when * formatting a value that included some trailing zeros and a * series of adjacent 9's. * - Added Nkey attribute. * 22-SEP-2011 (DSB): * - Added CardType attribute * - Allow GetFits to be used to get/set the value of the current * card. * 4-OCT-2011 (DSB): * When reading a FITS-WCFS header, if the projection is TPV (as produced * by SCAMP), change to TPN (the internal AST code for a distorted * TAN projection). * 22-NOV-2011 (DSB): * Allow the "-SIP" code to be used with non-celestial axes. * 1-FEB-2012 (DSB): * Write out MJD-OBS in the timescale specified by any TIMESYS * keyword in the FitsChan, and ensure the TIMESYS value is included * in the output header. * 23-FEB-2012 (DSB): * Use iauGd2gc in place of palGeoc where is saves some calculations. * 24-FEB-2012 (DSB): * Move invocation of AddEncodingFrame from Write to end of * MakeFitsFrameSet. This is so that AddEncodingFrame can take * advantage of any standardisations (such as adding celestial axes) * performed by MakeFItsFrameSet. Without this, a FRameSet contain * a 1D SpecFrame (no celestial axes) would fail to be exported using * FITS-CLASS encoding. * 29-FEB-2012 (DSB): * Fix bug in CLASSFromStore that caused spatial axes added by * MakeFitsFrameSet to be ignored. * 2-MAR-2012 (DSB): * - In CLASSFromSTore, ensure NAXIS2/3 values are stored in teh FitsChan, * and cater for FrameSets that have only a apectral axis and no celestial * axes (this prevented the VELO_LSR keyword being created).. * 7-MAR-2012 (DSB): * Use iauGc2gd in place of Geod. * 22-JUN-2012 (DSB): * - Check for distorted TAN projections that have zero for all PVi_m * coefficients. Issue a warning and ignore the distortion in such * cases. * - Remove all set but unused variables. * - Convert SAO distorted TAN projections (which use COi_j keywords * for polynomial coeffs) to TPN. * 26-JUN-2012 (DSB): * Correct call to astKeyFields in SAOTrans (thanks to Bill Joye * for pointing out this error). * 8-AUG-2012 (DSB): * Correct assignment to lonpole within CLASSFromStore. * 10-AUG-2012 (DSB): * Default DSS keywords CNPIX1 and CNPIX2 to zero if they are * absent, rather than reporting an error. * 7-DEC-2012 (DSB): * - When writing out a FrameSet that uses an SkyFrame to describe a * generalised spherical coordinate system ("system=unknown"), ensure * that the generated FITS CTYPE values use FITS-compliant codes * for the axis type ( "xxLN/xxLT" or "xLON/xLAT" ). * - Add support for reading and writing offset SkyFrames to * FITS-WCS. * 30-JAN-2013 (DSB): * When reading a FITS-CLASS header, use "VLSR" keyword if * "VELO-..." is not available. * 15-APR-2013 (DSB): * Correct initialisation of missing coefficients When reading a * SAO plate solution header. * 16-APR-2013 (DSB): * When determining default Encoding value, use "VLSR" keyword if * "VELO-..." is not available. * 30-MAY-2013 (DSB): * Prevent seg fault caused by overrunning the coeffs array in * WATCoeffs in cases where the TNX/ZPX projection is found to be * of a form that cannot be implemented as a TPN projection. * 11-JUN-2013 (DSB): * Fix support for reading GLS projections, and add support for * rotated GLS projections. * 28-AUG-2013 (DSB): * In WcsCelestial, if celestial axes are found with no projection * code in CTYPE, assume an old-fashioned CAR projection (i.e. no * rotation from native to WCS coords). Before this change, * CTYPE = "RA" | "DEC" axes got treated as radians, not degrees. * 16-SEP-2013 (DSB): * When exporting alternate offset SkyFrames to FITS-WCS headers, * correctly test the alternate Frame in the supplied FrameSet, rather * than the current Frame. * 24-SEP-2013 (DSB): * Fix bug in choosing default value for PolyTan attribute. * 19-OCT-2013 (DSB): * - In SIPMapping, always ignore any inverse polynomial supplied in * a SIP header as they seem often to be inaccurate. A new inverse is * created to replace it. * - In SIPMapping, only use a fit to the inverted SIP transformation * if an accuracy of 0.01 pixel can be achieved over an area three * times the dimensions of the image. Otherwise use an iterative * inverse for each point. People were seeing bad round-trip errors * when transforming points outside the image because the fit was * being used when it was not very accurate. * 12-NOV-2013 (DSB): * Added CardName and CardComm attributes. * 13-NOV-2013 (DSB): * Use a zero-length string for the CardComm attribute if the card * has no comment. * 15-NOV-2013 (DSB): * - Added method astShowFits. * - Ensure PurgeWcs removes WCS cards even if an error occurs when * reading FrameSets from the FitsChan. * - Change IsMapTab1D to improve chances of a -TAB mapping being found. * 6-JAN-2014 (DSB): * - Allow default options for newly created FitsChans to be * specified by the FITSCHAN_OPTIONS environment variable. * - Ensure the used CarLin value is not changed by a trailing frequency axis. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS FitsChan /* A macro which tests a character to see if it can be used within a FITS keyword. We include lower case letters here, but they are considered as equivalent to upper case letter. */ #define isFits(a) ( islower(a) || isupper(a) || isdigit(a) || (a)=='-' || (a)=='_' ) /* Macros which return the maximum and minimum of two values. */ #define MAX(aa,bb) ((aa)>(bb)?(aa):(bb)) #define MIN(aa,bb) ((aa)<(bb)?(aa):(bb)) /* Macro which takes a pointer to a FitsCard and returns non-zero if the card has been used and so should be ignored. */ #define CARDUSED(card) ( \ ( ignore_used == 2 && \ ( (FitsCard *) (card) )->flags & PROVISIONALLY_USED ) || \ ( ignore_used >= 1 && \ ( (FitsCard *) (card) )->flags & USED ) ) /* Set of characters used to encode a "sequence number" at the end of FITS keywords in an attempt to make them unique.. */ #define SEQ_CHARS "_ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* A general tolerance for equality between floating point values. */ #define TOL1 10.0*DBL_EPSILON /* A tolerance for equality between angular values in radians. */ #define TOL2 1.0E-10 /* Macro to check for equality of floating point values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. */ #define EQUAL(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=1.0E5*MAX((fabs(aa)+fabs(bb))*DBL_EPSILON,DBL_MIN)))) /* Macro to check for equality of floating point angular values. We cannot compare bad values directory because of the danger of floating point exceptions, so bad values are dealt with explicitly. The smallest significant angle is assumed to be 1E-9 radians (0.0002 arc-seconds).*/ #define EQUALANG(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=MAX(1.0E5*(fabs(aa)+fabs(bb))*DBL_EPSILON,1.0E-9)))) /* Macro to compare an angle in radians with zero, allowing some tolerance. */ #define ZEROANG(aa) (fabs(aa)<1.0E-9) /* Constants: */ #define UNKNOWN_ENCODING -1 #define NATIVE_ENCODING 0 #define FITSPC_ENCODING 1 #define DSS_ENCODING 2 #define FITSWCS_ENCODING 3 #define FITSIRAF_ENCODING 4 #define FITSAIPS_ENCODING 5 #define FITSAIPSPP_ENCODING 6 #define FITSCLASS_ENCODING 7 #define MAX_ENCODING 7 #define UNKNOWN_STRING "UNKNOWN" #define NATIVE_STRING "NATIVE" #define FITSPC_STRING "FITS-PC" #define FITSPC_STRING2 "FITS_PC" #define DSS_STRING "DSS" #define FITSWCS_STRING "FITS-WCS" #define FITSWCS_STRING2 "FITS_WCS" #define FITSIRAF_STRING "FITS-IRAF" #define FITSIRAF_STRING2 "FITS_IRAF" #define FITSAIPS_STRING "FITS-AIPS" #define FITSAIPS_STRING2 "FITS_AIPS" #define FITSAIPSPP_STRING "FITS-AIPS++" #define FITSAIPSPP_STRING2 "FITS_AIPS++" #define FITSCLASS_STRING "FITS-CLASS" #define FITSCLASS_STRING2 "FITS_CLASS" #define INDENT_INC 3 #define PREVIOUS 0 #define NEXT 1 #define HEADER_TEXT "Beginning of AST data for " #define FOOTER_TEXT "End of AST data for " #define FITSNAMLEN 8 #define FITSSTCOL 20 #define FITSRLCOL 30 #define FITSIMCOL 50 #define FITSCOMCOL 32 #define NORADEC 0 #define FK4 1 #define FK4NOE 2 #define FK5 3 #define GAPPT 4 #define ICRS 5 #define NOCEL 0 #define RADEC 1 #define ECLIP 2 #define GALAC 3 #define SUPER 4 #define HECLIP 5 #define AZEL 6 #define LONAX -1 #define NONAX 0 #define LATAX 1 #define NDESC 9 #define MXCTYPELEN 81 #define ALLWARNINGS " distortion noequinox noradesys nomjd-obs nolonpole nolatpole tnx zpx badcel noctype badlat badmat badval badctype badpv " #define NPFIT 10 #define SPD 86400.0 #define FL 1.0/298.257 /* Reference spheroid flattening factor */ #define A0 6378140.0 /* Earth equatorial radius (metres) */ /* String used to represent AST__BAD externally. */ #define BAD_STRING "" /* Each card in the fitschan has a set of flags associated with it, stored in different bits of the "flags" item within each FitsCard structure (note, in AST V1.4 these flags were stored in the "del" item... Dump and LoadFitsChan will need to be changed to use a correspondingly changed name for the external representation of this item). The following flags are currently defined: */ /* "USED" - This flag indicates that the the card has been used in the construction of an AST Object returned by astRead. Such cards should usually be treated as if they do not exist, i.e. they should not be used again by subsequent calls to astRead, they should not be recognised by public FitsChan methods which search the FitsChan for specified cards, and they should not be written out when the FitsChan is deleted. This flag was the only flag available in AST V1.4, and was called "Del" (for "deleted"). Used cards are retained in order to give an indication of where abouts within the header new cards should be placed when astWrite is called (i.e. new cards should usually be placed at the same point within the header as the cards which they replace). */ #define USED 1 /* "PROVISIONALLY_USED" - This flag indicates that the the card is being considered as a candidate for inclusion in the construction of an AST Object. If the Object is constructed succesfully, cards flagged as "provisionally used" will be changed to be flagged as "definitely used" (using the USED flag). If the Object fails to be constructed succesfully (if some required cards are missing from the FitsChan for instance), then "provisionally used" cards will be returned to the former state which they had prior to the attempt to construct the object. */ #define PROVISIONALLY_USED 2 /* "NEW" - This flag indicates that the the card has just been added to the FitsChan and may yet proove to be unrequired. For instance if the supplied Object is not of an appropriate flavour to be stored using the requested encoding, all "new" cards which were added before the inappropriateness was discovered will be removed from the FitsChan. Two different levels of "newness" are available. */ #define NEW1 4 #define NEW2 8 /* "PROTECTED" - This flag indicates that the the card should not be removed form the FitsChan when an Object is read using astRead. If this flag is not set, then the card will dehave as if it has been deleted if it was used in the construction of the returned AST Object. */ #define PROTECTED 16 /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "channel.h" #include "cmpframe.h" #include "cmpmap.h" #include "dssmap.h" #include "error.h" #include "fitschan.h" #include "frame.h" #include "frameset.h" #include "grismmap.h" #include "lutmap.h" #include "mathmap.h" #include "matrixmap.h" #include "memory.h" #include "object.h" #include "permmap.h" #include "pointset.h" #include "shiftmap.h" #include "skyframe.h" #include "timeframe.h" #include "keymap.h" #include "pal.h" #include "sofa.h" #include "slamap.h" #include "specframe.h" #include "dsbspecframe.h" #include "specmap.h" #include "sphmap.h" #include "unitmap.h" #include "polymap.h" #include "wcsmap.h" #include "winmap.h" #include "zoommap.h" #include "globals.h" #include "fitstable.h" /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include #include /* Type Definitions */ /* ================ */ /* This structure contains information describing a single FITS header card in a circular list of such structures. */ typedef struct FitsCard { char name[ FITSNAMLEN + 1 ];/* Keyword name (plus terminating null). */ int type; /* Data type. */ void *data; /* Pointer to the keyword's data value. */ char *comment; /* Pointer to a comment for the keyword. */ int flags; /* Flags for each card */ size_t size; /* Size of data value */ struct FitsCard *next; /* Pointer to next structure in list. */ struct FitsCard *prev; /* Pointer to previous structure in list. */ } FitsCard; /* Structure used to store information derived from the FITS WCS keyword values in a form more convenient to further processing. Conventions for units, etc, for values in a FitsStore follow FITS-WCS (e.g. angular values are stored in degrees, equinox is B or J depending on RADECSYS, etc). */ typedef struct FitsStore { char ****cname; char ****ctype; char ****ctype_com; char ****cunit; char ****radesys; char ****wcsname; char ****specsys; char ****ssyssrc; char ****ps; char ****timesys; double ***pc; double ***cdelt; double ***crpix; double ***crval; double ***equinox; double ***latpole; double ***lonpole; double ***mjdobs; double ***dut1; double ***mjdavg; double ***pv; double ***wcsaxes; double ***obsgeox; double ***obsgeoy; double ***obsgeoz; double ***restfrq; double ***restwav; double ***zsource; double ***velosys; double ***asip; double ***bsip; double ***apsip; double ***bpsip; double ***imagfreq; double ***axref; int naxis; AstKeyMap *tables; double ***skyref; double ***skyrefp; char ****skyrefis; } FitsStore; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static void (* parent_setsourcefile)( AstChannel *, const char *, int * ); static int (* parent_getobjsize)( AstObject *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_getfull)( AstChannel *, int * ); static int (* parent_getskip)( AstChannel *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static int (* parent_write)( AstChannel *, AstObject *, int * ); static AstObject *(* parent_read)( AstChannel *, int * ); #if defined(THREAD_SAFE) static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * ); #endif /* Strings to describe each data type. These should be in the order implied by the corresponding macros (eg AST__FLOAT, etc). */ static const char *type_names[9] = {"comment", "integer", "floating point", "string", "complex floating point", "complex integer", "logical", "continuation string", "undef" }; /* Text values used to represent Encoding values externally. */ static const char *xencod[8] = { NATIVE_STRING, FITSPC_STRING, DSS_STRING, FITSWCS_STRING, FITSIRAF_STRING, FITSAIPS_STRING, FITSAIPSPP_STRING, FITSCLASS_STRING }; /* Define two variables to hold TimeFrames which will be used for converting MJD values between time scales. */ static AstTimeFrame *tdbframe = NULL; static AstTimeFrame *timeframe = NULL; /* Max number of characters in a formatted int */ static int int_dig; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->Items_Written = 0; \ globals->Write_Nest = -1; \ globals->Current_Indent = 0; \ globals->Ignore_Used = 1; \ globals->Mark_New = 0; \ globals->CnvType_Text[ 0 ] = 0; \ globals->CnvType_Text0[ 0 ] = 0; \ globals->CnvType_Text1[ 0 ] = 0; \ globals->CreateKeyword_Seq_Nchars = -1; \ globals->FormatKey_Buff[ 0 ] = 0; \ globals->FitsGetCom_Sval[ 0 ] = 0; \ globals->IsSpectral_Ret = NULL; \ globals->Match_Fmt[ 0 ] = 0; \ globals->Match_Template = NULL; \ globals->Match_PA = 0; \ globals->Match_PB = 0; \ globals->Match_NA = 0; \ globals->Match_NB = 0; \ globals->Match_Nentry = 0; \ globals->WcsCelestial_Type[ 0 ] = 0; \ globals->Ignore_Used = 1; \ globals->Mark_New = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(FitsChan) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(FitsChan,Class_Init) #define class_vtab astGLOBAL(FitsChan,Class_Vtab) #define getattrib_buff astGLOBAL(FitsChan,GetAttrib_Buff) #define items_written astGLOBAL(FitsChan,Items_Written) #define write_nest astGLOBAL(FitsChan,Write_Nest) #define current_indent astGLOBAL(FitsChan,Current_Indent) #define ignore_used astGLOBAL(FitsChan,Ignore_Used) #define mark_new astGLOBAL(FitsChan,Mark_New) #define cnvtype_text astGLOBAL(FitsChan,CnvType_Text) #define cnvtype_text0 astGLOBAL(FitsChan,CnvType_Text0) #define cnvtype_text1 astGLOBAL(FitsChan,CnvType_Text1) #define createkeyword_seq_nchars astGLOBAL(FitsChan,CreateKeyword_Seq_Nchars) #define formatkey_buff astGLOBAL(FitsChan,FormatKey_Buff) #define fitsgetcom_sval astGLOBAL(FitsChan,FitsGetCom_Sval) #define isspectral_ret astGLOBAL(FitsChan,IsSpectral_Ret) #define match_fmt astGLOBAL(FitsChan,Match_Fmt) #define match_template astGLOBAL(FitsChan,Match_Template) #define match_pa astGLOBAL(FitsChan,Match_PA) #define match_pb astGLOBAL(FitsChan,Match_PB) #define match_na astGLOBAL(FitsChan,Match_NA) #define match_nb astGLOBAL(FitsChan,Match_NB) #define match_nentry astGLOBAL(FitsChan,Match_Nentry) #define wcscelestial_type astGLOBAL(FitsChan,WcsCelestial_Type) static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 ); #define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 ); static pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER; #define LOCK_MUTEX4 pthread_mutex_lock( &mutex4 ); #define UNLOCK_MUTEX4 pthread_mutex_unlock( &mutex4 ); /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* Buffer returned by GetAttrib. */ static char getattrib_buff[ AST__FITSCHAN_GETATTRIB_BUFF_LEN + 1 ]; /* Buffer for returned text string in CnvType */ static char cnvtype_text[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for real value in CnvType */ static char cnvtype_text0[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for imaginary value in CnvType */ static char cnvtype_text1[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Number of output items written since the last "Begin" or "IsA" output item, and level of Object nesting during recursive invocation of the astWrite method. */ static int items_written = 0; static int write_nest = -1; /* Indentation level for indented comments when writing Objects to a FitsChan. */ static int current_indent = 0; /* Ignore_Used: If 2, then cards which have been marked as either "definitely used" or "provisionally used" (see the USED flag above) will be ignored when searching the FitsChan, etc (i.e. they will be treated as if they have been removed from the FitsChan). If 1, then cards which have been "definitely used" will be skipped over. If zero then no cards will be skipped over. */ static int ignore_used = 1; /* Mark_New: If non-zero, then all cards added to the FitsChan will be marked with both the NEW1 and NEW2 flags (see above). If zero then new cards will not be marked with either NEW1 or NEW2. */ static int mark_new = 0; /* Number of characters used for encoding */ static int createkeyword_seq_nchars = -1; /* Buffer for value returned by FormatKey */ static char formatkey_buff[ 10 ]; /* Buffer for value returned by FitsGetCom */ static char fitsgetcom_sval[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Pointer returned by IsSpectral */ static const char *isspectral_ret = NULL; /* Format specifier for reading an integer field in Match */ static char match_fmt[ 10 ]; /* Pointer to start of template in Match */ static const char *match_template = NULL; /* Pointer to first returned field value in Match */ static int *match_pa = 0; /* Pointer to last returned field value in Match */ static int *match_pb = 0; /* No. of characters read from the test string in Match */ static int match_na = 0; /* No. of characters read from the template string in Match */ static int match_nb = 0; /* Number of recursive entries into Match */ static int match_nentry = 0; /* Buffer for celestial system in WcsCelestial */ static char wcscelestial_type[ 4 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstFitsChanVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #define LOCK_MUTEX2 #define UNLOCK_MUTEX2 #define LOCK_MUTEX3 #define UNLOCK_MUTEX3 #define LOCK_MUTEX4 #define UNLOCK_MUTEX4 #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstFitsChan *astFitsChanForId_( const char *(*)( void ), char *(*)( const char *(*)( void ), int * ), void (*)( const char * ), void (*)( void (*)( const char * ), const char *, int * ), const char *, ... ); AstFitsChan *astFitsChanId_( const char *(* source)( void ), void (* sink)( const char * ), const char *options, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static int GetObjSize( AstObject *, int * ); static void ClearCard( AstFitsChan *, int * ); static int GetCard( AstFitsChan *, int * ); static int TestCard( AstFitsChan *, int * ); static void SetCard( AstFitsChan *, int, int * ); static void ClearEncoding( AstFitsChan *, int * ); static int GetEncoding( AstFitsChan *, int * ); static int TestEncoding( AstFitsChan *, int * ); static void SetEncoding( AstFitsChan *, int, int * ); static void ClearCDMatrix( AstFitsChan *, int * ); static int GetCDMatrix( AstFitsChan *, int * ); static int TestCDMatrix( AstFitsChan *, int * ); static void SetCDMatrix( AstFitsChan *, int, int * ); static void ClearFitsDigits( AstFitsChan *, int * ); static int GetFitsDigits( AstFitsChan *, int * ); static int TestFitsDigits( AstFitsChan *, int * ); static void SetFitsDigits( AstFitsChan *, int, int * ); static void ClearDefB1950( AstFitsChan *, int * ); static int GetDefB1950( AstFitsChan *, int * ); static int TestDefB1950( AstFitsChan *, int * ); static void SetDefB1950( AstFitsChan *, int, int * ); static void ClearTabOK( AstFitsChan *, int * ); static int GetTabOK( AstFitsChan *, int * ); static int TestTabOK( AstFitsChan *, int * ); static void SetTabOK( AstFitsChan *, int, int * ); static void ClearCarLin( AstFitsChan *, int * ); static int GetCarLin( AstFitsChan *, int * ); static int TestCarLin( AstFitsChan *, int * ); static void SetCarLin( AstFitsChan *, int, int * ); static void ClearPolyTan( AstFitsChan *, int * ); static int GetPolyTan( AstFitsChan *, int * ); static int TestPolyTan( AstFitsChan *, int * ); static void SetPolyTan( AstFitsChan *, int, int * ); static void ClearIwc( AstFitsChan *, int * ); static int GetIwc( AstFitsChan *, int * ); static int TestIwc( AstFitsChan *, int * ); static void SetIwc( AstFitsChan *, int, int * ); static void ClearClean( AstFitsChan *, int * ); static int GetClean( AstFitsChan *, int * ); static int TestClean( AstFitsChan *, int * ); static void SetClean( AstFitsChan *, int, int * ); static void ClearWarnings( AstFitsChan *, int * ); static const char *GetWarnings( AstFitsChan *, int * ); static int TestWarnings( AstFitsChan *, int * ); static void SetWarnings( AstFitsChan *, const char *, int * ); static AstFitsChan *SpecTrans( AstFitsChan *, int, const char *, const char *, int * ); static AstFitsTable *GetNamedTable( AstFitsChan *, const char *, int, int, int, const char *, int * ); static AstFrameSet *MakeFitsFrameSet( AstFitsChan *, AstFrameSet *, int, int, int, const char *, const char *, int * ); static AstGrismMap *ExtractGrismMap( AstMapping *, int, AstMapping **, int * ); static AstKeyMap *GetTables( AstFitsChan *, int * ); static AstMapping *AddUnitMaps( AstMapping *, int, int, int * ); static AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *, double *, int *, char, FitsStore *, int *, int, const char *, const char *, int * ); static AstMapping *GrismSpecWcs( char *, FitsStore *, int, char, AstSpecFrame *, const char *, const char *, int * ); static AstMapping *IsMapTab1D( AstMapping *, double, const char *, AstFrame *, double *, int, int, AstFitsTable **, int *, int *, int *, int * ); static AstMapping *IsMapTab2D( AstMapping *, double, const char *, AstFrame *, double *, int, int, int, int, AstFitsTable **, int *, int *, int *, int *, int *, int *, int *, int *, int * ); static AstMapping *LinearWcs( FitsStore *, int, char, const char *, const char *, int * ); static AstMapping *LogAxis( AstMapping *, int, int, double *, double *, double, int * ); static AstMapping *LogWcs( FitsStore *, int, char, const char *, const char *, int * ); static AstMapping *MakeColumnMap( AstFitsTable *, const char *, int, int, const char *, const char *, int * ); static AstMapping *NonLinSpecWcs( AstFitsChan *, char *, FitsStore *, int, char, AstSpecFrame *, const char *, const char *, int * ); static AstMapping *OtherAxes( AstFitsChan *, AstFrameSet *, double *, int *, char, FitsStore *, double *, int *, const char *, const char *, int * ); static AstMapping *SIPMapping( double *, FitsStore *, char, int, const char *, const char *, int * ); static AstMapping *SpectralAxes( AstFitsChan *, AstFrameSet *, double *, int *, char, FitsStore *, double *, int *, const char *, const char *, int * ); static AstMapping *TabMapping( AstFitsChan *, FitsStore *, char, int **, const char *, const char *, int *); static AstMapping *WcsCelestial( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, double *, double *, AstSkyFrame **, AstMapping **, int *, const char *, const char *, int * ); static AstMapping *WcsIntWorld( AstFitsChan *, FitsStore *, char, int, const char *, const char *, int * ); static AstMapping *WcsMapFrm( AstFitsChan *, FitsStore *, char, AstFrame **, const char *, const char *, int * ); static AstMapping *WcsNative( AstFitsChan *, FitsStore *, char, AstWcsMap *, int, int, const char *, const char *, int * ); static AstMapping *WcsOthers( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, const char *, const char *, int * ); static AstMapping *WcsSpectral( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, double, double, AstSkyFrame *, const char *, const char *, int * ); static AstMapping *ZPXMapping( AstFitsChan *, FitsStore *, char, int, int[2], const char *, const char *, int * ); static AstMatrixMap *WcsCDeltMatrix( FitsStore *, char, int, const char *, const char *, int * ); static AstMatrixMap *WcsPCMatrix( FitsStore *, char, int, const char *, const char *, int * ); static AstObject *FsetFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static AstObject *Read( AstChannel *, int * ); static AstSkyFrame *WcsSkyFrame( AstFitsChan *, FitsStore *, char, int, char *, int, int, const char *, const char *, int * ); static AstTimeScaleType TimeSysToAst( AstFitsChan *, const char *, const char *, const char *, int * ); static AstWinMap *WcsShift( FitsStore *, char, int, const char *, const char *, int * ); static FitsCard *GetLink( FitsCard *, int, const char *, const char *, int * ); static FitsStore *FitsToStore( AstFitsChan *, int, const char *, const char *, int * ); static FitsStore *FreeStore( FitsStore *, int * ); static FitsStore *FsetToStore( AstFitsChan *, AstFrameSet *, int, double *, int, const char *, const char *, int * ); static char *CardComm( AstFitsChan *, int * ); static char *CardName( AstFitsChan *, int * ); static char *ConcatWAT( AstFitsChan *, int, const char *, const char *, int * ); static char *FormatKey( const char *, int, int, char, int * ); static char *GetItemC( char *****, int, int, char, char *, const char *method, const char *class, int * ); static char *SourceWrap( const char *(*)( void ), int * ); static char *UnPreQuote( const char *, int * ); static char GetMaxS( double ****item, int * ); static const char *GetAllWarnings( AstFitsChan *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetCardComm( AstFitsChan *, int * ); static const char *GetCardName( AstFitsChan *, int * ); static const char *GetFitsSor( const char *, int * ); static const char *IsSpectral( const char *, char[5], char[5], int * ); static double **OrthVectorSet( int, int, double **, int * ); static double *Cheb2Poly( double *, int, int, double, double, double, double, int * ); static double *FitLine( AstMapping *, double *, double *, double *, double, double *, int * ); static double *OrthVector( int, int, double **, int * ); static double *ReadCrval( AstFitsChan *, AstFrame *, char, const char *, const char *, int * ); static double ChooseEpoch( AstFitsChan *, FitsStore *, char, const char *, const char *, int * ); static double DateObs( const char *, int * ); static double GetItem( double ****, int, int, char, char *, const char *method, const char *class, int * ); static double NearestPix( AstMapping *, double, int, int * ); static double TDBConv( double, int, int, const char *, const char *, int * ); static int *CardFlags( AstFitsChan *, int * ); static int AIPSFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int AIPSPPFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int AddEncodingFrame( AstFitsChan *, AstFrameSet *, int, const char *, const char *, int * ); static int AddVersion( AstFitsChan *, AstFrameSet *, int, int, FitsStore *, double *, char, int, int, const char *, const char *, int * ); static int CLASSFromStore( AstFitsChan *, FitsStore *, AstFrameSet *, double *, const char *, const char *, int * ); static int CardType( AstFitsChan *, int * ); static int CheckFitsName( const char *, const char *, const char *, int * ); static int ChrLen( const char *, int * ); static int CnvType( int, void *, size_t, int, int, void *, const char *, const char *, const char *, int * ); static int CnvValue( AstFitsChan *, int , int, void *, const char *, int * ); static int ComBlock( AstFitsChan *, int, const char *, const char *, int * ); static int CountFields( const char *, char, const char *, const char *, int * ); static int DSSFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int EncodeFloat( char *, int, int, int, double, int * ); static int EncodeValue( AstFitsChan *, char *, int, int, const char *, int * ); static int FindBasisVectors( AstMapping *, int, int, double *, AstPointSet *, AstPointSet *, int * ); static int FindFits( AstFitsChan *, const char *, char[ AST__FITSCHAN_FITSCARDLEN + 1 ], int, int * ); static int FindKeyCard( AstFitsChan *, const char *, const char *, const char *, int * ); static int FindLonLatSpecAxes( FitsStore *, char, int *, int *, int *, const char *, const char *, int * ); static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * ); static int FitOK( int, double *, double *, double, int * ); static int FitsEof( AstFitsChan *, int * ); static int FitsFromStore( AstFitsChan *, FitsStore *, int, double *, AstFrameSet *, const char *, const char *, int * ); static int FitsGetCom( AstFitsChan *, const char *, char **, int * ); static int FitsSof( AstFitsChan *, int * ); static int FullForm( const char *, const char *, int, int * ); static int GetCardType( AstFitsChan *, int * ); static int GetFiducialWCS( AstWcsMap *, AstMapping *, int, int, double *, double *, int * ); static int GetFitsCF( AstFitsChan *, const char *, double *, int * ); static int GetFitsCI( AstFitsChan *, const char *, int *, int * ); static int GetFitsCN( AstFitsChan *, const char *, char **, int * ); static int GetFitsF( AstFitsChan *, const char *, double *, int * ); static int GetFitsI( AstFitsChan *, const char *, int *, int * ); static int GetFitsL( AstFitsChan *, const char *, int *, int * ); static int GetFitsS( AstFitsChan *, const char *, char **, int * ); static int GetFull( AstChannel *, int * ); static int GetMaxI( double ****item, char, int * ); static int GetMaxJM( double ****item, char, int * ); static int GetMaxJMC( char *****item, char, int * ); static int GetNcard( AstFitsChan *, int * ); static int GetNkey( AstFitsChan *, int * ); static int GetSkip( AstChannel *, int * ); static int GetUsedPolyTan( AstFitsChan *, AstFitsChan *, int, int, char, const char *, const char *, int * ); static int GetValue( AstFitsChan *, const char *, int, void *, int, int, const char *, const char *, int * ); static int GetValue2( AstFitsChan *, AstFitsChan *, const char *, int, void *, int, const char *, const char *, int * ); static int GoodWarns( const char *, int * ); static int HasAIPSSpecAxis( AstFitsChan *, const char *, const char *, int * ); static int HasCard( AstFitsChan *, const char *, const char *, const char *, int * ); static int IRAFFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int IsAIPSSpectral( const char *, char **, char **, int * ); static int IsMapLinear( AstMapping *, const double [], const double [], int, int * ); static int IsSkyOff( AstFrameSet *, int, int * ); static int KeyFields( AstFitsChan *, const char *, int, int *, int *, int * ); static int LooksLikeClass( AstFitsChan *, const char *, const char *, int * ); static int MakeBasisVectors( AstMapping *, int, int, double *, AstPointSet *, AstPointSet *, int * ); static int MakeIntWorld( AstMapping *, AstFrame *, int *, char, FitsStore *, double *, const char *, const char *, int * ); static int Match( const char *, const char *, int, int *, int *, const char *, const char *, int * ); static int MatchChar( char, char, const char *, const char *, const char *, int * ); static int MatchFront( const char *, const char *, char *, int *, int *, int *, const char *, const char *, const char *, int * ); static int MoveCard( AstFitsChan *, int, const char *, const char *, int * ); static int PCFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int SAOTrans( AstFitsChan *, AstFitsChan *, const char *, const char *, int * ); static int SearchCard( AstFitsChan *, const char *, const char *, const char *, int * ); static int SetFits( AstFitsChan *, const char *, void *, int, const char *, int, int * ); static int Similar( const char *, const char *, int * ); static int SkySys( AstFitsChan *, AstSkyFrame *, int, int, FitsStore *, int, int, char c, int, const char *, const char *, int * ); static int Split( const char *, char **, char **, char **, const char *, const char *, int * ); static int SplitMap( AstMapping *, int, int, int, AstMapping **, AstWcsMap **, AstMapping **, int * ); static int SplitMap2( AstMapping *, int, AstMapping **, AstWcsMap **, AstMapping **, int * ); static int SplitMat( int , double *, double *, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int TestFits( AstFitsChan *, const char *, int *, int * ); static int Use( AstFitsChan *, int, int, int * ); static int Ustrcmp( const char *, const char *, int * ); static int Ustrncmp( const char *, const char *, size_t, int * ); static int WATCoeffs( const char *, int, double **, int **, int *, int * ); static int WcsFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static int WcsNatPole( AstFitsChan *, AstWcsMap *, double, double, double, double *, double *, double *, int * ); static int WorldAxes( AstFitsChan *this, AstMapping *, double *, int *, int * ); static int Write( AstChannel *, AstObject *, int * ); static void *CardData( AstFitsChan *, size_t *, int * ); static void AdaptLut( AstMapping *, int, double, double, double, double, double, double **, double **, int *, int * ); static void AddFrame( AstFitsChan *, AstFrameSet *, int, int, FitsStore *, char, const char *, const char *, int * ); static void ChangePermSplit( AstMapping *, int * ); static void CheckZero( char *, double, int, int * ); static void Chpc1( double *, double *, int, int *, int *, int * ); static void ClassTrans( AstFitsChan *, AstFitsChan *, int, int, const char *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void CreateKeyword( AstFitsChan *, const char *, char [ FITSNAMLEN + 1 ], int * ); static void DSBSetUp( AstFitsChan *, FitsStore *, AstDSBSpecFrame *, char, double, const char *, const char *, int * ); static void DSSToStore( AstFitsChan *, FitsStore *, const char *, const char *, int * ); static void DelFits( AstFitsChan *, int * ); static void Delete( AstObject *, int * ); static void DeleteCard( AstFitsChan *, const char *, const char *, int * ); static void DistortMaps( AstFitsChan *, FitsStore *, char, int , AstMapping **, AstMapping **, AstMapping **, AstMapping **, const char *, const char *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void EmptyFits( AstFitsChan *, int * ); static void FindWcs( AstFitsChan *, int, int, int, const char *, const char *, int * ); static void FixNew( AstFitsChan *, int, int, const char *, const char *, int * ); static void FixUsed( AstFitsChan *, int, int, int, const char *, const char *, int * ); static void FormatCard( AstFitsChan *, char *, const char *, int * ); static void FreeItem( double ****, int * ); static void FreeItemC( char *****, int * ); static void GetFiducialNSC( AstWcsMap *, double *, double *, int * ); static void GetFiducialPPC( AstWcsMap *, double *, double *, int * ); static void GetNextData( AstChannel *, int, char **, char **, int * ); static void InsCard( AstFitsChan *, int, const char *, int, void *, const char *, const char *, const char *, int * ); static void MakeBanner( const char *, const char *, const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int * ); static void MakeIndentedComment( int, char, const char *, const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1], int * ); static void MakeIntoComment( AstFitsChan *, const char *, const char *, int * ); static void MakeInvertable( double **, int, double *, int * ); static void MarkCard( AstFitsChan *, int * ); static void NewCard( AstFitsChan *, const char *, int, const void *, const char *, int, int * ); static void PreQuote( const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ], int * ); static void PurgeWCS( AstFitsChan *, int * ); static void PutCards( AstFitsChan *, const char *, int * ); static void PutFits( AstFitsChan *, const char [ AST__FITSCHAN_FITSCARDLEN + 1 ], int, int * ); static void PutTable( AstFitsChan *, AstFitsTable *, const char *, int * ); static void PutTables( AstFitsChan *, AstKeyMap *, int * ); static void ReadFits( AstFitsChan *, int * ); static void ReadFromSource( AstFitsChan *, int * ); static void RemoveTables( AstFitsChan *, const char *, int * ); static void RetainFits( AstFitsChan *, int * ); static void RoundFString( char *, int, int * ); static void SetAlgCode( char *, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SetFitsCF( AstFitsChan *, const char *, double *, const char *, int, int * ); static void SetFitsCI( AstFitsChan *, const char *, int *, const char *, int, int * ); static void SetFitsCM( AstFitsChan *, const char *, int, int * ); static void SetFitsCN( AstFitsChan *, const char *, const char *, const char *, int, int * ); static void SetFitsCom( AstFitsChan *, const char *, const char *, int, int * ); static void SetFitsF( AstFitsChan *, const char *, double, const char *, int, int * ); static void SetFitsI( AstFitsChan *, const char *, int, const char *, int, int * ); static void SetFitsL( AstFitsChan *, const char *, int, const char *, int, int * ); static void SetFitsS( AstFitsChan *, const char *, const char *, const char *, int, int * ); static void SetFitsU( AstFitsChan *, const char *, const char *, int, int * ); static void SetItem( double ****, int, int, char, double, int * ); static void SetItemC( char *****, int, int, char, const char *, int * ); static void SetSourceFile( AstChannel *, const char *, int * ); static void SetValue( AstFitsChan *, const char *, void *, int, const char *, int * ); static void Shpc1( double, double, int, double *, double *, int * ); static void ShowFits( AstFitsChan *, int * ); static void SinkWrap( void (*)( const char * ), const char *, int * ); static void SkyPole( AstWcsMap *, AstMapping *, int, int, int *, char, FitsStore *, const char *, const char *, int * ); static void TableSource( AstFitsChan *, void (*)( AstFitsChan *, const char *, int, int, int * ), int * ); static void TidyOffsets( AstFrameSet *, int * ); static void Warn( AstFitsChan *, const char *, const char *, const char *, const char *, int * ); static void WcsFcRead( AstFitsChan *, AstFitsChan *, FitsStore *, const char *, const char *, int * ); static void WcsToStore( AstFitsChan *, AstFitsChan *, FitsStore *, const char *, const char *, int * ); static void WriteBegin( AstChannel *, const char *, const char *, int * ); static void WriteDouble( AstChannel *, const char *, int, int, double, const char *, int * ); static void WriteEnd( AstChannel *, const char *, int * ); static void WriteFits( AstFitsChan *, int * ); static void WriteInt( AstChannel *, const char *, int, int, int, const char *, int * ); static void WriteIsA( AstChannel *, const char *, const char *, int * ); static void WriteObject( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); static void WriteString( AstChannel *, const char *, int, int, const char *, const char *, int * ); static void WriteToSink( AstFitsChan *, int * ); static void SetTableSource( AstFitsChan *, void (*)( void ), void (*)( void (*)( void ), AstFitsChan *, const char *, int, int, int * ), int * ); static void TabSourceWrap( void (*)( void ), AstFitsChan *, const char *, int, int, int * ); #if defined(THREAD_SAFE) static int ManageLock( AstObject *, int, int, AstObject **, int * ); #endif /* Member functions. */ /* ================= */ static void AdaptLut( AstMapping *map, int npos, double eps, double x0, double x1, double v0, double v1, double **xtab, double **vtab, int *nsamp, int *status ){ /* * Name: * AdaptLut * Purpose: * Create a table of optimally sampled values for a Mapping. * Type: * Private function. * Synopsis: * void AdaptLut( AstMapping *map, int npos, double eps, double x0, * double x1, double v0, double v1, double **xtab, * double **vtab, int *nsamp, int *status ) * Class Membership: * FitsChan * Description: * This function returns a look-up table holding samples of the supplied * 1D mapping. The input values at which the samples are taken are * returned in the "xtab" array, and the Mapping output values at * these input values are returned in the "vtab" array. The sample * spacing is smaller at positions where the output gradient is * changing more rapidly (i.e. where the output is more non-linear). * Parameters: * map * Pointer to the Mapping. Should have 1 input and 1 output. * npos * The minimum number of samples to place within the interval to be * sampled, excluding the two end points (which are always sampeld * anyway). These samples are placed evenly through the [x0,x1] interval. The interval between adjacent samples will be further * subdivided if necessary by calling this function recursively. * eps * The maximum error in X (i.e. the Mapping input) allowed before * the supplied interval is subdivided further by a recursive call * to this function. * x0 * The Mapping input value at the start of the interval to be sampled. * It is assumed that this value is already stored in (*xtab)[0] on * entry. * x1 * The Mapping input value at the end of the interval to be sampled. * v0 * The Mapping output value at the start of the interval to be sampled. * It is assumed that this value is already stored in (*vtab)[0] on * entry. * v1 * The Mapping output value at the end of the interval to be sampled. * xtab * Address of a pointer to the array in which to store the Mapping * input values at which samples were taken. The supplied pointer * may be changed on exit to point to a larger array. New values * are added to the end of this array. The initial size of the array * is given by the supplied value for "*nsamp" * vtab * Address of a pointer to the array in which to store the Mapping * output value at each sample. The supplied pointer may be changed * on exit to point to a larger array. New values are added to the * end of this array. The initial size of the array is given by the * supplied value for "*nsamp". * nsamp * Address of an int holding the number of values in the "*xtab" * and "*ytab" arrays. Updated on exit to include the new values * added to the arrays by this function. * status * Pointer to the inherited status variable. * Returned Value: * The size of the returned xtab and vtab arrays. */ /* Local Variables: */ double *vv; /* Pointer to Mapping output values */ double *xx; /* Pointer to Mapping input values */ double dx; /* Step between sample positions */ double rg; /* Reciprocal of gradient of (x0,v0)->(x1,v1) line */ double xx0; /* X at first new sample position */ int ipos; /* Interior sample index */ int isamp; /* Index into extended xtab and vtab arrays. */ int subdivide; /* Subdivide each subinterval? */ /* Check the inherited status. */ if( !astOK ) return; /* Allocate work space. */ xx = astMalloc( sizeof( double )*npos ); vv = astMalloc( sizeof( double )*npos ); if( astOK ) { /* Set up the evenly spaced interior sample positions. */ dx = ( x1 - x0 )/( npos + 1 ); xx0 = x0 + dx; for( ipos = 0; ipos < npos; ipos++ ) { xx[ ipos ] = xx0 + ipos*dx; } /* Find the Mapping output values at these input values. */ astTran1( map, npos, xx, 1, vv ); /* See if any of these samples deviate significantly from the straight line defined by (x0,v0) and (x1,v1). If any such sample is found, we call this function recursively to sample the subdivided intervals. First handle cases where the straight line has zero gradient. */ subdivide = 0; if( v0 == v1 ) { /* Subdivide if any of the interior sample values are different to the end values. */ for( ipos = 0; ipos < npos; ipos++ ) { if( vv[ ipos ] != v0 ) { subdivide = 1; break; } } /* Now handle cases where the line has non-zero gradient. Subdivide if any of the interior sample input positions are further than "eps" from the input position that would give the same output value if the mapping was linear. */ } else { rg = ( x1 - x0 )/( v1 - v0 ); for( ipos = 0; ipos < npos; ipos++ ) { if( vv[ ipos ] == AST__BAD || fabs( rg*( vv[ ipos ] - v0 ) - ( xx[ ipos ] - x0 ) ) > eps ) { subdivide = 1; break; } } } /* If required, call this function recursively to subdivide each section of the supplied input interval, and append samples to the returned arrays. */ if( subdivide ) { /* Do each sub-interval, except the last one. The number of subintervals is one more than the number of interior samples. */ for( ipos = 0; ipos < npos; ipos++ ) { /* Append samples covering the current subinterval to the ends of the arrays. */ AdaptLut( map, npos, eps, x0, xx[ ipos ], v0, vv[ ipos ], xtab, vtab, nsamp, status ); /* Store the starting position for the next sub-interval. */ x0 = xx[ ipos ]; v0 = vv[ ipos ]; } /* Now do the final sub-interval. */ AdaptLut( map, npos, eps, x0, x1, v0, v1, xtab, vtab, nsamp, status ); /* If we do not need to subdivide, store the samples in the returned array, together with the supplied final point. */ } else { /* Extend the arrays. */ isamp = *nsamp; *nsamp += npos + 1; *xtab = astGrow( *xtab, *nsamp, sizeof( double ) ); *vtab = astGrow( *vtab, *nsamp, sizeof( double ) ); if( astOK ) { /* Store the sample positions and values at the end of the extended arrays. */ for( ipos = 0; ipos < npos; ipos++, isamp++ ) { (*xtab)[ isamp ] = xx[ ipos ]; (*vtab)[ isamp ] = vv[ ipos ]; } (*xtab)[ isamp ] = x1; (*vtab)[ isamp ] = v1; } } } /* Free resources. */ xx = astFree( xx ); vv= astFree( vv ); } static int AddEncodingFrame( AstFitsChan *this, AstFrameSet *fs, int encoding, const char *method, const char *class, int *status ){ /* * Name: * AddEncodingFrame * Purpose: * Add a Frame which conforms to the requirements of the specified encoding. * Type: * Private function. * Synopsis: * int AddEncodingFrame( AstFitsChan *this, AstFrameSet *fs, int encoding, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function attempts to create a Frame based on the current Frame * of the supplied FrameSet, which conforms to the requirements of the * specified Encoding. If created, this Frame is added into the * FrameSet as the new current Frame, and the index of the original current * Frame is returned. * Parameters: * this * Pointer to the FitsChan. * fs * Pointer to the FrameSet. * encoding * The encoding in use. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The index of the original current Frame in the FrameSet. A value of * AST__NOFRAME is returned if no new Frame is added to the FrameSet, * or if an error occurs. */ /* Local Variables: */ AstCmpFrame *cmpfrm; /* Pointer to spectral cube frame */ AstFrame *cfrm; /* Pointer to original current Frame */ AstFrame *newfrm; /* Frame describing coord system to be used */ AstFrame *pfrm; /* Pointer to primary Frame containing axis */ AstFrameSet *fsconv; /* FrameSet converting what we have to what we want */ AstMapping *map; /* Mapping from what we have to what we want */ AstSkyFrame *skyfrm; /* Pointer to SkyFrame */ AstSpecFrame *specfrm; /* Pointer to SpecFrame */ AstSystemType sys; /* Frame coordinate system */ int i; /* Axis index */ int naxc; /* No. of axes in original current Frame */ int paxis; /* Axis index in primary frame */ int result; /* Returned value */ /* Initialise */ result = AST__NOFRAME; /* Check the inherited status. */ if( !astOK ) return result; /* Get a pointer to the current Frame and note how many axes it has. */ cfrm = astGetFrame( fs, AST__CURRENT ); naxc = astGetNaxes( cfrm ); /* FITS-CLASS */ /* ========== */ if( encoding == FITSCLASS_ENCODING ) { /* Try to locate a SpecFrame and a SkyFrame in the current Frame. */ specfrm = NULL; skyfrm = NULL; for( i = 0; i < naxc; i++ ) { astPrimaryFrame( cfrm, i, &pfrm, &paxis ); if( astIsASpecFrame( pfrm ) ) { if( !specfrm ) specfrm = astCopy( pfrm ); } else if( astIsASkyFrame( pfrm ) ) { if( !skyfrm ) skyfrm = astCopy( pfrm ); } pfrm = astAnnul( pfrm ); } /* Cannot do anything if either is missing. */ if( specfrm && skyfrm ) { /* If the spectral axis is not frequency, set it to frequency. Also set spectral units of "Hz". */ sys = astGetSystem( specfrm ); if( sys != AST__FREQ ) { astSetSystem( specfrm, AST__FREQ ); sys = AST__FREQ; } /* Ensure the standard of rest is Source and units are "Hz". */ astSetUnit( specfrm, 0, "Hz" ); astSetStdOfRest( specfrm, AST__SCSOR ); /* The celestial axes must be either FK4, FK5 or galactic. */ sys = astGetSystem( skyfrm ); if( sys != AST__FK4 && sys != AST__FK5 && sys != AST__GALACTIC ) { astSetSystem( skyfrm, AST__FK5 ); sys = AST__FK5; } /* FK5 systems must be J2000, and FK4 must be B1950. */ if( sys == AST__FK5 ) { astSetC( skyfrm, "Equinox", "J2000.0" ); } else if( sys == AST__FK4 ) { astSetC( skyfrm, "Equinox", "B1950.0" ); } /* Combine the spectral and celestial Frames into a single CmpFrame with the spectral axis being the first axis. */ cmpfrm = astCmpFrame( specfrm, skyfrm, "", status ); /* Attempt to obtain the current Frame of the supplied FrameSet to this new Frame. */ fsconv = astConvert( cfrm, cmpfrm, "" ); if( fsconv ) { /* Get the Mapping and current Frame from the rconversion FrameSet. */ newfrm = astGetFrame( fsconv, AST__CURRENT ); map = astGetMapping( fsconv, AST__BASE, AST__CURRENT ); /* Save the original current Frame index. */ result = astGetCurrent( fs ); /* Add the new Frame into the supplied FrameSet using the above Mapping to connect it to the original current Frame. The new Frame becomes the current Frame. */ astAddFrame( fs, AST__CURRENT, map, newfrm ); /* Free resources */ map = astAnnul( map ); newfrm = astAnnul( newfrm ); fsconv = astAnnul( fsconv ); } /* Free resources */ cmpfrm = astAnnul( cmpfrm ); } /* Release resources. */ if( specfrm ) specfrm = astAnnul( specfrm ); if( skyfrm ) skyfrm = astAnnul( skyfrm ); } /* Free reources. */ cfrm = astAnnul( cfrm ); /* Return the result */ return result; } static void AddFrame( AstFitsChan *this, AstFrameSet *fset, int pixel, int npix, FitsStore *store, char s, const char *method, const char *class, int *status ){ /* * Name: * AddFrame * Purpose: * Create a Frame describing a set of axes with a given co-ordinate * version, and add it to the supplied FrameSet. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void AddFrame( AstFitsChan *this, AstFrameSet *fset, int pixel, * int npix, FitsStore *store, char s, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A Frame is created describing axis with a specific co-ordinate * version character, reading information from the supplied FitsStore. * A suitable Mapping is created to connect the new Frame to the pixel * (GRID) Frame in the supplied FrameSet, and the Frame is added into * the FrameSet using this Mapping. * Parameters: * this * The FitsChan from which the keywords were read. Warning messages * are added to this FitsChan if the celestial co-ordinate system is * not recognized. * fset * Pointer to the FrameSet to be extended. * pixel * The index of the pixel (GRID) Frame within fset. * npix * The number of pixel axes. * store * The FitsStore containing the required information extracted from * the FitsChan. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *frame; /* Requested Frame */ AstMapping *mapping; /* Mapping from pixel to requested Frame */ AstMapping *tmap; /* Temporary Mapping pointer */ AstPermMap *pmap; /* PermMap pointer to add or remove axes */ double con; /* Value to be assigned to missing axes */ int *inperm; /* Pointer to input axis permutation array */ int *outperm; /* Pointer to output axis permutation array */ int i; /* Axis index */ int nwcs; /* Number of wcs axes */ /* Check the inherited status. */ if( !astOK ) return; /* Get a Mapping between pixel coordinates and physical coordinates, using the requested axis descriptions. Also returns a Frame describing the physical coordinate system. */ mapping = WcsMapFrm( this, store, s, &frame, method, class, status ); /* Add the Frame into the FrameSet, and annul the mapping and frame. If the new Frame has more axes than the pixel Frame, use a PermMap which assigns constant value 1.0 to the extra axes. If the new Frame has less axes than the pixel Frame, use a PermMap which throws away the extra axes. */ if( mapping != NULL ) { nwcs = astGetNin( mapping ); if( nwcs != npix ) { inperm = astMalloc( sizeof(int)*(size_t)npix ); outperm = astMalloc( sizeof(int)*(size_t)nwcs ); if( astOK ) { for( i = 0; i < npix; i++ ) { inperm[ i ] = ( i < nwcs ) ? i : -1; } for( i = 0; i < nwcs; i++ ) { outperm[ i ] = ( i < npix ) ? i : -1; } con = 1.0; pmap = astPermMap( npix, inperm, nwcs, outperm, &con, "", status ); tmap = (AstMapping *) astCmpMap( pmap, mapping, 1, "", status ); pmap = astAnnul( pmap ); (void) astAnnul( mapping ); mapping = tmap; } inperm = astFree( inperm ); outperm = astFree( outperm ); } astAddFrame( fset, pixel, mapping, frame ); /* Annul temporary resources. */ mapping = astAnnul( mapping ); } frame = astAnnul( frame ); } static int AddVersion( AstFitsChan *this, AstFrameSet *fs, int ipix, int iwcs, FitsStore *store, double *dim, char s, int encoding, int isoff, const char *method, const char *class, int *status ){ /* * Name: * AddVersion * Purpose: * Add values to a FitsStore describing a specified Frame in a FrameSet. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int AddVersion( AstFitsChan *this, AstFrameSet *fs, int ipix, int iwcs, * FitsStore *store, double *dim, char s, int encoding, * int isoff, const char *method, const char *class, * int *status ) * Class Membership: * FitsChan member function. * Description: * Values are added to the supplied FitsStore describing the specified * WCS Frame, and its relationship to the specified pixel Frame. These * values are based on the standard FITS-WCS conventions. * Parameters: * this * Pointer to the FitsChan. * fs * Pointer to the FrameSet. * ipix * The index of the pixel (GRID) Frame within fset. * iwcs * The index of the Frame within fset to use as the WCS co-ordinate * Frame. * store * The FitsStore in which to store the information extracted from * the FrameSet. * dim * Pointer to an array of pixel axis dimensions. Individual elements * will be AST__BAD if dimensions are not known. The number of * elements should equal the number of axes in the base Frame of the * supplied FrameSet. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * encoding * The encoding being used. * isoff * If greater than zero, the Frame is an offset SkyFrame and the * description added to the FitsStore should describe offset coordinates. * If less than than zero, the Frame is an offset SkyFrame and the * description added to the FitsStore should describe absolute coordinates. * If zero, the Frame is an absolute SkyFrame and the description added * to the FitsSTore should (by necessity) describe absolute coordinates. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Retuned Value: * A value of 1 is returned if the WCS Frame was succesfully added to * the FitsStore. A value of zero is returned otherwise. */ /* Local Variables: */ AstFrame *wcsfrm; /* WCS Frame */ AstFrameSet *fset; /* Temporary FrameSet */ AstMapping *iwcmap; /* Mapping from WCS to IWC Frame */ AstMapping *mapping; /* Mapping from pixel to WCS Frame */ AstMapping *pixiwcmap; /* Mapping from pixel to IWC Frame */ AstMapping *tmap2; /* Temporary Mapping */ AstMapping *tmap; /* Temporary Mapping */ const char *old_skyrefis;/* Old value of SkyRefIs attribute */ double *crvals; /* Pointer to array holding default CRVAL values */ double cdelt2; /* Sum of squared PC values */ double cdelt; /* CDELT value for axis */ double crpix; /* CRPIX value for axis */ double crval; /* CRVAL value for axis */ double pc; /* Element of the PC array */ int *axis_done; /* Flags indicating which axes have been done */ int *wperm; /* FITS axis for each Mapping output (Frame axis) */ int fits_i; /* FITS WCS axis index */ int fits_j; /* FITS pixel axis index */ int iax; /* Frame axis index */ int icurr; /* Index of current Frame */ int nwcs; /* No. of axes in WCS frame */ int ret; /* Returned value */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* If the frame is a SkyFrame describing offset coordinates, but the description added to the FitsStore should be for absolute coordinates, temporarily clear the SkyFrame SkyRefIs attribute. We need to make it the current Frame first so that we can use the FrameSet to clear the attribte, so that the SkyFrame will be re-mapped within the FrameSet to take account of the clearing. For negative isoff values, set the specific negative value to indicate the original SkyRefIs value. */ if( isoff < 0 ) { icurr = astGetCurrent( fs ); astSetCurrent( fs, iwcs ); old_skyrefis = astGetC( fs, "SkyRefIs" ); if( astOK ) { if( !Ustrcmp( old_skyrefis, "POLE", status ) ) { isoff = -1; } else if( !Ustrcmp( old_skyrefis, "ORIGIN", status ) ) { isoff = -2; } else { isoff = -3; } } astClear( fs, "SkyRefIs" ); astSetCurrent( fs, icurr ); } else { old_skyrefis = AST__BAD_REF; } /* Construct a new FrameSet holding the pixel and WCS Frames from the supplied FrameSet, but in which the current Frame is a copy of the supplied WCS Frame, but optionally extended to include any extra axes needed to conform to the FITS model. For instance, if the WCS Frame consists of a single 1D SpecFrame with a defined celestial reference position (SpecFrame attributes RefRA and RefDec), then FITS-WCS paper III requires there to be a pair of celestial axes in the WCS Frame in which the celestial reference point for the spectral axis is defined. */ fset = MakeFitsFrameSet( this, fs, ipix, iwcs, encoding, method, class, status ); /* If required, re-instate the original value of the SkyRefIs attribute in the supplied FrameSet. */ if( old_skyrefis != AST__BAD_REF ) { astSetCurrent( fs, iwcs ); astSetC( fs, "SkyRefIs", old_skyrefis ); astSetCurrent( fs, icurr ); } /* Abort if the FrameSet could not be produced. */ if( !fset ) return ret; /* Get the Mapping from base to current Frame and check its inverse is defined. Return if not. Note, we can handle non-invertable Mappings if we are allowed to use the -TAB algorithm. */ mapping = astGetMapping( fset, AST__BASE, AST__CURRENT ); if( !astGetTranInverse( mapping ) && astGetTabOK( this ) <= 0 ) { mapping = astAnnul( mapping ); fset = astAnnul( fset ); return ret; } /* We now need to choose the "FITS WCS axis" (i.e. the number that is included in FITS keywords such as CRVAL2) for each axis of the output Frame. For each WCS axis, we use the index of the pixel axis which is most closely aligned with it. Allocate memory to store these indices, and then fill the memory. */ nwcs= astGetNout( mapping ); wperm = astMalloc( sizeof(int)*(size_t) nwcs ); if( ! WorldAxes( this, mapping, dim, wperm, status ) ) { wperm = astFree( wperm ); mapping = astAnnul( mapping ); fset = astAnnul( fset ); return ret; } /* Allocate an array of flags, one for each axis, which indicate if a description of the corresponding axis has yet been stored in the FitsStore. Initialise them to indicate that no axes have yet been described. */ axis_done = astMalloc( sizeof(int)*(size_t) nwcs ); if( astOK ) for( iax = 0; iax < nwcs; iax++ ) axis_done[ iax ] = 0; /* Get the original reference point from the FitsChan and convert it into the require WCS Frame. This is used as the default reference point (some algorithms may choose to ignore this default reference point ). */ wcsfrm = astGetFrame( fset, AST__CURRENT ); crvals = ReadCrval( this, wcsfrm, s, method, class, status ); /* For each class of FITS conventions (celestial, spectral, others), identify any corresponding axes within the WCS Frame and add descriptions of them to the FitsStore. These descriptions are in terms of the FITS keywords defined in the corresponding FITS-WCS paper. Note, the keywords which descirbed the pixel->IWC mapping (CRPIX, CD, PC, CDELT) are not stored by these functions, instead each function returns a Mapping from WCS to IWC coords (these Mappings pass on axes of the wrong class without change). These Mappings are combined in series to get the final WCS->IWC Mapping. First do celestial axes. */ iwcmap = CelestialAxes( this, fset, dim, wperm, s, store, axis_done, isoff, method, class, status ); /* Now look for spectral axes, and update the iwcmap. */ tmap = SpectralAxes( this, fset, dim, wperm, s, store, crvals, axis_done, method, class, status ); tmap2 = (AstMapping *) astCmpMap( iwcmap, tmap, 1, "", status ); tmap = astAnnul( tmap ); (void) astAnnul( iwcmap ); iwcmap = tmap2; /* Finally add descriptions of any axes not yet described (they are assumed to be linear), and update the iwcmap. */ tmap = OtherAxes( this, fset, dim, wperm, s, store, crvals, axis_done, method, class, status ); tmap2 = (AstMapping *) astCmpMap( iwcmap, tmap, 1, "", status ); tmap = astAnnul( tmap ); (void) astAnnul( iwcmap ); iwcmap = tmap2; /* The "iwcmap" Mapping found above converts from the WCS Frame to the IWC Frame. Combine the pixel->WCS Mapping with this WCS->IWC Mapping to get the pixel->IWC Mapping. */ pixiwcmap = (AstMapping *) astCmpMap( mapping, iwcmap, 1, "", status ); mapping = astAnnul( mapping ); iwcmap = astAnnul( iwcmap ); /* Now attempt to store values for the keywords describing the pixel->IWC Mapping (CRPIX, CD, PC, CDELT). This tests that the iwcmap is linear. Zero is returned if the test fails. */ ret = MakeIntWorld( pixiwcmap, wcsfrm, wperm, s, store, dim, method, class, status ); /* If succesfull... */ if( ret ) { /* Store the Domain name as the WCSNAME keyword (if set). */ if( astTestDomain( wcsfrm ) ) { SetItemC( &(store->wcsname), 0, 0, s, (char *) astGetDomain( wcsfrm ), status ); } /* Store the UT1-UTC correction, if set, converting from seconds to days (as used by JACH). */ if( astTestDut1( wcsfrm ) && s == ' ' ) { SetItem( &(store->dut1), 0, 0, ' ', astGetDut1( wcsfrm )/SPD, status ); } /* Set CRVAL values which are very small compared to the pixel size to zero. */ for( iax = 0; iax < nwcs; iax++ ) { fits_i = wperm[ iax ]; crval = GetItem( &(store->crval), fits_i, 0, s, NULL, method, class, status ); if( crval != AST__BAD ) { cdelt2 = 0.0; for( fits_j = 0; fits_j < nwcs; fits_j++ ){ pc = GetItem( &(store->pc), fits_i, fits_j, s, NULL, method, class, status ); if( pc == AST__BAD ) pc = ( fits_i == fits_j ) ? 1.0 : 0.0; cdelt2 += pc*pc; } cdelt = GetItem( &(store->cdelt), fits_i, 0, s, NULL, method, class, status ); if( cdelt == AST__BAD ) cdelt = 1.0; cdelt2 *= ( cdelt*cdelt ); if( fabs( crval ) < sqrt( DBL_EPSILON*cdelt2 ) ) { SetItem( &(store->crval), fits_i, 0, s, 0.0, status ); } } } /* Round CRPIX values to the nearest millionth of a pixel. */ for( iax = 0; iax < nwcs; iax++ ) { crpix = GetItem( &(store->crpix), 0, iax, s, NULL, method, class, status ); if( crpix != AST__BAD ) { SetItem( &(store->crpix), 0, iax, s, floor( crpix*1.0E6 + 0.5 )*1.0E-6, status ); } } } /* Free remaining resources. */ if( crvals ) crvals = astFree( crvals ); wcsfrm = astAnnul( wcsfrm ); pixiwcmap = astAnnul( pixiwcmap ); axis_done = astFree( axis_done ); wperm = astFree( wperm ); fset = astAnnul( fset ); /* If an error has occurred, return zero */ return astOK ? ret : 0; } static AstMapping *AddUnitMaps( AstMapping *map, int iax, int nax, int *status ) { /* * Name: * AddUnitMaps * Purpose: * Embed a Mapping within a pair of parallel UnitMaps. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *AddUnitMaps( AstMapping *map, int iax, int nax, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a Mapping which consists of the supplied Mapping * in parallel with a pair of UnitMaps so that the first axis of the * supplied Mapping is at a specified axis number in the returned Mapping. * Parameters: * map * Pointer to the Mapping. The Mapping must have equal numbers of * input and output coordinates. * iax * The index for the first input of "map" within the returned * Mapping. * nax * The number of axes for the returned Mapping. * status * Pointer to the inherited status variable. * Returned Value: * A Mapping which has "nax" axes, and in which the "iax" axis * corresponds to the first axis of "map". Axes lower than "iax" are * transformed using a UnitMap, and axes higher than the last axis of * "map" are transformed using a UnitMap. */ /* Local Variables: */ AstMapping *ret; /* Returned Mapping */ AstMapping *tmap0; /* Temporary Mapping */ AstMapping *tmap1; /* Temporary Mapping */ AstMapping *tmap2; /* Temporary Mapping */ int nmap; /* Number of supplied Mapping inputs */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Initialise the returned Mapping to be a clone of the supplied Mapping. */ ret = astClone( map ); /* Note the number of inputs of the supplied Mapping (assumed to be equal to the number of outputs). */ nmap = astGetNin( map ); /* If necessary produce a parallel CmpMap which combines the Mapping with a UnitMap representing the axes lower than "iax". */ if( iax > 0 ) { tmap0 = (AstMapping *) astUnitMap( iax, "", status ); tmap1 = (AstMapping *) astCmpMap( tmap0, ret, 0, "", status ); ret = astAnnul( ret ); tmap0 = astAnnul( tmap0 ); ret = tmap1; } /* If necessary produce a parallel CmpMap which combines the Mapping with a UnitMap representing the axes higher than "iax+nmap". */ if( iax + nmap < nax ) { tmap1 = (AstMapping *) astUnitMap( nax - iax - nmap, "", status ); tmap2 = (AstMapping *) astCmpMap( ret, tmap1, 0, "", status ); ret = astAnnul( ret ); tmap1 = astAnnul( tmap1 ); ret = tmap2; } /* Return the result. */ return ret; } static int AIPSFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * AIPSFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-AIPS encoding. * Type: * Private function. * Synopsis: * int AIPSFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-AIPS encoding. * * AIPS encoding is like FITS-WCS encoding but with the following * restrictions: * * 1) The celestial projection must not have any projection parameters * which are not set to their default values. The one exception to this * is that SIN projections are acceptable if the associated projection * parameter PV_1 is zero and PV_2 = cot( reference point * latitude). This is encoded using the string "-NCP". The SFL projection * is encoded using the string "-GLS". Note, the original AIPS WCS * system only recognised a small subset of the currently available * projections, but some more recent AIPS-like software recognizes some * of the new projections included in the FITS-WCS encoding. The AIT, * GLS and MER can only be written if the CRVAL keywords are zero for * both longitude and latitude axes. * * 2) The celestial axes must be RA/DEC, galactic or ecliptic. * * 3) LONPOLE and LATPOLE must take their default values. * * 4) Only primary axis descriptions are written out. * * 5) EPOCH is written instead of EQUINOX & RADECSYS, and uses the * IAU 1984 rule ( EPOCH < 1984.0 is treated as a Besselian epoch * and implies RADECSYS=FK4, EPOCH >= 1984.0 is treated as a * Julian epoch and implies RADECSYS=FK5). The RADECSYS & EQUINOX * values in the FitsStore must be consistent with this rule. * * 6) Any rotation produced by the PC matrix must be restricted to * the celestial plane, and must involve no shear. A CROTA keyword * with associated CDELT values are produced instead of the PC * matrix. * * 7) ICRS is not supported. * * 8) Spectral axes can be created only for FITS-WCS CTYPE values of "FREQ" * "VRAD" and "VOPT-F2W" and with standards of rest of LSRK, LSRD, * BARYCENT and GEOCENTR. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ char *comm; /* Pointer to comment string */ const char *cval; /* Pointer to string keyword value */ const char *specunit;/* Pointer to corrected spectral units string */ char combuf[80]; /* Buffer for FITS card comment */ char lattype[MXCTYPELEN];/* Latitude axis CTYPE */ char lontype[MXCTYPELEN];/* Longitude axis CTYPE */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ char spectype[MXCTYPELEN];/* Spectral axis CTYPE */ double *cdelt; /* Pointer to CDELT array */ double cdl; /* CDELT term */ double cdlat_lon; /* Off-diagonal CD element */ double cdlon_lat; /* Off-diagonal CD element */ double coscro; /* Cos( CROTA ) */ double crota; /* CROTA value to use */ double epoch; /* Epoch of reference equinox */ double fd; /* Fraction of a day */ double latval; /* CRVAL for latitude axis */ double lonval; /* CRVAL for longitude axis */ double mjd99; /* MJD at start of 1999 */ double p1, p2; /* Projection parameters */ double rho_a; /* First estimate of CROTA */ double rho_b; /* Second estimate of CROTA */ double sincro; /* Sin( CROTA ) */ double specfactor; /* Factor for converting internal spectral units */ double val; /* General purpose value */ int axlat; /* Index of latitude FITS WCS axis */ int axlon; /* Index of longitude FITS WCS axis */ int axrot1; /* Index of first CROTA rotation axis */ int axrot2; /* Index of second CROTA rotation axis */ int axspec; /* Index of spectral FITS WCS axis */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int naxis; /* No. of axes */ int ok; /* Is FitsSTore OK for IRAF encoding? */ int prj; /* Projection type */ /* Check the inherited status. */ if( !astOK ) return 0; /* Initialise */ specunit = ""; specfactor = 1.0; /* First check that the values in the FitsStore conform to the requirements of the AIPS encoding. Assume they do to begin with. */ ok = 1; /* Just do primary axes. */ s = ' '; /* Look for the primary celestial axes. */ FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status ); /* If both longitude and latitude axes are present ...*/ if( axlon >= 0 && axlat >= 0 ) { /* Get the CRVAL values for both axes. */ latval = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status ); if( latval == AST__BAD ) ok = 0; lonval = GetItem( &( store->crval ), axlon, 0, s, NULL, method, class, status ); if( lonval == AST__BAD ) ok = 0; /* Get the CTYPE values for both axes. Extract the projection type as specified by the last 4 characters in the latitude CTYPE keyword value. */ cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { strcpy( lontype, cval ); } cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; prj = AST__WCSBAD; } else { strcpy( lattype, cval ); prj = astWcsPrjType( cval + 4 ); } /* Check the projection type is OK. */ if( prj == AST__WCSBAD ){ ok = 0; } else if( prj != AST__SIN ){ /* There must be no projection parameters. */ if( GetMaxJM( &(store->pv), ' ', status ) >= 0 ) { ok = 0; /* FITS-AIPS cannot handle the AST-specific TPN projection. */ } else if( prj == AST__TPN ) { ok = 0; /* For AIT, MER and GLS, check that the reference point is the origin of the celestial co-ordinate system. */ } else if( prj == AST__MER || prj == AST__AIT || prj == AST__SFL ) { if( latval != 0.0 || lonval != 0.0 ){ ok = 0; /* Change the new SFL projection code to to the older equivalent GLS */ } else if( prj == AST__SFL ){ (void) strcpy( lontype + 4, "-GLS" ); (void) strcpy( lattype + 4, "-GLS" ); } } /* SIN projections are only acceptable if the associated projection parameters are both zero, or if the first is zero and the second = cot( reference point latitude ) (the latter case is equivalent to the old NCP projection). */ } else { p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status ); p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status ); if( p1 == AST__BAD ) p1 = 0.0; if( p2 == AST__BAD ) p2 = 0.0; ok = 0; if( p1 == 0.0 ) { if( p2 == 0.0 ) { ok = 1; } else if( fabs( p2 ) >= 1.0E14 && latval == 0.0 ){ ok = 1; (void) strcpy( lontype + 4, "-NCP" ); (void) strcpy( lattype + 4, "-NCP" ); } else if( fabs( p2*tan( AST__DD2R*latval ) - 1.0 ) < 0.01 ){ ok = 1; (void) strcpy( lontype + 4, "-NCP" ); (void) strcpy( lattype + 4, "-NCP" ); } } } /* Identify the celestial coordinate system from the first 4 characters of the longitude CTYPE value. Only RA, galactic longitude, and ecliptic longitude can be stored using FITS-AIPS. */ if( ok && strncmp( lontype, "RA--", 4 ) && strncmp( lontype, "GLON", 4 ) && strncmp( lontype, "ELON", 4 ) ) ok = 0; /* If the physical Frame requires a LONPOLE or LATPOLE keyword, it cannot be encoded using FITS-IRAF. */ if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ) != AST__BAD || GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ) != AST__BAD ) ok = 0; } /* If a spectral axis is present ...*/ if( ok && axspec >= 0 ) { /* Get the CTYPE values for the axis, and find the AIPS equivalent, if possible. */ cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) { strcpy( spectype, "FREQ" ); } else if( !strncmp( cval, "VRAD", astChrLen( cval ) ) ) { strcpy( spectype, "VELO" ); } else if( !strncmp( cval, "VOPT-F2W", astChrLen( cval ) ) ) { strcpy( spectype, "FELO" ); } else { ok = 0; } } /* If OK, check the SPECSYS value and add the AIPS equivalent onto the end of the CTYPE value.*/ cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else if( ok ) { if( !strncmp( cval, "LSRK", astChrLen( cval ) ) ) { strcpy( spectype+4, "-LSR" ); } else if( !strncmp( cval, "LSRD", astChrLen( cval ) ) ) { strcpy( spectype+4, "-LSD" ); } else if( !strncmp( cval, "BARYCENT", astChrLen( cval ) ) ) { strcpy( spectype+4, "-HEL" ); } else if( !strncmp( cval, "GEOCENTR", astChrLen( cval ) ) ) { strcpy( spectype+4, "-GEO" ); } else { ok = 0; } } /* If still OK, ensure the spectral axis units are Hz or m/s. */ cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else if( ok ) { if( !strcmp( cval, "Hz" ) ) { specunit = "HZ"; specfactor = 1.0; } else if( !strcmp( cval, "kHz" ) ) { specunit = "HZ"; specfactor = 1.0E3; } else if( !strcmp( cval, "MHz" ) ) { specunit = "HZ"; specfactor = 1.0E6; } else if( !strcmp( cval, "GHz" ) ) { specunit = "HZ"; specfactor = 1.0E9; } else if( !strcmp( cval, "m/s" ) ) { specunit = "m/s"; specfactor = 1.0; } else if( !strcmp( cval, "km/s" ) ) { specunit = "m/s"; specfactor = 1.0E3; } else { ok = 0; } } } /* Save the number of axes */ naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1; /* If this is different to the value of NAXIS abort since this encoding does not support WCSAXES keyword. */ if( naxis != store->naxis ) ok = 0; /* Allocate memory to store the CDELT values */ if( ok ) { cdelt = (double *) astMalloc( sizeof(double)*naxis ); if( !cdelt ) ok = 0; } else { cdelt = NULL; } /* Check that rotation is restricted to the celestial plane, and extract the CDELT (diagonal) terms, etc. If there are no celestial axes, restrict rotation to the first two non-spectral axes. */ if( axlat < 0 && axlon < 0 ) { if( axspec >= 0 && naxis > 2 ) { axrot2 = ( axspec == 0 ) ? 1 : 0; axrot1 = axrot2 + 1; if( axrot1 == axspec ) axrot1++; } else if( naxis > 1 ){ axrot2 = 0; axrot1 = 1; } else { axrot2 = -1; axrot1 = -1; } } else { axrot1 = axlon; axrot2 = axlat; } cdlat_lon = 0.0; cdlon_lat = 0.0; for( i = 0; i < naxis && ok; i++ ){ cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdl == AST__BAD ) cdl = 1.0; for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdl; if( i == j ){ cdelt[ i ] = val; } else if( i == axrot2 && j == axrot1 ){ cdlat_lon = val; } else if( i == axrot1 && j == axrot2 ){ cdlon_lat = val; } else if( val != 0.0 ){ ok = 0; } } } /* Find the CROTA and CDELT values for the celestial axes. */ if( ok && axrot1 >= 0 && axrot2 >= 0 ) { if( cdlat_lon > 0.0 ) { rho_a = atan2( cdlat_lon, cdelt[ axrot1 ] ); } else if( cdlat_lon == 0.0 ) { rho_a = 0.0; } else { rho_a = atan2( -cdlat_lon, -cdelt[ axrot1 ] ); } if( cdlon_lat > 0.0 ) { rho_b = atan2( cdlon_lat, -cdelt[ axrot2 ] ); } else if( cdlon_lat == 0.0 ) { rho_b = 0.0; } else { rho_b = atan2( -cdlon_lat, cdelt[ axrot2 ] ); } if( fabs( palDrange( rho_a - rho_b ) ) < 1.0E-2 ){ crota = 0.5*( palDranrm( rho_a ) + palDranrm( rho_b ) ); coscro = cos( crota ); sincro = sin( crota ); if( fabs( coscro ) > fabs( sincro ) ){ cdelt[ axrot2 ] /= coscro; cdelt[ axrot1 ] /= coscro; } else { cdelt[ axrot2 ] = -cdlon_lat/sincro; cdelt[ axrot1 ] = cdlat_lon/sincro; } crota *= AST__DR2D; } else { ok = 0; } } else { crota = 0.0; } /* Get RADECSYS and the reference equinox (called EPOCH in FITS-AIPS). */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); epoch = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); /* If RADECSYS was available... */ if( cval ){ /* ICRS is not supported in this encoding. */ if( !strcmp( "ICRS", cval ) ) ok = 0; /* If epoch was not available, set a default epoch. */ if( epoch == AST__BAD ){ if( !strcmp( "FK4", cval ) ){ epoch = 1950.0; } else if( !strcmp( "FK5", cval ) ){ epoch = 2000.0; } else { ok = 0; } /* If an epoch was supplied, check it is consistent with the IAU 1984 rule. */ } else { if( !strcmp( "FK4", cval ) ){ if( epoch >= 1984.0 ) ok = 0; } else if( !strcmp( "FK5", cval ) ){ if( epoch < 1984.0 ) ok = 0; } else { ok = 0; } } } /* Only create the keywords if the FitsStore conforms to the requirements of the FITS-AIPS encoding. */ if( ok ) { /* Get and save CRPIX for all pixel axes. These are required, so break if they are not available. */ for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { sprintf( combuf, "Reference pixel on axis %d", j + 1 ); SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CRVAL for all intermediate axes. These are required, so break if they are not available. */ for( i = 0; i < naxis && ok; i++ ){ val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { if( i == axspec ) val *= specfactor; sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CTYPE for all intermediate axes. These are required, so break if they are not available. Use the potentially modified versions saved above for the celestial axes. */ for( i = 0; i < naxis && ok; i++ ){ if( i == axlat ) { cval = lattype; } else if( i == axlon ) { cval = lontype; } else if( i == axspec ) { cval = spectype; } else { cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); } if( cval && strcmp( cval + 4, "-TAB" ) ) { comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING, comm, status ); } else { ok = 0; } } /* CDELT values */ if( axspec != -1 ) cdelt[ axspec ] *= specfactor; for( i = 0; i < naxis; i++ ){ SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i, AST__FLOAT, "Pixel size", status ); } /* CUNIT values. */ for( i = 0; i < naxis; i++ ) { cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( cval ) { if( i == axspec ) cval = specunit; sprintf( combuf, "Units for axis %d", i + 1 ); SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING, combuf, status ); } } /* CROTA */ if( axrot2 != -1 ){ SetValue( this, FormatKey( "CROTA", axrot2 + 1, -1, s, status ), &crota, AST__FLOAT, "Axis rotation", status ); } else if( ( axspec == -1 && naxis > 1 ) || ( axspec != -1 && naxis > 2 ) ) { SetValue( this, "CROTA1", &crota, AST__FLOAT, "Axis rotation", status ); } /* Reference equinox */ if( epoch != AST__BAD ) SetValue( this, "EPOCH", &epoch, AST__FLOAT, "Epoch of reference equinox", status ); /* Date of observation. */ val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD ) { /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING, "Date of observation", status ); } /* Spectral stuff.. */ if( axspec >= 0 ) { /* Rest frequency */ val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFREQ", -1, -1, s, status ), &val, AST__FLOAT, "[Hz] Rest frequency", status ); } } /* Release CDELT workspace */ if( cdelt ) cdelt = (double *) astFree( (void *) cdelt ); /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ok : 0; } static int AIPSPPFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * AIPSPPFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-AIPS++ encoding. * Type: * Private function. * Synopsis: * int AIPSPPFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-AIPS++ encoding. * * AIPS++ encoding is like FITS-WCS encoding but with the following * restrictions: * * 1) The celestial axes must be RA/DEC, galactic or ecliptic. * * 2) Only primary axis descriptions are written out. * * 3) RADESYS is not written and so the RADECSYS & EQUINOX values in the * FitsStore must be consistent with the "1984" rule. * * 4) Any rotation produced by the PC matrix must be restricted to * the celestial plane, and must involve no shear. A CROTA keyword * with associated CDELT values are produced instead of the PC * matrix. * * 5) ICRS is not supported. * * 6) Spectral axes can be created only for FITS-WCS CTYPE values of "FREQ" * "VRAD" and "VOPT-F2W" and with standards of rest of LSRK, LSRD, * BARYCENT and GEOCENTR. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ char *comm; /* Pointer to comment string */ const char *cval; /* Pointer to string keyword value */ const char *specunit;/* Pointer to corrected spectral units string */ char combuf[80]; /* Buffer for FITS card comment */ char lattype[MXCTYPELEN];/* Latitude axis CTYPE */ char lontype[MXCTYPELEN];/* Longitude axis CTYPE */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ char spectype[MXCTYPELEN];/* Spectral axis CTYPE */ double *cdelt; /* Pointer to CDELT array */ double cdl; /* CDELT term */ double cdlat_lon; /* Off-diagonal CD element */ double cdlon_lat; /* Off-diagonal CD element */ double coscro; /* Cos( CROTA ) */ double crota; /* CROTA value to use */ double epoch; /* Epoch of reference equinox */ double fd; /* Fraction of a day */ double mjd99; /* MJD at start of 1999 */ double rho_a; /* First estimate of CROTA */ double rho_b; /* Second estimate of CROTA */ double sincro; /* Sin( CROTA ) */ double specfactor; /* Factor for converting internal spectral units */ double val; /* General purpose value */ int axlat; /* Index of latitude FITS WCS axis */ int axlon; /* Index of longitude FITS WCS axis */ int axrot1; /* Index of first CROTA rotation axis */ int axrot2; /* Index of second CROTA rotation axis */ int axspec; /* Index of spectral FITS WCS axis */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int m; /* Projection parameter index */ int maxm; /* Max projection parameter index */ int naxis; /* No. of axes */ int ok; /* Is FitsSTore OK for IRAF encoding? */ int prj; /* Projection type */ /* Check the inherited status. */ if( !astOK ) return 0; /* Initialise */ specunit = ""; specfactor = 1.0; maxm = 0; /* First check that the values in the FitsStore conform to the requirements of the AIPS++ encoding. Assume they do to begin with. */ ok = 1; /* Just do primary axes. */ s = ' '; /* Save the number of axes */ naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1; /* Look for the primary celestial and spectral axes. */ FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status ); /* If both longitude and latitude axes are present ...*/ if( axlon >= 0 && axlat >= 0 ) { /* Get the CTYPE values for both axes. Extract the projection type as specified by the last 4 characters in the latitude CTYPE keyword value. */ cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { strcpy( lontype, cval ); } cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; prj = AST__WCSBAD; } else { strcpy( lattype, cval ); prj = astWcsPrjType( cval + 4 ); } /* FITS-AIPS++ cannot handle the AST-specific TPN projection. */ if( prj == AST__TPN || prj == AST__WCSBAD ) ok = 0; /* Projection parameters. FITS-AIPS++ encoding ignores projection parameters associated with the longitude axis. The number of parameters is limited to 10. */ maxm = GetMaxJM( &(store->pv), ' ', status ); for( i = 0; i < naxis && ok; i++ ){ if( i != axlon ) { for( m = 0; m <= maxm; m++ ){ val = GetItem( &(store->pv), i, m, s, NULL, method, class, status ); if( val != AST__BAD ) { if( i != axlat || m >= 10 ){ ok = 0; break; } } } } } /* Identify the celestial coordinate system from the first 4 characters of the longitude CTYPE value. Only RA, galactic longitude, and ecliptic longitude can be stored using FITS-AIPS++. */ if( ok && strncmp( lontype, "RA--", 4 ) && strncmp( lontype, "GLON", 4 ) && strncmp( lontype, "ELON", 4 ) ) ok = 0; } /* If a spectral axis is present ...*/ if( axspec >= 0 ) { /* Get the CTYPE values for the axis, and find the AIPS equivalent, if possible. */ cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) { strcpy( spectype, "FREQ" ); } else if( !strncmp( cval, "VRAD", astChrLen( cval ) ) ) { strcpy( spectype, "VELO" ); } else if( !strncmp( cval, "VOPT-F2W", astChrLen( cval ) ) ) { strcpy( spectype, "FELO" ); } else { ok = 0; } } /* If OK, check the SPECSYS value and add the AIPS equivalent onto the end of the CTYPE value.*/ cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { if( !strncmp( cval, "LSRK", astChrLen( cval ) ) ) { strcpy( spectype+4, "-LSR" ); } else if( !strncmp( cval, "LSRD", astChrLen( cval ) ) ) { strcpy( spectype+4, "-LSD" ); } else if( !strncmp( cval, "BARYCENT", astChrLen( cval ) ) ) { strcpy( spectype+4, "-HEL" ); } else if( !strncmp( cval, "GEOCENTR", astChrLen( cval ) ) ) { strcpy( spectype+4, "-GEO" ); } else { ok = 0; } } /* If still OK, ensure the spectral axis units are Hz or m/s. */ cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else if( ok ) { if( !strcmp( cval, "Hz" ) ) { specunit = "HZ"; specfactor = 1.0; } else if( !strcmp( cval, "kHz" ) ) { specunit = "HZ"; specfactor = 1.0E3; } else if( !strcmp( cval, "MHz" ) ) { specunit = "HZ"; specfactor = 1.0E6; } else if( !strcmp( cval, "GHz" ) ) { specunit = "HZ"; specfactor = 1.0E9; } else if( !strcmp( cval, "m/s" ) ) { specunit = "m/s"; specfactor = 1.0; } else if( !strcmp( cval, "km/s" ) ) { specunit = "m/s"; specfactor = 1.0E3; } else { ok = 0; } } } /* If this is different to the value of NAXIS abort since this encoding does not support WCSAXES keyword. */ if( naxis != store->naxis ) ok = 0; /* Allocate memory to store the CDELT values */ if( ok ) { cdelt = (double *) astMalloc( sizeof(double)*naxis ); if( !cdelt ) ok = 0; } else { cdelt = NULL; } /* Check that rotation is restricted to the celestial plane, and extract the CDELT (diagonal) terms, etc. If there are no celestial axes, restrict rotation to the first two non-spectral axes. */ if( axlat < 0 && axlon < 0 ) { if( axspec >= 0 && naxis > 2 ) { axrot2 = ( axspec == 0 ) ? 1 : 0; axrot1 = axrot2 + 1; if( axrot1 == axspec ) axrot1++; } else if( naxis > 1 ){ axrot2 = 0; axrot1 = 1; } else { axrot2 = -1; axrot1 = -1; } } else { axrot1 = axlon; axrot2 = axlat; } cdlat_lon = 0.0; cdlon_lat = 0.0; for( i = 0; i < naxis && ok; i++ ){ cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdl == AST__BAD ) cdl = 1.0; for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdl; if( i == j ){ cdelt[ i ] = val; } else if( i == axrot2 && j == axrot1 ){ cdlat_lon = val; } else if( i == axrot1 && j == axrot2 ){ cdlon_lat = val; } else if( val != 0.0 ){ ok = 0; } } } /* Find the CROTA and CDELT values for the celestial axes. */ if( ok && axrot1 >= 0 && axrot2 >= 0 ) { if( cdlat_lon > 0.0 ) { rho_a = atan2( cdlat_lon, cdelt[ axrot1 ] ); } else if( cdlat_lon == 0.0 ) { rho_a = 0.0; } else { rho_a = atan2( -cdlat_lon, -cdelt[ axrot1 ] ); } if( cdlon_lat > 0.0 ) { rho_b = atan2( cdlon_lat, -cdelt[ axrot2 ] ); } else if( cdlon_lat == 0.0 ) { rho_b = 0.0; } else { rho_b = atan2( -cdlon_lat, cdelt[ axrot2 ] ); } if( fabs( palDrange( rho_a - rho_b ) ) < 1.0E-2 ){ crota = 0.5*( palDranrm( rho_a ) + palDranrm( rho_b ) ); coscro = cos( crota ); sincro = sin( crota ); if( fabs( coscro ) > fabs( sincro ) ){ cdelt[ axrot2 ] /= coscro; cdelt[ axrot1 ] /= coscro; } else { cdelt[ axrot2 ] = -cdlon_lat/sincro; cdelt[ axrot1 ] = cdlat_lon/sincro; } crota *= AST__DR2D; /* Use AST__BAD to indicate that CDi_j values should be produced instead of CROTA/CDELT. (I am told AIPS++ can understand CD matrices) */ } else { crota = AST__BAD; } } else { crota = 0.0; } /* Get RADECSYS and the reference equinox. */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); epoch = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); /* If RADECSYS was available... */ if( cval ){ /* ICRS is not supported in this encoding. */ if( !strcmp( "ICRS", cval ) ) ok = 0; /* If epoch was not available, set a default epoch. */ if( epoch == AST__BAD ){ if( !strcmp( "FK4", cval ) ){ epoch = 1950.0; } else if( !strcmp( "FK5", cval ) ){ epoch = 2000.0; } else { ok = 0; } /* If an equinox was supplied, check it is consistent with the IAU 1984 rule. */ } else { if( !strcmp( "FK4", cval ) ){ if( epoch >= 1984.0 ) ok = 0; } else if( !strcmp( "FK5", cval ) ){ if( epoch < 1984.0 ) ok = 0; } else { ok = 0; } } } /* Only create the keywords if the FitsStore conforms to the requirements of the FITS-AIPS++ encoding. */ if( ok ) { /* Get and save CRPIX for all pixel axes. These are required, so break if they are not available. */ for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { sprintf( combuf, "Reference pixel on axis %d", j + 1 ); SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CRVAL for all intermediate axes. These are required, so break if they are not available. */ for( i = 0; i < naxis && ok; i++ ){ val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { if( i == axspec ) val *= specfactor; sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CTYPE for all intermediate axes. These are required, so break if they are not available. Use the potentially modified versions saved above for the celestial axes. */ for( i = 0; i < naxis && ok; i++ ){ if( i == axlat ) { cval = lattype; } else if( i == axlon ) { cval = lontype; } else if( i == axspec ) { cval = spectype; } else { cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); } if( cval && strcmp( cval + 4, "-TAB" ) ) { comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING, comm, status ); } else { ok = 0; } } /* CDELT values */ if( axspec != -1 ) cdelt[ axspec ] *= specfactor; for( i = 0; i < naxis; i++ ){ SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i, AST__FLOAT, "Pixel size", status ); } /* CUNIT values. [Spectral axis units should be upper-case] */ for( i = 0; i < naxis; i++ ) { cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( cval ) { if( i == axspec ) cval = specunit; sprintf( combuf, "Units for axis %d", i + 1 ); SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING, combuf, status ); } } /* CD matrix. Multiply the row of the PC matrix by the CDELT value. */ if( crota == AST__BAD ) { for( i = 0; i < naxis; i++ ) { cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdl == AST__BAD ) cdl = 1.0; for( j = 0; j < naxis; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdl; if( val != 0.0 ) { SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val, AST__FLOAT, "Transformation matrix element", status ); } } } /* CROTA */ } else if( crota != 0.0 ) { if( axrot2 != -1 ){ SetValue( this, FormatKey( "CROTA", axrot2 + 1, -1, s, status ), &crota, AST__FLOAT, "Axis rotation", status ); } else if( ( axspec == -1 && naxis > 1 ) || ( axspec != -1 && naxis > 2 ) ) { SetValue( this, "CROTA1", &crota, AST__FLOAT, "Axis rotation", status ); } } /* Reference equinox */ if( epoch != AST__BAD ) SetValue( this, "EPOCH", &epoch, AST__FLOAT, "Epoch of reference equinox", status ); /* Latitude of native north pole. */ val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "LATPOLE", &val, AST__FLOAT, "Latitude of native north pole", status ); /* Longitude of native north pole. */ val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "LONPOLE", &val, AST__FLOAT, "Longitude of native north pole", status ); /* Date of observation. */ val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD ) { /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING, "Date of observation", status ); } /* Projection parameters. */ if( axlat >= 0 && axlon >= 0 ) { for( m = 0; m <= maxm; m++ ){ val = GetItem( &(store->pv), axlat, m, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "PROJP", m, -1, ' ', status ), &val, AST__FLOAT, "Projection parameter", status ); } } /* Spectral stuff.. */ if( axspec >= 0 ) { /* Rest frequency */ val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFREQ", -1, -1, s, status ), &val, AST__FLOAT, "[Hz] Rest frequency", status ); } } /* Release CDELT workspace */ if( cdelt ) cdelt = (double *) astFree( (void *) cdelt ); /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ok : 0; } static char *CardComm( AstFitsChan *this, int *status ){ /* * Name: * CardComm * Purpose: * Return the keyword comment from the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *CardComm( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a pointer to a string holding the keyword comment from the * current card. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the keyword comment, or NULL if the FitsChan is at * end-of-file, or does not have a comment. * Notes: * - The current card is not changed by this function. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ char *ret; /* Check the supplied object. */ if( !this ) return NULL; /* If the current card is defined, store a pointer to its keyword comment. */ if( this->card ){ ret = ( (FitsCard *) this->card )->comment; /* Otherwise store a NULL pointer. */ } else { ret = NULL; } /* Return the answer. */ return ret; } static void *CardData( AstFitsChan *this, size_t *size, int *status ){ /* * Name: * CardData * Purpose: * Return a pointer to the keyword data value for the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void *CardData( AstFitsChan *this, size_t *size, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a pointer to keyword data value from the current card. * Parameters: * this * Pointer to the FitsChan. * size * A pointer to a location at which to return the number of bytes * occupied by the data value. NULL can be supplied if this * information is not required. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the keyword data, or NULL if the FitsChan is at * end-of-file, or if the keyword does not have any data. * Notes: * - For text data, the returned value for "size" includes the * terminating null character. * - The current card is not changed by this function. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ void *ret; /* Check the supplied object. */ if( !this ) return NULL; /* If the current card is defined, store a pointer to its keyword data. */ if( this->card ){ ret = ( (FitsCard *) this->card )->data; if( size ) *size = ( (FitsCard *) this->card )->size; /* Otherwise store a NULL pointer. */ } else { ret = NULL; if( size ) *size = 0; } /* Return the answer. */ return ret; } static int *CardFlags( AstFitsChan *this, int *status ){ /* * Name: * CardFlags * Purpose: * Return a pointer to the flags mask for the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int *CardFlags( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a pointer to the flags mask for the current card. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The pointer to the flags mask. * Notes: * - The current card is not changed by this function. * - NULL is returned if the current card is not defined. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ int *ret; /* Check the supplied object. */ if( !this ) return NULL; /* If the current card is defined, store its deletion flag. */ if( this->card ){ ret = &( ( (FitsCard *) this->card )->flags ); /* Otherwise store zero. */ } else { ret = NULL; } /* Return the answer. */ return ret; } static char *CardName( AstFitsChan *this, int *status ){ /* * Name: * CardName * Purpose: * Return the keyword name from the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *CardName( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a pointer to a string holding the keyword name from the * current card. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the keyword name, or NULL if the FitsChan is at * end-of-file. * Notes: * - The current card is not changed by this function. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ char *ret; /* Check the supplied object. */ if( !this ) return NULL; /* If the current card is defined, store a pointer to its keyword name. */ if( this->card ){ ret = ( (FitsCard *) this->card )->name; /* Otherwise store a NULL pointer. */ } else { ret = NULL; } /* Return the answer. */ return ret; } static int CardType( AstFitsChan *this, int *status ){ /* * Name: * CardType * Purpose: * Return the keyword type from the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int CardType( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns the keyword type from the current card. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The keyword type. * Notes: * - The current card is not changed by this function. * - AST__NOTYPE is returned if the current card is not defined. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ int ret; /* Check the supplied object. */ if( !this ) return AST__NOTYPE; /* If the current card is defined, store the keyword type. */ if( this->card ){ ret = ( (FitsCard *) this->card )->type; /* Otherwise store AST__NOTYPE. */ } else { ret = AST__NOTYPE; } /* Return the answer. */ return ret; } static AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *fs, double *dim, int *wperm, char s, FitsStore *store, int *axis_done, int isoff, const char *method, const char *class, int *status ){ /* * Name: * CelestialAxes * Purpose: * Add values to a FitsStore describing celestial axes in a Frame. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *fs, double *dim, * int *wperm, char s, FitsStore *store, int *axis_done, * int isoff, const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The current Frame of the supplied FrameSet is searched for celestial * axes. If any are found, FITS WCS keyword values describing the axis * are added to the supplied FitsStore, if possible (the conventions * of FITS-WCS paper II are used). Note, this function does not store * values for keywords which define the transformation from pixel * coords to Intermediate World Coords (CRPIX, PC and CDELT), but a * Mapping is returned which embodies these values. This Mapping is * from the current Frame in the FrameSet (WCS coords) to a Frame * representing IWC. The IWC Frame has the same number of axes as the * WCS Frame which may be greater than the number of base Frame (i.e. * pixel) axes. * Parameters: * this * Pointer to the FitsChan. * fs * Pointer to the FrameSet. The base Frame should represent FITS pixel * coordinates, and the current Frame should represent FITS WCS * coordinates. The number of base Frame axes should not exceed the * number of current Frame axes. * dim * An array holding the image dimensions in pixels. AST__BAD can be * supplied for any unknown dimensions. * wperm * Pointer to an array of integers with one element for each axis of * the current Frame. Each element holds the zero-based * index of the FITS-WCS axis (i.e. the value of "i" in the keyword * names "CTYPEi", "CRVALi", etc) which describes the Frame axis. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * store * The FitsStore in which to store the FITS WCS keyword values. * axis_done * An array of flags, one for each Frame axis, which indicate if a * description of the corresponding axis has yet been stored in the * FitsStore. * isoff * If greater than zero, the description to add to the FitsStore * should describe offset coordinates. If less than zero, the * description to add to the FitsStore should describe absolute * coordinates but should include the SkyRefIs, SkyRef and SkyRefP * attributes. If zero, ignore all offset coordinate info. The * absolute value indicates the nature of the reference point: * 1 == "pole", 2 == "origin", otherwise "ignored". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * If celestial axes were found which can be described using the * conventions of FITS-WCS paper II, then a Mapping from the current Frame * of the supplied FrameSet, to the IWC Frame is returned. Otherwise, * a UnitMap is returned. Note, the Mapping only defines the IWC * transformation for celestial axes. Any non-celestial axes are passed * unchanged by the returned Mapping. */ /* Local Variables: */ AstFitsTable *table; /* Pointer to structure holding -TAB table info */ AstFrame *pframe; /* Primary Frame containing current WCS axis*/ AstFrame *wcsfrm; /* WCS Frame within FrameSet */ AstMapping *map1; /* Pointer to pre-WcsMap Mapping */ AstMapping *map3; /* Pointer to post-WcsMap Mapping */ AstMapping *map; /* Pixel -> WCS mapping */ AstMapping *ret; /* Returned Mapping */ AstMapping *tmap0; /* A temporary Mapping */ AstMapping *tmap1; /* A temporary Mapping */ AstMapping *tmap2; /* A temporary Mapping */ AstMapping *tmap3; /* A temporary Mapping */ AstMapping *tmap4; /* A temporary Mapping */ AstSkyFrame *skyfrm; /* The SkyFrame defining current WCS axis */ AstWcsMap *map2; /* Pointer to WcsMap */ AstWcsMap *map2b; /* Pointer to WcsMap with cleared lat/lonpole */ char *cval; /* Pointer to keyword value */ char *temp; /* Pointer to temporary string */ double *mat; /* Pointer to matrix diagonal elements */ double *ppcfid; /* Pointer to array holding PPC at fiducial point */ double con; /* Constant value for unassigned axes */ double crval[ 2 ]; /* Psi coords of reference point */ double pv; /* Projection parameter value */ double skyfid[ 2 ]; /* Sky coords of fiducial point */ double val; /* Keyword value */ int *inperm; /* Input axis permutation array */ int *outperm; /* Output axis permutation array */ int *tperm; /* Pointer to new FITS axis numbering array */ int axlat; /* Index of latitude output from WcsMap */ int axlon; /* Index of longitude output from WcsMap */ int extver; /* Table version number for -TAB headers */ int fits_ilat; /* FITS WCS axis index for latitude axis */ int fits_ilon; /* FITS WCS axis index for longitude axis */ int i; /* Loop index */ int iax; /* Axis index */ int icolindexlat; /* Index of table column holding lat index vector */ int icolindexlon; /* Index of table column holding lon index vector */ int icolmainlat; /* Index of table column holding main lat coord array */ int icolmainlon; /* Index of table column holding main lon coord array */ int interplat; /* INterpolation method for latitude look-up tables */ int interplon; /* INterpolation method for longitude look-up tables */ int ilat; /* Index of latitude axis within total WCS Frame */ int ilon; /* Index of longitude axis within total WCS Frame */ int j; /* Loop index */ int m; /* Projection parameter index */ int maxm; /* Largest used "m" value */ int mlat; /* Index of latitude axis in main lat coord array */ int mlon; /* Index of longitude axis in main lon coord array */ int nwcs; /* Number of WCS axes */ int nwcsmap; /* Number of inputs/outputs for the WcsMap */ int paxis; /* Axis index within primary Frame */ int skylataxis; /* Index of latitude axis within SkyFrame */ int skylonaxis; /* Index of longitude axis within SkyFrame */ int tpn; /* Is the WCS projectiona TPN projection? */ /* Initialise */ ret = NULL; /* Other initialisation to avoid compiler warnings. */ mlon = 0; mlat = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Get a pointer to the WCS Frame. */ wcsfrm = astGetFrame( fs, AST__CURRENT ); /* Store the number of WCS axes. */ nwcs = astGetNout( fs ); /* Check each axis in the WCS Frame to see if it is a celestial axis. */ skyfrm = NULL; map = NULL; ilon = -1; ilat = -1; for( iax = 0; iax < nwcs; iax++ ) { /* Obtain a pointer to the primary Frame containing the current WCS axis. */ astPrimaryFrame( wcsfrm, iax, &pframe, &paxis ); /* If the current axis belongs to a SkyFrame, we have found a celestial axis. Keep a pointer to it, and note the indices of the celestial axes within the complete WCS Frame. The MakeFitsFrameSet function will have ensured that the WCS Frame only contains at most a single SkyFrame. */ if( astIsASkyFrame( pframe ) ) { if( !skyfrm ) skyfrm = astClone( pframe ); if( paxis == 0 ) { ilon = iax; } else { ilat = iax; } /* Indicate that this axis has been classified. */ axis_done[ iax ] = 1; } /* Release resources. */ pframe = astAnnul( pframe ); } /* Only proceed if we found celestial axes. */ if( ilon != -1 && ilat != -1 ) { /* Note the FITS WCS axis indices for the longitude and latitude axes */ fits_ilon = wperm[ ilon ]; fits_ilat = wperm[ ilat ]; /* Create an array to hold the Projection Plane Coords corresponding to the CRVALi keywords. */ ppcfid = (double *) astMalloc( sizeof( double )*nwcs ); /* Get the pixel->wcs Mapping. */ map = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* Get the table version number to use if we end up using the -TAB algorithm. This is the set value of the TabOK attribute (if positive). */ extver = astGetTabOK( this ); /* Some of the required FITS Keyword values are defined by the WcsMap contained within the Mapping. Split the mapping up into a list of serial component mappings, and locate the first WcsMap in this list. The first Mapping returned by this call is the result of compounding all the Mappings up to (but not including) the WcsMap, the second returned Mapping is the (inverted) WcsMap, and the third returned Mapping is anything following the WcsMap. Only proceed if one and only one WcsMap is found. */ if( SplitMap( map, astGetInvert( map ), ilon, ilat, &map1, &map2, &map3, status ) ){ /* Get the indices of the latitude and longitude axes within the SkyFrame (not necessarily (1,0) because they may have been permuted). */ skylataxis = astGetLatAxis( skyfrm ); skylonaxis = astGetLonAxis( skyfrm ); /* The reference point in the celestial coordinate system is found by transforming the fiducial point in native spherical co-ordinates into WCS coordinates using map3. */ if( GetFiducialWCS( map2, map3, ilon, ilat, skyfid + skylonaxis, skyfid + skylataxis, status ) ){ /* We also need to find the indices of the longitude and latitude outputs from the WcsMap. These may not be the same as ilat and ilon because of axis permutations in "map3". */ axlon = astGetWcsAxis( map2, 0 ); axlat = astGetWcsAxis( map2, 1 ); /* Normalise the latitude and longitude values at the fiducial point. The longitude and latitude values found above will be in radians, but after normalization we convert them to degrees, as expected by other functions which handle FitsStores. */ if( skyfid[ skylonaxis ] == AST__BAD ) skyfid[ skylonaxis ] = 0.0; if( skyfid[ skylataxis ] == AST__BAD ) skyfid[ skylataxis ] = 0.0; if( ZEROANG( skyfid[ 0 ] ) ) skyfid[ 0 ] = 0.0; if( ZEROANG( skyfid[ 1 ] ) ) skyfid[ 1 ] = 0.0; astNorm( skyfrm, skyfid ); SetItem( &(store->crval), fits_ilon, 0, s, AST__DR2D*skyfid[ skylonaxis ], status ); SetItem( &(store->crval), fits_ilat, 0, s, AST__DR2D*skyfid[ skylataxis ], status ); /* Set a flag if we have a TPN projection. This is an AST-specific projection which mimicks the old "TAN with correction terms" projection which was removed from the final version of the FITS-WCS paper II. */ tpn = ( astGetWcsType( map2 ) == AST__TPN ); /* Store the WCS projection parameters. Except for TPN projections, always exclude parameters 3 and 4 on the longitude axis since these are reserved to hold copies of LONPOLE and LATPOLE. */ for( m = 0; m < WCSLIB_MXPAR; m++ ){ if( astTestPV( map2, axlon, m ) ) { if( m < 3 || m > 4 || tpn ) { pv = astGetPV( map2, axlon, m ); if( pv != AST__BAD ) SetItem( &(store->pv), fits_ilon, m, s, pv, status ); } } if( astTestPV( map2, axlat, m ) ) { pv = astGetPV( map2, axlat, m ); if( pv != AST__BAD ) SetItem( &(store->pv), fits_ilat, m, s, pv, status ); } } /* If PVi_0 (for the longitude axis) is non-zero, the Cartesian coordinates used by the WcsMap (Projection Plane Coordinates, PPC) need to be shifted to produce Intermediate World Coordinates (IWC). This shift results in the pixel reference position specified by the CRPIXi values (and which corresponds to the origin of IWC) mapping on to the fiducial position specified by the CRVALi values. The required shifts are just the PPC coordinates of the fiducial point. The AST-specific "TPN" projection uses longitude projection parameters to define correction terms, and so cannot use the above convention (which is part of FITS-WCS paper II). Therefore TPN projections always use zero shift between PPC and IWC. */ for( iax = 0; iax < nwcs; iax++ ) ppcfid[ iax ] = 0.0; if( !tpn && astGetPV( map2, axlon, 0 ) != 0.0 ) { GetFiducialPPC( (AstWcsMap *) map2, ppcfid + ilon, ppcfid + ilat, status ); if( ppcfid[ ilon ] == AST__BAD ) ppcfid[ ilon ] = 0.0; if( ppcfid[ ilat ] == AST__BAD ) ppcfid[ ilat ] = 0.0; ppcfid[ ilon ] *= AST__DR2D; ppcfid[ ilat ] *= AST__DR2D; } /* Store the CTYPE, CNAME, EQUINOX, MJDOBS, and RADESYS values. */ SkySys( this, skyfrm, 1, astGetWcsType( map2 ), store, fits_ilon, fits_ilat, s, isoff, method, class, status ); /* Store the LONPOLE and LATPOLE values in the FitsStore. */ SkyPole( map2, map3, ilon, ilat, wperm, s, store, method, class, status ); /* The values of LONPOLE and LATPOLE stored above (in the FitsStore) will be ignored by WcsNative if the WcsMap contains set values for projection parameters PVi_3a and/or PVi_4a (these will be used in preference to the values in the FitsStore). To avoid this happening we take a copy of the WcsMap and clear the relevant parameters (but not if the WcsMap is for a TPN projection because TPN uses PVi_3a and PVi_4a for other purposes). */ if( astGetWcsType( map2 ) != AST__TPN ) { map2b = astCopy( map2 ); astClearPV( map2b, axlon, 3 ); astClearPV( map2b, axlon, 4 ); } else { map2b = astClone( map2 ); } /* We will now create the Mapping from WCS coords to IWC coords. In fact, we produce the Mapping from IWC to WCS and then invert it. Create the first component of this Mapping which implements any shift of origin from IWC to PPC. */ tmap0 = (AstMapping *) astShiftMap( nwcs, ppcfid, "", status ); /* The next component of this Mapping scales the PPC coords from degrees to radians on the celestial axes. */ mat = astMalloc( sizeof( double )*(size_t) nwcs ); if( astOK ) { for( iax = 0; iax < nwcs; iax++ ) mat[ iax ] = 1.0; mat[ ilon ] = AST__DD2R; mat[ ilat ] = AST__DD2R; tmap1 = (AstMapping *) astMatrixMap( nwcs, nwcs, 1, mat, "", status ); mat = astFree( mat ); } else { tmap1 = NULL; } /* Now create the Mapping from Native Spherical Coords to WCS. */ tmap2 = WcsNative( NULL, store, s, map2b, fits_ilon, fits_ilat, method, class, status ); /* Combine the WcsMap with the above Mapping, to get the Mapping from PPC to WCS. */ tmap3 = (AstMapping *) astCmpMap( map2b, tmap2, 1, "", status ); tmap2 = astAnnul( tmap2 ); /* If there are more WCS axes than IWC axes, create a UnitMap for the extra WCS axes and add it in parallel with tmap3. */ nwcsmap = astGetNin( map3 ); if( nwcsmap < nwcs ) { tmap2 = (AstMapping *) astUnitMap( nwcs - nwcsmap, "", status ); tmap4 = (AstMapping *) astCmpMap( tmap3, tmap2, 0, "", status ); tmap3 = astAnnul( tmap3 ); tmap2 = astAnnul( tmap2 ); tmap3 = tmap4; nwcsmap = nwcs; } /* The pixel->wcs mapping may include a PermMap which selects some sub-set or super-set of the orignal WCS axes. In this case the number of inputs and outputs for "tmap3" created above may not equal "nwcs". To avoid this, we embed "tmap3" between 2 PermMaps which select the required axes. */ if( nwcsmap != nwcs || ilon != axlon || ilat != axlat ) { inperm = astMalloc( sizeof( int )*(size_t) nwcs ); outperm = astMalloc( sizeof( int )*(size_t) nwcsmap ); if( astOK ) { /* Indicate that no inputs of the PermMap have yet been assigned to any outputs */ for( i = 0; i < nwcs; i++ ) inperm[ i ] = -1; /* Assign the WcsMap long/lat axes to the WCS Frame long/lat axes */ inperm[ ilon ] = axlon; inperm[ ilat ] = axlat; /* Assign the remaining inputs arbitrarily (doesn't matter how we do this since the WcsMap is effectively a UnitMap on all non-celestial axes). */ iax = 0; for( i = 0; i < nwcs; i++ ) { while( iax == axlon || iax == axlat ) iax++; if( inperm[ i ] == -1 ) inperm[ i ] = iax++; } /* Do the same for the outputs. */ for( i = 0; i < nwcsmap; i++ ) outperm[ i ] = -1; outperm[ axlon ] = ilon; outperm[ axlat ] = ilat; iax = 0; for( i = 0; i < nwcsmap; i++ ) { while( iax == ilon || iax == ilat ) iax++; if( outperm[ i ] == -1 ) outperm[ i ] = iax++; } /* Create the PermMap. */ con = AST__BAD; tmap2 = (AstMapping *) astPermMap( nwcs, inperm, nwcsmap, outperm, &con, "", status ); /* Sandwich the WcsMap between the PermMap and its inverse. */ tmap4 = (AstMapping *) astCmpMap( tmap2, tmap3, 1, "", status ); tmap3 = astAnnul( tmap3 ); astInvert( tmap2 ); tmap3 = (AstMapping *) astCmpMap( tmap4, tmap2, 1, "", status ); tmap2 = astAnnul( tmap2 ); tmap4 = astAnnul( tmap4 ); } inperm = astFree( inperm ); outperm = astFree( outperm ); } /* Combine these Mappings together. */ tmap4 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, "", status ); tmap0 = astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); ret = (AstMapping *) astCmpMap( tmap4, tmap3, 1, "", status ); tmap3 = astAnnul( tmap3 ); tmap4 = astAnnul( tmap4 ); /* Invert this Mapping to get the Mapping from WCS to IWC. */ astInvert( ret ); /* The spherical rotation involved in converting WCS to IWC can result in in appropriate numbering of the FITS axes. For instance, a LONPOLE value of 90 degrees causes the IWC axes to be transposed. For this reason we re-asses the FITS axis numbers assigned to the celestial axes in order to make the IWC axes as close as possible to the pixel axes with the same number. To do this, we need the Mapping from pixel to IWC, which is formed by concatenating the pixel->WCS Mapping with the WCS->IWC Mapping. */ tmap0 = (AstMapping *) astCmpMap( map, ret, 1, "", status ); /* Find the outputs of this Mapping which should be associated with each input. */ tperm = astMalloc( sizeof(int)*(size_t) nwcs ); if( ! WorldAxes( this, tmap0, dim, tperm, status ) ) { ret = astAnnul( ret ); } /* If the index associated with the celestial axes appear to have been swapped... */ if( ret && astOK && fits_ilon == tperm[ ilat ] && fits_ilat == tperm[ ilon ] ) { /* Swap the fits axis indices associated with each WCS axis to match. */ wperm[ ilon ] = fits_ilat; wperm[ ilat ] = fits_ilon; /* Swap the stored CRVAL value for the longitude and latitude axis. */ val = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status ); SetItem( &(store->crval), fits_ilat, 0, s, GetItem( &(store->crval), fits_ilon, 0, s, NULL, method, class, status ), status ); SetItem( &(store->crval), fits_ilon, 0, s, val, status ); /* Swap the stored CTYPE value for the longitude and latitude axis. */ cval = GetItemC( &(store->ctype), fits_ilat, 0, s, NULL, method, class, status ); if( cval ) { temp = astStore( NULL, (void *) cval, strlen( cval ) + 1 ); cval = GetItemC( &(store->ctype), fits_ilon, 0, s, NULL, method, class, status ); if( cval ) { SetItemC( &(store->ctype), fits_ilat, 0, s, cval, status ); SetItemC( &(store->ctype), fits_ilon, 0, s, temp, status ); } temp = astFree( temp ); } /* Swap the stored CNAME value for the longitude and latitude axis. */ cval = GetItemC( &(store->cname), fits_ilat, 0, s, NULL, method, class, status ); if( cval ) { temp = astStore( NULL, (void *) cval, strlen( cval ) + 1 ); cval = GetItemC( &(store->cname), fits_ilon, 0, s, NULL, method, class, status ); if( cval ) { SetItemC( &(store->cname), fits_ilat, 0, s, cval, status ); SetItemC( &(store->cname), fits_ilon, 0, s, temp, status ); } temp = astFree( temp ); } /* Swap the projection parameters asociated with the longitude and latitude axes. */ maxm = GetMaxJM( &(store->pv), s, status ); for( m = 0; m <= maxm; m++ ){ val = GetItem( &(store->pv), fits_ilat, m, s, NULL, method, class, status ); SetItem( &(store->pv), fits_ilat, m, s, GetItem( &(store->pv), fits_ilon, m, s, NULL, method, class, status ), status ); SetItem( &(store->pv), fits_ilon, m, s, val, status ); } } /* Release resources. */ map2b = astAnnul( map2b ); tperm = astFree( tperm ); tmap0 = astAnnul( tmap0 ); } /* Release resources. */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); /* If no WcsMap was found in the pixel->WCS Mapping, it may be possible to describe the celestial axes using a tabular look-up table (i.e. the FITS-WCS "_TAB" algorithm). Only do this if the -TAB algorithm is to be supported. */ } else if( extver > 0 ) { /* Get any pre-existing FitsTable from the FitsStore. This is the table in which the tabular data will be stored (if the Mapping can be expressed in -TAB form). */ if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL; /* See if the transformations for the celestial axes can be expressed in -TAB form. The returned Mapping (if any) is the Mapping from (lon,lat) (rads) to (psi_lon,psi_lat) (pixels). See FITS-WCS paper III section 6.1.2 for definition of psi. Scale the values stored in the table from radians to degrees. */ tmap0 = IsMapTab2D( map, AST__DR2D, "deg", wcsfrm, dim, ilon, ilat, fits_ilon, fits_ilat, &table, &icolmainlon, &icolmainlat, &icolindexlon, &icolindexlat, &mlon, &mlat, &interplon, &interplat, status ); if( tmap0 ) { /* Store the CTYPE, CNAME, EQUINOX, MJDOBS, and RADESYS values. */ SkySys( this, skyfrm, 0, 0, store, fits_ilon, fits_ilat, s, isoff, method, class, status ); /* If possible, choose the two CRVAL values (which are values on the psi axes) so that transforming them using the Mapping returned by IsMapTab2D gives the sky reference position stored in the SkyFrame. Check the SkyFrame has a defined reference position. */ if( astTestSkyRef( skyfrm, 0 ) && astTestSkyRef( skyfrm, 1 ) ){ /* Get the longitude and latitude at the reference point in radians. */ skyfid[ 0 ] = astGetSkyRef( skyfrm, astGetLonAxis( skyfrm )); skyfid[ 1 ] = astGetSkyRef( skyfrm, astGetLatAxis( skyfrm )); /* We use the WCS->psi Mapping to convert the reference point WCS coords (rads) into psi coords (pixels). We can only do this if the WCS->psi Mapping has a defined forward transformation. */ if( astGetTranForward( tmap0 ) ) { astTran2( tmap0, 1, skyfid, skyfid + 1, 1, crval, crval + 1 ); /* If the WCS->psi mapping has an undefined forward transformation, then just store the sky reference point coords (in degs) in keywords AXREFn, and use 1.0 for the CRVAL values, so that IWC becomes equal to (psi-1) i.e. (grid coords - 1). This means the reference point is at grid coords (1.0,1.0). Note this choice of 1.0 for CRVAL is not arbitrary since it is required by the trick used to create invertable CD matrix in function MakeInvertable. */ } else { SetItem( &(store->axref), fits_ilon, 0, s, AST__DR2D*skyfid[ 0 ], status ); SetItem( &(store->axref), fits_ilat, 0, s, AST__DR2D*skyfid[ 1 ], status ); crval[ 0 ] = 1.0; crval[ 1 ] = 1.0; } /* If the SkyFrame has no reference position, use 1.0 for the CRVAL values. */ } else { crval[ 0 ] = 1.0; crval[ 1 ] = 1.0; } /* Create a Mapping that describes the transformation from the lon and lat psi axes to the lon and lat IWC axes (i.e. a ShiftMap that just subtracts the CRVAL values from each axis). */ crval[ 0 ] = -crval[ 0 ]; crval[ 1 ] = -crval[ 1 ]; tmap1 = (AstMapping *) astShiftMap( 2, crval, " ", status ); crval[ 0 ] = -crval[ 0 ]; crval[ 1 ] = -crval[ 1 ]; /* Create a series compound Mapping that applies the Mapping returned by IsMapTab2D first (the Mapping from WCS to psi), followed by the Mapping from psi to IWC created above. There-after, use this compound Mapping in place of the Mapping returned by IsMapTab2D. It maps WCS to IWC. */ tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, " ", status ); (void) astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); tmap0 = tmap2; /* Store the CRVAL values */ SetItem( &(store->crval), fits_ilon, 0, s, crval[ 0 ], status ); SetItem( &(store->crval), fits_ilat, 0, s, crval[ 1 ], status ); /* Store TAB-specific values in the FitsStore. First the name of the FITS binary table extension holding the coordinate info. */ SetItemC( &(store->ps), fits_ilon, 0, s, AST_TABEXTNAME, status ); SetItemC( &(store->ps), fits_ilat, 0, s, AST_TABEXTNAME, status ); /* Next the table version number. This is the set (positive) value for the TabOK attribute. */ SetItem( &(store->pv), fits_ilon, 1, s, extver, status ); SetItem( &(store->pv), fits_ilat, 1, s, extver, status ); /* Also store the table version in the binary table header. */ astSetFitsI( table->header, "EXTVER", extver, "Table version number", 0 ); /* Next the name of the table column containing the main coords array. */ SetItemC( &(store->ps), fits_ilon, 1, s, astColumnName( table, icolmainlon ), status ); SetItemC( &(store->ps), fits_ilat, 1, s, astColumnName( table, icolmainlat ), status ); /* Next the name of the column containing the index array. */ if( icolindexlon >= 0 ) SetItemC( &(store->ps), fits_ilon, 2, s, astColumnName( table, icolindexlon ), status ); if( icolindexlat >= 0 ) SetItemC( &(store->ps), fits_ilat, 2, s, astColumnName( table, icolindexlat ), status ); /* The one-based index of the axes within the coordinate array that describes FITS WCS axes "fits_ilon" and "fits_ilat". */ SetItem( &(store->pv), fits_ilon, 3, s, mlon, status ); SetItem( &(store->pv), fits_ilat, 3, s, mlat, status ); /* The interpolation method (an AST extension to the published -TAB algorithm, communicated through the QVi_4a keyword). */ SetItem( &(store->pv), fits_ilon, 4, s, interplon, status ); SetItem( &(store->pv), fits_ilat, 4, s, interplat, status ); /* Also store the FitsTable itself in the FitsStore. */ astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL ); /* Allocate space for the arrays that define the permutations required for the inputs and outputs of a PermMap. */ inperm = astMalloc( sizeof( double )*nwcs ); outperm = astMalloc( sizeof( double )*nwcs ); if( astOK ) { /* Create the WCS -> IWC Mapping. First create a parallel CmpMap that combines the Mapping returned by IsMapTab2D (which transforms the celestial axes), with a UnitMap which transforms the non-celestial axes. */ if( nwcs > 2 ) { tmap1 = (AstMapping *) astUnitMap( nwcs - 2, " ", status ); tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 0, " ", status ); tmap1 = astAnnul( tmap1 ); } else { tmap2 = astClone( tmap0 ); } /* Now create a PermMap that permutes the inputs of this CmpMap into the order of the axes in the WCS Frame. */ outperm[ 0 ] = ilon; outperm[ 1 ] = ilat; j = 0; for( i = 2; i < nwcs; i++ ) { while( j == ilon || j == ilat ) j++; outperm[ i ] = j++; } for( i = 0; i < nwcs; i++ ) inperm[ outperm[ i ] ] = i; tmap1 = (AstMapping *) astPermMap( nwcs, inperm, nwcs, outperm, NULL, " ", status ); /* Use this PermMap (and its inverse) to permute the inputs (and outputs) of the parallel CmpMap created above. */ tmap3 = (AstMapping *) astCmpMap( tmap1, tmap2, 1, " ", status ); tmap2 = astAnnul( tmap2 ); astInvert( tmap1 ); tmap2 = (AstMapping *) astCmpMap( tmap3, tmap1, 1, " ", status ); tmap1 = astAnnul( tmap1 ); tmap3 = astAnnul( tmap3 ); /* Now create a PermMap that permutes the WCS axes into the FITS axis order. */ for( i = 0; i < nwcs; i++ ) { inperm[ i ] = wperm[ i ]; outperm[ wperm[ i ] ] = i; } tmap1 = (AstMapping *) astPermMap( nwcs, inperm, nwcs, outperm, NULL, "", status ); /* Use this PermMap to permute the outputs of the "tmap2" Mapping. The resulting Mapping is the Mapping from the current Frame to IWC and is the Mapping to be returned as the function value. */ ret = (AstMapping *) astCmpMap( tmap2, tmap1, 1, " ", status ); tmap1 = astAnnul( tmap1 ); tmap2 = astAnnul( tmap2 ); } /* Free remaining resources. */ inperm = astFree( inperm ); outperm = astFree( outperm ); tmap0 = astAnnul( tmap0 ); } if( table ) table = astAnnul( table ); } /* Release resources. */ ppcfid = astFree( ppcfid ); } /* Release resources. */ wcsfrm = astAnnul( wcsfrm ); if( skyfrm ) skyfrm = astAnnul( skyfrm ); if( map ) map = astAnnul( map ); /* If we have a Mapping to return, simplify it. Otherwise, create a UnitMap to return. */ if( ret ) { tmap0 = ret; ret = astSimplify( tmap0 ); tmap0 = astAnnul( tmap0 ); } else { ret = (AstMapping *) astUnitMap( nwcs, "", status ); } /* Return the result. */ return ret; } static void ChangePermSplit( AstMapping *map, int *status ){ /* * Name: * ChangePermSplit * Purpose: * Change all PermMaps in a Mapping to use the alternate * implementation of the astMapSplit method. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void ChangePermSplit( AstMapping *map, int *status ) * Class Membership: * FitsChan member function. * Description: * The PemMap class provides two implementations of the astMapSplit * method. The implementation used by each PermMap is determined by * the value of the PermMap's "PermSplit" attribute. This function * searches the supplied Mapping for any PermMaps, and set their * PermSplit attribute to 1, indicating that the alternate * implementation of astMapSplit should be used. * Parameters: * map * Pointer to the Mapping. Modified on exit by setting all * PermSplit attributes to 1. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstMapping *map1; AstMapping *map2; int series; int invert1; int invert2; /* Check inherited status */ if( !astOK ) return; /* If the supplied Mapping is a PermMap, set its PermSplit attribute non-zero. */ if( astIsAPermMap( map ) ) { astSetPermSplit( map, 1 ); /* If the supplied Mapping is not a PermMap, attempt to decompose the Mapping into two component Mappings. */ } else { astDecompose( map, &map1, &map2, &series, &invert1, &invert2 ); /* If the Mapping could be decomposed, use this function recursively to set the PermSplit attributes in each component Mapping. */ if( map1 && map2 ) { ChangePermSplit( map1, status ); ChangePermSplit( map2, status ); /* Annul the component Mappings. */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); } else if( map1 ) { map1 = astAnnul( map1 ); } else if( map2 ) { map2 = astAnnul( map2 ); } } } static double *Cheb2Poly( double *c, int nx, int ny, double xmin, double xmax, double ymin, double ymax, int *status ){ /* * Name: * Cheb2Poly * Purpose: * Converts a two-dimensional Chebyshev polynomial to standard form and * scale the arguments. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double *Cheb2Poly( double *c, int nx, int ny, double xmin, double xmax, * double ymin, double ymax, int *status ) * Class Membership: * FitsChan * Description: * Given the coefficients of a two-dimensional Chebychev polynomial P(u,v), * find the coefficients of the equivalent standard two-dimensional * polynomial Q(x,y). The allowed range of u and v is assumed to be the * unit square, and this maps on to the rectangle in (x,y) given by * (xmin:xmax,ymin:ymax). * Parameters: * c * An array of (nx,ny) elements supplied holding the coefficients of * P, such that the coefficient of (Ti(u)*Tj(v)) is held in element * (i + j*nx), where "Ti(u)" is the Chebychev polynomial (of the * first kind) of order "i" evaluated at "u", and "Tj(v)" is the * Chebychev polynomial of order "j" evaluated at "v". * nx * One more than the maximum power of u within P. * ny * One more than the maximum power of v within P. * xmin * X value corresponding to u = -1 * xmax * X value corresponding to u = +1 * ymin * Y value corresponding to v = -1 * ymax * Y value corresponding to v = +1 * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a dynamically allocated array of (nx,ny) elements holding * the coefficients of Q, such that the coefficient of (x^i*y^j) is held * in element (i + j*nx). Free it using astFree when no longer needed. */ /* Local Variables: */ double *d; double *pa; double *pw; double *work1; double *work2; double *work3; int *iw1; int *iw2; int i; int j; /* Check the status and supplied value pointer. */ if( !astOK ) return NULL; /* Allocate returned array. */ d = astMalloc( sizeof( *d )*nx*ny ); /* Allocate workspace. */ work1 = astMalloc( sizeof( *work1 )*ny ); work2 = astMalloc( sizeof( *work2 )*ny ); work3 = astMalloc( sizeof( *work2 )*nx ); iw1 = astMalloc( sizeof(int)*( nx > ny ? nx : ny ) ); iw2 = astMalloc( sizeof(int)*( nx > ny ? nx : ny ) ); if( astOK ) { /* Thinking of P as a 1D polynomial in v, each coefficient would itself then be a 1D polynomial in u: P = ( c[0] + c[1]*T1(u) + c[2]*T2(u) + ... ) + ( c[nx] + c[nx+1]*T1(u) + c[nx+2]*T2(u) + ... )*T1(v) + (c[2*nx] + c[2*nx+1]*T1(u) + c[2*nx+2]*T2(u) + ... )*T2(v) + ... (c[(ny-1)*nx] + c[(ny-1)*nx+1]*T1(u) + c[(ny-1)*nx+2]*T2(u) + ... )T{ny-1}(v) Use Chpc1 to convert these "polynomial coefficients" to standard form, storing the result in the corresponding row of "d" . Also, convert them from u to x. */ for( j = 0; j < ny; j++ ) { Chpc1( c + j*nx, work3, nx, iw1, iw2, status ); Shpc1( xmin, xmax, nx, work3, d + j*nx, status ); } /* The polynomial value is now: ( d[0] + d[1]*x + d[2]*x*x + ... ) + ( d[nx] + d[nx+1]*x + d[nx+2]*x*x + ... )*T1(v) + (d[2*nx] + d[2*nx+1]*x + d[2*nx+2]*x*x + ... )*T2(v) + ... (d[(ny-1)*nx] + d[(ny-1)*nx+1]*x + d[(ny-1)*nx+2]*x*x + ... )*T{ny-1}(v) If we rearrange this expression to view it as a 1D polynomial in x, rather than v, each coefficient of the new 1D polynomial is then itself a polynomial in v: ( d[0] + d[nx]*T1(v) + d[2*nx]*T2(v) + ... d[(ny-1)*nx]*T{ny-1}(v) ) + ( d[1] + d[nx+1]*T1(v) + d[2*nx+1]*T2(v) + ... d[(ny-1)*nx+1]T{ny-1}(v)... )*x + ( d[2] + d[nx+2]*T1(v) + d[2*nx+2]*T2(v) + ... d[(ny-1)*nx+2]T{ny-1}(v)... )*x*x + ... ( d[nx-1] + d[2*nx-1]*T1(v) + d[3*nx-1]*T2(v) + ... d[ny*nx-1]*T{ny-1}(v) )*x*x*... Now use Chpc1 to convert each of these "polynomial coefficients" to standard form. We copy each column of the d array into a 1D work array, use Shpc1 to modify the values in the work array, and then write the modified values back into the current column of d. Also convert from v to y. */ for( i = 0; i < nx; i++ ) { pa = d + i; pw = work1; for( j = 0; j < ny; j++ ) { *(pw++) = *pa; pa += nx; } Chpc1( work1, work2, ny, iw1, iw2, status ); Shpc1( ymin, ymax, ny, work2, work1, status ); pa = d + i; pw = work1; for( j = 0; j < ny; j++ ) { *pa = *(pw++); pa += nx; } } /* So the polynomial is now: ( d[0] + d[nx]*y + d[2*nx]*y*y + ... d[(ny-1)*nx]*y*y*... ) + ( d[1] + d[nx+1]*y + d[2*nx+1]*y*y + ... d[(ny-1)*nx+1]*y*y*... )*x + ( d[2] + d[nx+2]*y + d[2*nx+2]*y*y + ... d[(ny-1)*nx+2]*y*y*... )*x*x + ... ( d[nx-1] + d[2*nx-1]*y + d[3*nx-1]*y*y + ... d[ny*nx-1]*y*y*... )*x*x*... Re-arranging, this is: ( d[0] + d[1]*x + d[2]*x*x + ... ) + ( d[nx] + d[nx+1]*x + d[nx+2]*x*x + ... )*y + (d[2*nx] + d[2*nx+1]*x + d[2*nx+2]*x*x + ... )*y*y + ... (d[(ny-1)*nx] + d[(ny-1)*nx+1]*x + d[(ny-1)*nx+2]*x*x + ... )*y*y*... as required. */ } /* Free the workspace. */ work1 = astFree( work1 ); work2 = astFree( work2 ); work3 = astFree( work3 ); iw1 = astFree( iw1 ); iw2 = astFree( iw2 ); /* Return the result. */ return d; } static int CheckFitsName( const char *name, const char *method, const char *class, int *status ){ /* * Name: * CheckFitsName * Purpose: * Check a keyword name conforms to FITS standards. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int CheckFitsName( const char *name, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * FITS keywords must contain between 1 and 8 characters, and each * character must be an upper-case Latin alphabetic character, a digit, * an underscore, or a hyphen. Leading, trailing or embedded white space * is not allowed, with the exception of totally blank or null keyword * names. * Parameters: * name * Pointer to a string holding the name to check. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 0 is returned if the supplied name was blank. A value of 1 * is returned otherwise. * Notes: * - An error is reported if the supplied keyword name does not * conform to FITS requirements, and zero is returned. */ /* Local Variables: */ const char *c; /* Pointer to next character in name */ size_t n; /* No. of characters in supplied name */ int ret; /* Returned value */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise the returned value to indicate that the supplied name was blank. */ ret = 0; /* Check that the supplied pointer is not NULL. */ if( name ){ /* Get the number of characters in the name. */ n = strlen( name ); /* Report an error if the name has too many characters in it. */ if( n > FITSNAMLEN ){ astError( AST__BDFTS, "%s(%s): The supplied FITS keyword name ('%s') " "has %d characters. FITS only allows up to %d.", status, method, class, name, (int) n, FITSNAMLEN ); /* If the name has no characters in it, then assume it is a legal blank keyword name. Otherwise, check that no illegal characters occur in the name. */ } else if( n != 0 ) { /* Whitespace is only allowed in the special case of a name consisting entirely of whitespace. Such keywords are used to indicate that the rest of the card is a comment. Find the first non-whitespace character in the name. */ c = name; while( isspace( ( int ) *(c++) ) ); /* If the name is filled entirely with whitespace, then the name is acceptable as the special case. Otherwise, we need to do more checks. */ if( c - name - 1 < n ){ /* Indicate that the supplied name is not blank. */ ret = 1; /* Loop round every character checking that it is one of the legal characters. Report an error if any illegal characters are found. */ c = name; while( *c ){ if( !isFits( (int) *c ) ){ if( *c == '=' ){ astError( AST__BDFTS, "%s(%s): An equals sign ('=') was found " "before column %d within a FITS keyword name or header " "card.", status, method, class, FITSNAMLEN + 1 ); } else if( *c < ' ' ) { astError( AST__BDFTS, "%s(%s): The supplied FITS keyword " "name ('%s') contains an illegal non-printing " "character (ascii value %d).", status, method, class, name, *c ); } else if( *c < ' ' ) { astError( AST__BDFTS, "%s(%s): The supplied FITS keyword " "name ('%s') contains an illegal character ('%c').", status, method, class, name, *c ); } break; } c++; } } } /* Report an error if no pointer was supplied. */ } else if( astOK ){ astError( AST__INTER, "CheckFitsName(fitschan): AST internal " "error; a NULL pointer was supplied for the keyword name. ", status ); } /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static void CheckZero( char *text, double value, int width, int *status ){ /* * Name: * CheckZero * Purpose: * Ensure that the formatted value zero has no minus sign. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void CheckZero( char *text, double value, int width, int *status ) * Class Membership: * FitsChan member function. * Description: * There is sometimes a problem (perhaps only on DEC UNIX) when formatting * the floating-point value 0.0 using C. Sometimes it gives the string * "-0". This function fixed this by checking the first character of * the supplied string (if the supplied value is zero), and shunting the * remaining text one character to the right if it is a minus sign. It * returns without action if the supplied value is not zero. * * In addition, this function also rounds out long sequences of * adjacent zeros or nines in the number. * Parameters: * text * The formatted value. * value * The floating value which was formatted. * width * The minimum field width to use. The value is right justified in * this field width. Ignored if zero. * status * Pointer to the inherited status variable. * Notes: * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ char *c; /* Return if no text was supplied. */ if( !text ) return; /* If the numerical value is zero, check for the leading minus sign. */ if( value == 0.0 ) { /* Find the first non-space character. */ c = text; while( *c && isspace( (int) *c ) ) c++; /* If the first non-space character is a minus sign, replace it with a space. */ if( *c == '-' ) *c = ' '; /* Otherwise, round out sequences of zeros or nines. */ } else { RoundFString( text, width, status ); } } static double ChooseEpoch( AstFitsChan *this, FitsStore *store, char s, const char *method, const char *class, int *status ){ /* * Name: * ChooseEpoch * Purpose: * Choose a FITS keyword value to use for the AST Epoch attribute. * Type: * Private function. * Synopsis: * double ChooseEpoch( AstFitsChan *this, FitsStore *store, char s, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function returns an MJD value in the TDB timescale, which can * be used as the Epoch value in an AST Frame. It uses the following * preference order: secondary MJD-AVG, primary MJD-AVG, secondary MJD-OBS, * primary MJD-OBS. Note, DATE-OBS keywords are converted into MJD-OBS * keywords by the SpecTrans function before this function is called. * Parameters: * this * Pointer to the FitsChan. * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * method * The calling method. Used only in error messages. * class * The object class. Used only in error messages. * status * Pointer to the inherited status variable. * Returned Value: * The MJD value. * Notes: * - A value of AST__BAD is returned if an error occurs, or if none * of the required keywords can be found in the FitsChan. */ /* Local Variables: */ const char *timesys; /* The TIMESYS value in the FitsStore */ double mjd; /* The returned MJD */ /* Initialise the returned value. */ mjd = AST__BAD; /* Check the global status. */ if( !astOK ) return mjd; /* Otherwise, try to get the secondary MJD-AVG value. */ mjd = GetItem( &(store->mjdavg), 0, 0, s, NULL, method, class, status ); /* Otherwise, try to get the primary MJD-AVG value. */ if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdavg), 0, 0, ' ', NULL, method, class, status ); /* If the secondary MJD-OBS keyword is present in the FitsChan, gets its value. */ if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdobs), 0, 0, s, NULL, method, class, status ); /* Otherwise, try to get the primary MJD-OBS value. */ if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status ); /* Now convert the MJD value to the TDB timescale. */ timesys = GetItemC( &(store->timesys), 0, 0, ' ', NULL, method, class, status ); mjd = TDBConv( mjd, TimeSysToAst( this, timesys, method, class, status ), 0, method, class, status ); /* Return the answer. */ return mjd; } static void Chpc1( double *c, double *d, int n, int *w0, int *w1, int *status ){ /* * Name: * Chpc1 * Purpose: * Converts a one-dimensional Chebyshev polynomial to standard form. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void Chpc1( double *c, double *d, int n, int *w0, int *w1, int *status ) * Class Membership: * FitsChan * Description: * Given the coefficients of a one-dimensional Chebychev polynomial P(u), * find the coefficients of the equivalent standard 1D polynomial Q(u). * The allowed range of u is assumed to be the unit interval. * Parameters: * c * An array of n elements supplied holding the coefficients of * P, such that the coefficient of (Ti(u)) is held in element * (i), where "Ti(u)" is the Chebychev polynomial (of the * first kind) of order "i" evaluated at "u". * d * An array of n elements returned holding the coefficients of * Q, such that the coefficient of (u^i) is held in element (i). * n * One more than the highest power of u in P. * w0 * Pointer to a work array of n elements. * w1 * Pointer to a work array of n elements. * status * Inherited status value * Notes: * - Vaguely inspired by the Numerical Recipes routine "chebpc". But the * original had bugs, so I wrote this new version from first principles. */ /* Local Variables: */ int sv; int j; int k; /* Check inherited status */ if( !astOK ) return; /* Initialise the returned coefficients array. */ for( j = 0; j < n; j++ ) d[ j ] = 0.0; /* Use the recurrence relation T{k+1}(x) = 2.x.T{k}(x) - T{k-1}(x). w0[i] holds the coefficient of x^i in T{k-1}. w1[i] holds the coefficient of x^i in T{k}. Initialise them for T0 (="1") and T1 (="x"). */ for( j = 0; j < n; j++ ) w0[ j ] = w1[ j ] = 0; w0[ 0 ] = 1; w1[ 1 ] = 1; /* Update the returned coefficients array to include the T0 and T1 terms. */ d[ 0 ] = c[ 0 ]; d[ 1 ] = c[ 1 ]; /* Loop round using the above recurrence relation until we have found T{n-1}. */ for( k = 1; k < n - 1; k++ ){ /* To get the coefficients of T{k+1} shift the contents of w1 up one element, introducing a zero at the low end, and then double all the values in w1. Finally subtract off the values in w0. This implements the above recurrence relationship. Starting at the top end and working down to the bottom, store a new value for each element of w1. */ for( j = n - 1; j > 0; j-- ) { /* First save the original element of w1 in w0 for use next time. But we also need the original w0 element later on so save it first. */ sv = w0[ j ]; w0[ j ] = w1[ j ]; /* Double the lower neighbouring w1 element and subtract off the w0 element saved above. This forms the new value for w1. */ w1[ j ] = 2*w1[ j - 1 ] - sv; } /* Introduce a zero into the lowest element of w1, saving the original value first in w0. Then subtract off the original value of w0. */ sv = w0[ 0 ]; w0[ 0 ] = w1[ 0 ]; w1[ 0 ] = -sv; /* W1 now contains the coefficients of T{k+1} in w1, and the coefficients of T{k} in w0. Multiply these by the supplied coefficient for T{k+1}, and add them into the returned array. */ for( j = 0; j <= k + 1; j++ ){ d[ j ] += c[ k + 1 ]*w1[ j ]; } } } static int ChrLen( const char *string, int *status ){ /* * Name: * ChrLen * Purpose: * Return the length of a string excluding any trailing white space. * Type: * Private function. * Synopsis: * int ChrLen( const char *string, int *status ) * Class Membership: * FitsChan * Description: * This function returns the length of a string excluding any trailing * white space, or non-printable characters. * Parameters: * string * Pointer to the string. * status * Pointer to the inherited status variable. * Returned Value: * The length of a string excluding any trailing white space and * non-printable characters. * Notes: * - A value of zero is returned if a NULL pointer is supplied, or if an * error has already occurred. */ /* Local Variables: */ const char *c; /* Pointer to the next character to check */ int ret; /* The returned string length */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise the returned string length. */ ret = 0; /* Check a string has been supplied. */ if( string ){ /* Check each character in turn, starting with the last one. */ ret = strlen( string ); c = string + ret - 1; while( ret ){ if( isprint( (int) *c ) && !isspace( (int) *c ) ) break; c--; ret--; } } /* Return the answer. */ return ret; } static int CLASSFromStore( AstFitsChan *this, FitsStore *store, AstFrameSet *fs, double *dim, const char *method, const char *class, int *status ){ /* * Name: * CLASSFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-CLASS encoding. * Type: * Private function. * Synopsis: * int CLASSFromStore( AstFitsChan *this, FitsStore *store, * AstFrameSet *fs, double *dim, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-CLASS encoding. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * fs * Pointer to the FrameSet from which the values in the FitsStore * were derived. * dim * Pointer to an array holding the main array dimensions (AST__BAD * if a dimension is not known). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ AstFrame *azelfrm; /* (az,el) frame */ AstFrame *curfrm; /* Current Frame in supplied FrameSet */ AstFrame *freqfrm; /* Frame for reference frequency value */ AstFrame *radecfrm; /* Spatial frame for CRVAL values */ AstFrame *velofrm; /* Frame for reference velocity value */ AstFrameSet *fsconv1;/* FrameSet connecting "curfrm" & "radecfrm" */ AstFrameSet *fsconv2;/* FrameSet connecting "curfrm" & "azelfrm" */ AstMapping *map1; /* Axis permutation to get (lonaxis,lataxis) = (0,1) */ AstMapping *map2; /* Mapping from FITS CTYPE to (az,el) */ AstMapping *map3; /* Mapping from (lon,lat) to (az,el) */ char *comm; /* Pointer to comment string */ char *cval; /* Pointer to string keyword value */ char attbuf[20]; /* Buffer for AST attribute name */ char combuf[80]; /* Buffer for FITS card comment */ char lattype[MXCTYPELEN];/* Latitude axis CTYPE */ char lontype[MXCTYPELEN];/* Longitude axis CTYPE */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ char spectype[MXCTYPELEN];/* Spectral axis CTYPE */ double *cdelt; /* Pointer to CDELT array */ double aval[ 2 ]; /* General purpose array */ double azel[ 2 ]; /* Reference (az,el) values */ double cdl; /* CDELT term */ double crval[ 3 ]; /* CRVAL values converted to rads, etc */ double delta; /* Spectral axis increment */ double equ; /* Epoch of reference equinox */ double fd; /* Fraction of a day */ double latval; /* CRVAL for latitude axis */ double lonpole; /* LONPOLE value */ double lonval; /* CRVAL for longitude axis */ double mjd99; /* MJD at start of 1999 */ double p1, p2; /* Projection parameters */ double radec[ 2 ]; /* Reference (lon,lat) values */ double rf; /* Rest freq (Hz) */ double specfactor; /* Factor for converting internal spectral units */ double val; /* General purpose value */ double xin[ 3 ]; /* Grid coords at centre of first pixel */ double xout[ 3 ]; /* WCS coords at centre of first pixel */ int axlat; /* Index of latitude FITS WCS axis */ int axlon; /* Index of longitude FITS WCS axis */ int axspec; /* Index of spectral FITS WCS axis */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int naxis2; /* Length of pixel axis 2 */ int naxis3; /* Length of pixel axis 3 */ int naxis; /* No. of axes */ int ok; /* Is FitsSTore OK for IRAF encoding? */ int prj; /* Projection type */ /* Other initialisation to avoid compiler warnings. */ lonval = 0.0; latval = 0.0; /* Check the inherited status. */ if( !astOK ) return 0; /* Initialise */ specfactor = 1.0; /* First check that the values in the FitsStore conform to the requirements of the CLASS encoding. Assume they do not to begin with. */ ok = 0; /* Just do primary axes. */ s = ' '; /* Look for the primary celestial axes. */ FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status ); /* Get the current Frame from the supplied FrameSet. */ curfrm = astGetFrame( fs, AST__CURRENT ); /* Spectral and celestial axes must be present in axes 1,2 and 3. */ if( axspec >= 0 && axspec < 3 && axlon >= 0 && axlon < 3 && axlat >= 0 && axlat < 3 ) { ok = 1; /* If the spatial pixel axes are degenerate (i.e. span only a single pixel), modify the CRPIX and CRVAL values in the FitsStore to put the reference point at the centre of the one and only spatial pixel. */ if( store->naxis >= 3 && dim[ axlon ] == 1.0 && dim[ axlat ] == 1.0 ){ xin[ 0 ] = 1.0; xin[ 1 ] = 1.0; xin[ 2 ] = 1.0; astTranN( fs, 1, 3, 1, xin, 1, 3, 1, xout ); if( xout[ axlon ] != AST__BAD && xout[ axlat ] != AST__BAD ) { /* The indices of the spatial axes in the FITS header may not be the same as the indices of the spatial axes in the WCS Frame of the supplied FrameSet. So search the current Frame for longitude and latitude axes, and store the corresponding elements of the "xout" array for later use. */ for( i = 0; i < 3; i++ ) { sprintf( attbuf, "IsLonAxis(%d)", i + 1 ); if( astHasAttribute( curfrm, attbuf ) ) { if( astGetI( curfrm, attbuf ) ) { lonval = xout[ i ]; } else { latval = xout[ i ]; } } } /* Store them in the FitsStore. */ SetItem( &(store->crval), axlon, 0, ' ', lonval*AST__DR2D, status ); SetItem( &(store->crval), axlat, 0, ' ', latval*AST__DR2D, status ); SetItem( &(store->crpix), 0, axlon, ' ', 1.0, status ); SetItem( &(store->crpix), 0, axlat, ' ', 1.0, status ); } } /* Get the CRVAL values for both spatial axes. */ latval = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status ); if( latval == AST__BAD ) ok = 0; lonval = GetItem( &( store->crval ), axlon, 0, s, NULL, method, class, status ); if( lonval == AST__BAD ) ok = 0; /* Get the CTYPE values for both axes. Extract the projection type as specified by the last 4 characters in the latitude CTYPE keyword value. */ cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { strcpy( lontype, cval ); } cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; prj = AST__WCSBAD; } else { strcpy( lattype, cval ); prj = astWcsPrjType( cval + 4 ); } /* Check the projection type is OK. */ if( prj == AST__WCSBAD ){ ok = 0; } else if( prj != AST__SIN ){ /* Check the projection code is OK. */ ok = 0; if( prj == AST__TAN || prj == AST__ARC || prj == AST__STG || prj == AST__AIT || prj == AST__SFL ) { ok = 1; /* For AIT, and SFL, check that the reference point is the origin of the celestial co-ordinate system. */ if( prj == AST__AIT || prj == AST__SFL ) { if( latval != 0.0 || lonval != 0.0 ){ ok = 0; /* Change the new SFL projection code to to the older equivalent GLS */ } else if( prj == AST__SFL ){ (void) strcpy( lontype + 4, "-GLS" ); (void) strcpy( lattype + 4, "-GLS" ); /* Change the new AIT projection code to to the older equivalent ATF */ } else if( prj == AST__AIT ){ (void) strcpy( lontype + 4, "-ATF" ); (void) strcpy( lattype + 4, "-ATF" ); } } } /* SIN projections are only acceptable if the associated projection parameters are both zero. */ } else { p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status ); p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status ); if( p1 == AST__BAD ) p1 = 0.0; if( p2 == AST__BAD ) p2 = 0.0; ok = ( p1 == 0.0 && p2 == 0.0 ); } /* Identify the celestial coordinate system from the first 4 characters of the longitude CTYPE value. Only RA and galactic longitude can be stored using FITS-CLASS. */ if( ok && strncmp( lontype, "RA--", 4 ) && strncmp( lontype, "GLON", 4 ) ) ok = 0; /* Get the CTYPE values for the spectral axis, and find the CLASS equivalent, if possible. */ cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else { if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) { strcpy( spectype, "FREQ" ); } else { ok = 0; } } /* If OK, check the SPECSYS value is SOURCE. */ cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else if( ok ) { if( strncmp( cval, "SOURCE", astChrLen( cval ) ) ) ok = 0; } /* If still OK, ensure the spectral axis units are Hz. */ cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; } else if( ok ) { if( !strcmp( cval, "Hz" ) ) { specfactor = 1.0; } else if( !strcmp( cval, "kHz" ) ) { specfactor = 1.0E3; } else if( !strcmp( cval, "MHz" ) ) { specfactor = 1.0E6; } else if( !strcmp( cval, "GHz" ) ) { specfactor = 1.0E9; } else { ok = 0; } } } /* Save the number of WCS axes */ naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1; /* If this is larger than 3, ignore the surplus WCS axes. Note, the above code has checked that the spatial and spectral axes are WCS axes 0, 1 and 2. */ if( naxis > 3 ) naxis = 3; /* Allocate memory to store the CDELT values */ if( ok ) { cdelt = (double *) astMalloc( sizeof(double)*naxis ); if( !cdelt ) ok = 0; } else { cdelt = NULL; } /* Check that there is no rotation, and extract the CDELT (diagonal) terms, etc. If the spatial axes are degenerate (i.e. cover only a single pixel) then ignore any rotation. */ if( !GetValue( this, FormatKey( "NAXIS", axlon + 1, -1, s, status ), AST__INT, &naxis2, 0, 0, method, class, status ) ) { naxis2 = 0; } if( !GetValue( this, FormatKey( "NAXIS", axlat + 1, -1, s, status ), AST__INT, &naxis3, 0, 0, method, class, status ) ) { naxis3 = 0; } for( i = 0; i < naxis && ok; i++ ){ cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdl == AST__BAD ) cdl = 1.0; for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdl; if( i == j ){ cdelt[ i ] = val; } else if( val != 0.0 ){ if( naxis2 != 1 || naxis3 != 1 ) ok = 0; } } } /* Get RADECSYS and the reference equinox. */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); equ = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); /* If RADECSYS was available... */ if( cval ){ /* Only FK4 and FK5 are supported in this encoding. */ if( strcmp( "FK4", cval ) && strcmp( "FK5", cval ) ) ok = 0; /* If epoch was not available, set a default epoch. */ if( equ == AST__BAD ){ if( !strcmp( "FK4", cval ) ){ equ = 1950.0; } else if( !strcmp( "FK5", cval ) ){ equ = 2000.0; } else { ok = 0; } /* If an epoch was supplied, check it is consistent with the IAU 1984 rule. */ } else { if( !strcmp( "FK4", cval ) ){ if( equ >= 1984.0 ) ok = 0; } else if( !strcmp( "FK5", cval ) ){ if( equ < 1984.0 ) ok = 0; } else { ok = 0; } } /* Check we have a rest frequency */ rf = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status ); if( rf == AST__BAD ) ok = 0; } /* If the spatial Frame covers more than a single Frame and requires a LONPOLE or LATPOLE keyword, it cannot be encoded using FITS-CLASS. However since FITS-CLASS imposes a no rotation restriction, it can tolerate lonpole values of +/- 180 degrees. */ if( ok && ( naxis2 != 1 || naxis3 != 1 ) ) { lonpole = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ); if( lonpole != AST__BAD && lonpole != -180.0 && lonpole == 180 ) ok = 0; if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ) != AST__BAD ) ok = 0; } /* Only create the keywords if the FitsStore conforms to the requirements of the FITS-CLASS encoding. */ if( ok ) { /* If celestial axes were added by MakeFitsFrameSet, we need to ensure the header contains 3 main array axes. This is because the CLASS encoding does not support the WCSAXES keyword. */ if( store->naxis == 1 ) { /* Update the "NAXIS" value to 3 or put a new card in at the start. */ astClearCard( this ); i = 3; SetValue( this, "NAXIS", &i, AST__INT, NULL, status ); /* Put NAXIS2/3 after NAXIS1, or after NAXIS if the FitsChan does not contain NAXIS1. These are set to 1 since the spatial axes are degenerate. */ if( FindKeyCard( this, "NAXIS1", method, class, status ) ) { MoveCard( this, 1, method, class, status ); } i = 1; SetValue( this, "NAXIS2", &i, AST__INT, NULL, status ); SetValue( this, "NAXIS3", &i, AST__INT, NULL, status ); } /* Find the last WCS related card. */ FindWcs( this, 1, 1, 0, method, class, status ); /* Get and save CRPIX for all pixel axes. These are required, so break if they are not available. */ for( j = 0; j < naxis && ok; j++ ){ val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { sprintf( combuf, "Reference pixel on axis %d", j + 1 ); SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CRVAL for all intermediate axes. These are required, so break if they are not available. Note, the frequency axis CRVAL is redefined by FITS-CLASS by reducing it by the RESTFREQ value. */ for( i = 0; i < naxis && ok; i++ ){ val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; } else { crval[ i ] = val; if( i == axspec ) { val *= specfactor; val -= rf; } sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save CTYPE for all intermediate axes. These are required, so break if they are not available. Use the potentially modified versions saved above for the celestial axes. */ for( i = 0; i < naxis && ok; i++ ){ if( i == axlat ) { cval = lattype; } else if( i == axlon ) { cval = lontype; } else if( i == axspec ) { cval = spectype; } else { cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); } if( cval && strcmp( cval + 4, "-TAB" ) ) { comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING, comm, status ); } else { ok = 0; } } /* CDELT values */ if( axspec != -1 ) cdelt[ axspec ] *= specfactor; for( i = 0; i < naxis; i++ ){ SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i, AST__FLOAT, "Pixel size", status ); } /* Reference equinox */ if( equ != AST__BAD ) SetValue( this, "EQUINOX", &equ, AST__FLOAT, "Epoch of reference equinox", status ); /* Date of observation. */ val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD ) { /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING, "Date of observation", status ); } /* Rest frequency */ SetValue( this, "RESTFREQ", &rf, AST__FLOAT, "[Hz] Rest frequency", status ); /* The image frequency corresponding to the rest frequency (only used for double sideband data). */ val = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { SetValue( this, "IMAGFREQ", &val, AST__FLOAT, "[Hz] Image frequency", status ); } /* Ensure the FitsChan contains OBJECT and LINE headers */ if( !HasCard( this, "OBJECT", method, class, status ) ) { cval = " "; SetValue( this, "OBJECT", &cval, AST__STRING, NULL, status ); } if( !HasCard( this, "LINE", method, class, status ) ) { cval = " "; SetValue( this, "LINE", &cval, AST__STRING, NULL, status ); } /* CLASS expects the VELO-LSR keyword to hold the radio velocity of the reference channel (NOT of the source as I was told!!) with respect to the LSRK rest frame. The "crval" array holds the frequency of the reference channel in the source rest frame, so we need to convert this to get the value for VELO-LSR. Create a SpecFrame describing the required frame (other attributes such as Epoch etc are left unset and so will be picked up from the supplied FrameSet). We set MinAxes and MaxAxes so that the Frame can be used as a template to match the 1D or 3D current Frame in the supplied FrameSet. */ velofrm = (AstFrame *) astSpecFrame( "System=vrad,StdOfRest=lsrk," "Unit=m/s,MinAxes=1,MaxAxes=3", status ); /* Find the spectral axis within the current Frame of the supplied FrameSet, using the above "velofrm" as a template. */ fsconv1 = astFindFrame( curfrm, velofrm, "" ); /* If OK, extract the SpecFrame from the returned FraneSet (this will have the attribute values that were assigned explicitly to "velofrm" and will have inherited all unset attributes from the supplied FrameSet). */ if( fsconv1 ) { velofrm = astAnnul( velofrm ); velofrm = astGetFrame( fsconv1, AST__CURRENT ); fsconv1 = astAnnul( fsconv1 ); /* Take a copy of the velofrm and modify its attributes so that it describes frequency in the sources rest frame in units of Hz. This is the system that CLASS expects for the CRVAL3 keyword. */ freqfrm = astCopy( velofrm ); astSet( freqfrm, "System=freq,StdOfRest=Source,Unit=Hz", status ); /* Get a Mapping from frequency to velocity. */ fsconv1 = astConvert( freqfrm, velofrm, "" ); if( fsconv1 ) { /* Use this Mapping to convert the spectral crval value from frequency to velocity. Also convert the value for the neighbouring channel. */ aval[ 0 ] = crval[ axspec ]*specfactor; aval[ 1 ] = aval[ 0 ] + cdelt[ axspec ]*specfactor; astTran1( fsconv1, 2, aval, 1, aval ); /* Store the value. Also store it as VLSR since this keyword seems to be used for the same thing. */ SetValue( this, "VELO-LSR", aval, AST__FLOAT, "[m/s] Reference velocity", status ); SetValue( this, "VLSR", aval, AST__FLOAT, "[m/s] Reference velocity", status ); /* The DELTAV keyword holds the radio velocity channel spacing in the LSR. */ delta = aval[ 1 ] - aval[ 0 ]; SetValue( this, "DELTAV", &delta, AST__FLOAT, "[m/s] Velocity resolution", status ); /* Free remaining resources. */ fsconv1 = astAnnul( fsconv1 ); } } velofrm = astAnnul( velofrm ); /* AZIMUTH and ELEVATIO - the (az,el) equivalent of CRVAL. We need a Mapping from the CTYPE spatial system to (az,el). This depends on all the extra info like telescope position, epoch, etc. This info is in the current Frame in the supplied FrameSet. First get a conversion from a sky frame with default axis ordering to the supplied Frame. All the extra info is picked up from the supplied Frame since it is not set in the template. */ radecfrm = (AstFrame *) astSkyFrame( "Permute=0,MinAxes=3,MaxAxes=3", status ); fsconv1 = astFindFrame( curfrm, radecfrm, "" ); /* Now get conversion from the an (az,el) Frame to the supplied Frame. */ azelfrm = (AstFrame *) astSkyFrame( "System=AZEL,Permute=0,MinAxes=3,MaxAxes=3", status ); fsconv2 = astFindFrame( curfrm, azelfrm, "" ); /* If both conversions werew possible, concatenate their Mappings to get a Mapping from (lon,lat) in the CTYPE system, to (az,el). */ if( fsconv1 && fsconv2 ) { map1 = astGetMapping( fsconv1, AST__CURRENT, AST__BASE ); map2 = astGetMapping( fsconv2, AST__BASE, AST__CURRENT ); map3 = (AstMapping *) astCmpMap( map1, map2, 1, "", status ); /* Store the CRVAL (ra,dec) values in the default order. */ radec[ 0 ] = crval[ axlon ]*AST__DD2R; radec[ 1 ] = crval[ axlat ]*AST__DD2R; /* Transform to (az,el), normalise, convert to degrees and store. */ astTranN( map3, 1, 2, 1, radec, 1, 2, 1, azel ); if( azel[ 0 ] != AST__BAD && azel[ 1 ] != AST__BAD ) { astNorm( azelfrm, azel ); azel[ 0 ] *= AST__DR2D; azel[ 1 ] *= AST__DR2D; SetValue( this, "AZIMUTH", azel, AST__FLOAT, "[Deg] Telescope azimuth", status ); SetValue( this, "ELEVATIO", azel + 1, AST__FLOAT, "[Deg] Telescope elevation", status ); } /* Free resources */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); fsconv1 = astAnnul( fsconv1 ); fsconv2 = astAnnul( fsconv2 ); } radecfrm = astAnnul( radecfrm ); azelfrm = astAnnul( azelfrm ); } curfrm = astAnnul( curfrm ); /* Release CDELT workspace */ if( cdelt ) cdelt = (double *) astFree( (void *) cdelt ); /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ok : 0; } static void ClassTrans( AstFitsChan *this, AstFitsChan *ret, int axlat, int axlon, const char *method, const char *class, int *status ){ /* * Name: * ClassTrans * Purpose: * Translated non-standard FITS-CLASS headers into equivalent standard * ones. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void ClassTrans( AstFitsChan *this, AstFitsChan *ret, int axlat, * int axlon, const char *method, const char *class ) * Class Membership: * FitsChan member function. * Description: * This function extends the functionality of the SpecTrans function, * by converting non-standard WCS keywords into standard FITS-WCS * keywords, using the conventions of the FITS-CLASS encoding. * Parameters: * this * Pointer to the FitsChan containing the original header cards. * ret * Pointer to a FitsChan in which to return the standardised header * cards. * axlat * Zero-based index of the celestial latitude axis. * axlon * Zero-based index of the celestial longitude axis. * method * Pointer to string holding name of calling method. * class * Pointer to a string holding the name of the supplied object class. */ /* Local Variables: */ char *cval; /* Pointer to character string */ char newtype[ 10 ]; /* New CTYPE value */ const char *keyname; /* Pointer to keyword name */ const char *ssyssrc; /* Pointer to SSYSSRC keyword value string */ double crval; /* CRVAL value */ double restfreq; /* Rest frequency (Hz) */ double v0; /* Ref channel velocity in source frame */ double vref; /* Ref channel velocity in LSR or whatever */ double vsource; /* Source velocity */ double zsource; /* Source redshift */ int axspec; /* Index of spectral axis */ /* Check the global error status. */ if ( !astOK ) return; /* Get the rest frequency. */ restfreq = AST__BAD; if( !GetValue2( ret, this, "RESTFRQ", AST__FLOAT, (void *) &restfreq, 0, method, class, status ) ){ GetValue2( ret, this, "RESTFREQ", AST__FLOAT, (void *) &restfreq, 0, method, class, status ); } if( restfreq == AST__BAD ) { astError( AST__BDFTS, "%s(%s): Keyword RESTFREQ not found in CLASS " "FITS header.", status, method, class ); } /* Get the index of the spectral axis. */ if( axlat + axlon == 1 ) { axspec = 2; } else if( axlat + axlon == 3 ) { axspec = 0; } else { axspec = 1; } /* Get the spectral CTYPE value */ if( GetValue2( ret, this, FormatKey( "CTYPE", axspec + 1, -1, ' ', status ), AST__STRING, (void *) &cval, 0, method, class, status ) ){ /* We can only handle frequency axes at the moment. */ if( !astChrMatch( "FREQ", cval ) ) { astError( AST__BDFTS, "%s(%s): FITS-CLASS keyword %s has value " "\"%s\" - CLASS support in AST only includes \"FREQ\" axes.", status, method, class, FormatKey( "CTYPE", axspec + 1, -1, ' ', status ), cval ); /* CRVAL for the spectral axis needs to be incremented by RESTFREQ if the axis represents frequency. */ } else { keyname = FormatKey( "CRVAL", axspec + 1, -1, ' ', status ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &crval, 1, method, class, status ) ) { crval += restfreq; SetValue( ret, keyname, (void *) &crval, AST__FLOAT, NULL, status ); } } /* CLASS frequency axes describe source frame frequencies. */ cval = "SOURCE"; SetValue( ret, "SPECSYS", (void *) &cval, AST__STRING, NULL, status ); } /* If no projection code is supplied for the longitude and latitude axes, use "-GLS". This will be translated to "-SFL" by SpecTrans. */ keyname = FormatKey( "CTYPE", axlon + 1, -1, ' ', status ); if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) ){ if( !strncmp( " ", cval + 4, 4 ) ) { strncpy( newtype, cval, 4 ); strcpy( newtype + 4, "-GLS" ); cval = newtype; SetValue( ret, keyname, (void *) &cval, AST__STRING, NULL, status ); } } keyname = FormatKey( "CTYPE", axlat + 1, -1, ' ', status ); if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) ){ if( !strncmp( " ", cval + 4, 4 ) ) { strncpy( newtype, cval, 4 ); strcpy( newtype + 4, "-GLS" ); cval = newtype; SetValue( ret, keyname, (void *) &cval, AST__STRING, NULL, status ); } } /* Look for a keyword with name "VELO-...". This specifies the radio velocity at the reference channel, in a standard of rest specified by the "..." in the keyword name. If "VELO-..." is not found, look for "VLSR", which is the same as "VELO-LSR". */ if( GetValue2( ret, this, "VELO-%3c", AST__FLOAT, (void *) &vref, 0, method, class, status ) || GetValue2( ret, this, "VLSR", AST__FLOAT, (void *) &vref, 0, method, class, status ) ){ /* Calculate the radio velocity (in the rest frame of the source) corresponding to the frequency at the reference channel. */ v0 = AST__C*( restfreq - crval )/restfreq; /* Assume that the source velocity is the difference between this velocity and the reference channel velocity given by "VELO-..." */ vsource = vref - v0; /* Get the keyword name and find the corresponding SSYSSRC keyword value. */ keyname = CardName( this, status ); if( !strcmp( keyname, "VELO-HEL" ) ) { ssyssrc = "BARYCENT"; } else if( !strcmp( keyname, "VELO-OBS" ) || !strcmp( keyname, "VELO-TOP" ) ) { ssyssrc = "TOPOCENT"; } else if( !strcmp( keyname, "VELO-EAR" ) || !strcmp( keyname, "VELO-GEO" ) ) { ssyssrc = "GEOCENTR"; } else { ssyssrc = "LSRK"; } SetValue( ret, "SSYSSRC", (void *) &ssyssrc, AST__STRING, NULL, status ); /* Convert from radio velocity to redshift and store as ZSOURCE */ zsource = ( AST__C / (AST__C - vsource) ) - 1.0; SetValue( ret, "ZSOURCE", (void *) &zsource, AST__FLOAT, NULL, status ); } } static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * FitsChan member function (over-rides the astClearAttrib protected * method inherited from the Channel class). * Description: * This function clears the value of a specified attribute for a * FitsChan, so that the default value will subsequently be used. * Parameters: * this * Pointer to the FitsChan. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Check the attribute name and clear the appropriate attribute. */ /* Card. */ /* ----- */ if ( !strcmp( attrib, "card" ) ) { astClearCard( this ); /* Encoding. */ /* --------- */ } else if ( !strcmp( attrib, "encoding" ) ) { astClearEncoding( this ); /* CDMatrix */ /* -------- */ } else if ( !strcmp( attrib, "cdmatrix" ) ) { astClearCDMatrix( this ); /* FitsDigits. */ /* ----------- */ } else if ( !strcmp( attrib, "fitsdigits" ) ) { astClearFitsDigits( this ); /* DefB1950 */ /* -------- */ } else if ( !strcmp( attrib, "defb1950" ) ) { astClearDefB1950( this ); /* TabOK */ /* ----- */ } else if ( !strcmp( attrib, "tabok" ) ) { astClearTabOK( this ); /* CarLin */ /* ------ */ } else if ( !strcmp( attrib, "carlin" ) ) { astClearCarLin( this ); /* PolyTan */ /* ------- */ } else if ( !strcmp( attrib, "polytan" ) ) { astClearPolyTan( this ); /* Iwc */ /* --- */ } else if ( !strcmp( attrib, "iwc" ) ) { astClearIwc( this ); /* Clean */ /* ----- */ } else if ( !strcmp( attrib, "clean" ) ) { astClearClean( this ); /* Warnings. */ /* -------- */ } else if ( !strcmp( attrib, "warnings" ) ) { astClearWarnings( this ); /* If the name was not recognised, test if it matches any of the read-only attributes of this class. If it does, then report an error. */ } else if ( astOK && ( !strcmp( attrib, "ncard" ) || !strcmp( attrib, "allwarnings" ) ) ){ astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " "value for a %s.", status, attrib, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static void ClearCard( AstFitsChan *this, int *status ){ /* *+ * Name: * astClearCard * Purpose: * Clear the Card attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * void astClearCard( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function clears the Card attribute for the supplied FitsChan by * setting it to the index of the first un-used card in the FitsChan. * This causes the next read operation performed on the FitsChan to * read the first card. Thus, it is equivalent to "rewinding" the FitsChan. * Parameters: * this * Pointer to the FitsChan. * Notes: * - This function attempts to execute even if an error has occurred. *- */ /* Local Variables; */ astDECLARE_GLOBALS /* Declare the thread specific global data */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Check the supplied FitsChan. If its is empty, return. */ if ( !this || !(this->head) ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Set the pointer to the current card so that it points to the card at the head of the list. */ this->card = this->head; /* If the current card has been read into an AST object, move on to the first card which has not, unless we are not skipping such cards. */ if( CARDUSED(this->card) ){ MoveCard( this, 1, "astClearCard", astGetClass( this ), status ); } } static int CnvValue( AstFitsChan *this, int type, int undef, void *buff, const char *method, int *status ){ /* * * Name: * CnvValue * Purpose: * Convert a data value into a given FITS data type. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int CnvValue( AstFitsChan *this, int type, int undef, void *buff, * const char *method, int *status ) * Class Membership: * FitsChan method. * Description: * This function produces a copy of the data value for the current card * converted from its stored data type to the supplied data type. * Parameters: * this * Pointer to the FitsChan. * type * The FITS data type in which to return the data value of the * current card. * undef * Determines what happens if the current card has an undefined * value. If "undef" is zero, an error will be reported identifying * the undefined keyword value. If "undef" is non-zero, no error is * reported and the contents of the output buffer are left unchanged. * buf * A pointer to a buffer to recieve the converted value. It is the * responsibility of the caller to ensure that a suitable buffer is * supplied. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the conversion was not possible (in which case NO error is * reported), one otherwise. * Notes: * - When converting from floating point to integer, the floating * point value is truncated using a C cast. * - Non-zero numerical values are considered TRUE, and zero * numerical values are considered FALSE. Any string starting with a * 'T' or a 'Y' (upper or lower case) is considered TRUE, and anything * starting with an 'F' or an 'N' (upper or lower case) is considered * FALSE. In addition, a dot ('.') may be placed in front of a 'T' or an * 'F'. * - A logical TRUE value is represented as a real numerical value of * one and the character string "Y". A logical FALSE value is represented * by a real numerical value of zero and the character string "N". * - When converting from a string to any numerical value, zero is * returned if the string is not a formatted value which can be converted * into the corresponding type using astSscanf. * - Real and imaginary parts of a complex value should be separated by * spaces within strings. If a string does contains only a single numerical * value, it is assumed to be the real part, and the imaginary part is * assumed to be zero. * - When converting a complex numerical type to a non-complex numerical * type, the returned value is derived from the real part only, the * imaginary part is ignored. * - Zero is returned if an error has occurred, or if this function * should fail for any reason. * - If the supplied value is undefined an error will be reported. */ /* Local Variables: */ int otype; /* Stored data type */ size_t osize; /* Size of stored data */ void *odata; /* Pointer to stored data */ /* Check the global error status, and the supplied buffer. */ if ( !astOK || !buff ) return 0; /* Get the type in which the data value is stored. */ otype = CardType( this, status ); /* Get a pointer to the stored data value, and its size. */ osize = 0; odata = CardData( this, &osize, status ); /* Do the conversion. */ return CnvType( otype, odata, osize, type, undef, buff, CardName( this, status ), method, astGetClass( this ), status ); } static int CnvType( int otype, void *odata, size_t osize, int type, int undef, void *buff, const char *name, const char *method, const char *class, int *status ){ /* * * Name: * CnvType * Purpose: * Convert a data value into a given FITS data type. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int CnvType( int otype, void *odata, size_t osize, int type, int undef, * void *buff, const char *name, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan method. * Description: * This function produces a copy of the data value for the current card * converted from its stored data type to the supplied data type. * Parameters: * otype * The type of the supplied data value. * odata * Pointer to a buffer holding the supplied data value. * osize * The size of the data value (in bytes - strings include the * terminating null). * type * The FITS data type in which to return the data value of the * current card. * undef * Determines what happens if the supplied data value type is * undefined If "undef" is zero, an error will be reported identifying * the undefined keyword value. If "undef" is non-zero, no error is * reported and the contents of the output buffer are left unchanged. * buff * A pointer to a buffer to recieve the converted value. It is the * responsibility of the caller to ensure that a suitable buffer is * supplied. * name * A pointer to a string holding a keyword name to include in error * messages. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the conversion was not possible (in which case NO error is * reported), one otherwise. * Notes: * - When converting from floating point to integer, the floating * point value is truncated using a C cast. * - Non-zero numerical values are considered TRUE, and zero * numerical values are considered FALSE. Any string starting with a * 'T' or a 'Y' (upper or lower case) is considered TRUE, and anything * starting with an 'F' or an 'N' (upper or lower case) is considered * FALSE. In addition, a dot ('.') may be placed in front of a 'T' or an * 'F'. * - A logical TRUE value is represented as a real numerical value of * one and the character string "Y". A logical FALSE value is represented * by a real numerical value of zero and the character string "N". * - When converting from a string to any numerical value, zero is * returned if the string isn not a formatted value which can be converted * into the corresponding type using astSscanf. * - Real and imaginary parts of a complex value should be separated by * spaces within strings. If a string does contains only a single numerical * value, it is assumed to be the real part, and the imaginary part is * assumed to be zero. * - When converting a complex numerical type to a non-complex numerical * type, the returned value is derived from the real part only, the * imaginary part is ignored. * - Zero is returned if an error has occurred, or if this function * should fail for any reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *c; /* Pointer to next character */ const char *ostring; /* String data value */ double odouble; /* Double data value */ int oint; /* Integer data value */ int ival; /* Integer value read from string */ int len; /* Length of character string */ int nc; /* No. of characetsr used */ int ret; /* Returned success flag */ /* Check the global error status, and the supplied buffer. */ if ( !astOK || !buff ) return 0; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* Assume success. */ ret = 1; /* If the supplied data type is undefined, report an error unless the returned data type is also undefined or an undefined value is acceptable for the keyword. */ if( otype == AST__UNDEF ) { if( type != AST__UNDEF && !undef ) { ret = 0; astError( AST__FUNDEF, "The FITS keyword '%s' has an undefined " "value.", status, name ); } /* If the returned data type is undefined, the returned value is immaterial, so leave the buffer contents unchanged. */ } else if( type == AST__UNDEF ) { /* If there is no data value and this is not a COMMENT keyword, or if there is a data value and this is a COMMENT card, conversion is not possible. */ } else if( ( odata && otype == AST__COMMENT ) || ( !odata && otype != AST__COMMENT ) ) { ret = 0; /* If there is no data (and therefore this is a comment card), leave the supplied buffers unchanged. */ } else if( odata ) { /* Do each possible combination of supplied and stored data types... */ /* Convert a AST__FLOAT data value to ... */ if( otype == AST__FLOAT ){ odouble = *( (double *) odata ); if( type == AST__FLOAT ){ (void) memcpy( buff, odata, osize ); } else if( type == AST__STRING || type == AST__CONTINUE ){ if( odouble != AST__BAD ) { (void) sprintf( cnvtype_text, "%.*g", DBL_DIG, odouble ); CheckZero( cnvtype_text, odouble, 0, status ); } else { strcpy( cnvtype_text, BAD_STRING ); } *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ *( (int *) buff ) = (int) odouble; } else if( type == AST__LOGICAL ){ *( (int *) buff ) = ( odouble == 0.0 ) ? 0 : 1; } else if( type == AST__COMPLEXF ){ ( (double *) buff )[ 0 ] = odouble; ( (double *) buff )[ 1 ] = 0.0; } else if( type == AST__COMPLEXI ){ ( (int *) buff )[ 0 ] = (int) odouble; ( (int *) buff )[ 1 ] = 0; } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } /* Convert a AST__STRING data value to ... */ } else if( otype == AST__STRING || type == AST__CONTINUE ){ ostring = (char *) odata; len = (int) strlen( ostring ); if( type == AST__FLOAT ){ if( nc = 0, ( 0 == astSscanf( ostring, BAD_STRING " %n", &nc ) ) && (nc >= len ) ){ *( (double *) buff ) = AST__BAD; } else if( nc = 0, ( 1 != astSscanf( ostring, "%lf %n", (double *) buff, &nc ) ) || (nc < len ) ){ ret = 0; } } else if( type == AST__STRING || type == AST__CONTINUE ){ strncpy( cnvtype_text, (char *) odata, AST__FITSCHAN_FITSCARDLEN ); *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ if( nc = 0, ( 1 != astSscanf( ostring, "%d %n", (int *) buff, &nc ) ) || (nc < len ) ){ ret = 0; } } else if( type == AST__LOGICAL ){ if( nc = 0, ( 1 == astSscanf( ostring, "%d %n", &ival, &nc ) ) && (nc >= len ) ){ *( (int *) buff ) = ival ? 1 : 0; } else { c = ostring; while( *c && isspace( (int) *c ) ) c++; if( *c == 'y' || *c == 'Y' || *c == 't' || *c == 'T' || ( *c == '.' && ( c[1] == 't' || c[1] == 'T' ) ) ){ *( (int *) buff ) = 1; } else if( *c == 'n' || *c == 'N' || *c == 'f' || *c == 'F' || ( *c == '.' && ( c[1] == 'f' || c[1] == 'F' ) ) ){ *( (int *) buff ) = 0; } else { ret = 0; } } } else if( type == AST__COMPLEXF ){ if( nc = 0, ( 1 != astSscanf( ostring, "%lf %lf %n", (double *) buff, (double *) buff + 1, &nc ) ) || (nc < len ) ){ if( nc = 0, ( 1 != astSscanf( ostring, "%lf %n", (double *) buff, &nc ) ) || (nc < len ) ){ ret = 0; } else { ( (double *) buff )[ 1 ] = 0.0; } } } else if( type == AST__COMPLEXI ){ if( nc = 0, ( 1 != astSscanf( ostring, "%d %d %n", (int *) buff, (int *) buff + 1, &nc ) ) || (nc < len ) ){ if( nc = 0, ( 1 != astSscanf( ostring, "%d %n", (int *) buff, &nc ) ) || (nc < len ) ){ ret = 0; } else { ( (int *) buff )[ 1 ] = 0; } } } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } /* Convert an AST__INT data value to ... */ } else if( otype == AST__INT ){ oint = *( (int *) odata ); if( type == AST__FLOAT ){ *( (double *) buff ) = (double) oint; } else if( type == AST__STRING || type == AST__CONTINUE ){ (void) sprintf( cnvtype_text, "%d", oint ); *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ (void) memcpy( buff, odata, osize ); } else if( type == AST__LOGICAL ){ *( (int *) buff ) = oint ? 1 : 0; } else if( type == AST__COMPLEXF ){ ( (double *) buff )[ 0 ] = (double) oint; ( (double *) buff )[ 1 ] = 0.0; } else if( type == AST__COMPLEXI ){ ( (int *) buff )[ 0 ] = oint; ( (int *) buff )[ 1 ] = 0; } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } /* Convert a LOGICAL data value to ... */ } else if( otype == AST__LOGICAL ){ oint = *( (int *) odata ); if( type == AST__FLOAT ){ *( (double *) buff ) = oint ? 1.0 : 0.0; } else if( type == AST__STRING || type == AST__CONTINUE ){ if( oint ){ strcpy( cnvtype_text, "Y" ); } else { strcpy( cnvtype_text, "N" ); } *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ *( (int *) buff ) = oint; } else if( type == AST__LOGICAL ){ (void) memcpy( buff, odata, osize ); } else if( type == AST__COMPLEXF ){ ( (double *) buff )[ 0 ] = oint ? 1.0 : 0.0; ( (double *) buff )[ 1 ] = 0.0; } else if( type == AST__COMPLEXI ){ ( (int *) buff )[ 0 ] = oint ? 1 : 0; ( (int *) buff )[ 1 ] = 0; } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } /* Convert a AST__COMPLEXF data value to ... */ } else if( otype == AST__COMPLEXF ){ odouble = ( (double *) odata )[ 0 ]; if( type == AST__FLOAT ){ *( (double *) buff ) = odouble; } else if( type == AST__STRING || type == AST__CONTINUE ){ (void) sprintf( cnvtype_text0, "%.*g", DBL_DIG, ( (double *) odata )[ 0 ] ); CheckZero( cnvtype_text0, ( (double *) odata )[ 0 ], 0, status ); (void) sprintf( cnvtype_text1, "%.*g", DBL_DIG, ( (double *) odata )[ 1 ] ); CheckZero( cnvtype_text1, ( (double *) odata )[ 1 ], 0, status ); (void) sprintf( cnvtype_text, "%s %s", cnvtype_text0, cnvtype_text1 ); *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ *( (int *) buff ) = (int) odouble; } else if( type == AST__LOGICAL ){ *( (int *) buff ) = ( odouble == 0.0 ) ? 0 : 1; } else if( type == AST__COMPLEXF ){ (void) memcpy( buff, odata, osize ); } else if( type == AST__COMPLEXI ){ ( (int *) buff )[ 0 ] = (int) odouble; ( (int *) buff )[ 1 ] = (int) ( (double *) odata )[ 1 ]; } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } /* Convert a AST__COMPLEXI data value to ... */ } else if( otype == AST__COMPLEXI ){ oint = ( (int *) odata )[ 0 ]; if( type == AST__FLOAT ){ *( (double *) buff ) = (double) oint; } else if( type == AST__STRING || type == AST__CONTINUE ){ (void) sprintf( cnvtype_text, "%d %d", ( (int *) odata )[ 0 ], ( (int *) odata )[ 1 ] ); *( (char **) buff ) = cnvtype_text; } else if( type == AST__INT ){ *( (int *) buff ) = oint; } else if( type == AST__LOGICAL ){ *( (int *) buff ) = oint ? 1 : 0; } else if( type == AST__COMPLEXF ){ ( (double *) buff )[ 0 ] = (double) oint; ( (double *) buff )[ 1 ] = (double) ( (int *) odata )[ 1 ]; } else if( type == AST__COMPLEXI ){ (void) memcpy( buff, odata, osize ); } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } } else if( astOK ){ ret = 0; astError( AST__INTER, "CnvType: AST internal programming error - " "FITS data-type no. %d not yet supported.", status, type ); } } return ret; } static int ComBlock( AstFitsChan *this, int incr, const char *method, const char *class, int *status ){ /* * Name: * ComBlock * Purpose: * Delete a AST comment block in a Native-encoded FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int ComBlock( AstFitsChan *this, int incr, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function looks for a block of comment cards as defined below, * and deletes all the cards in the block, if a suitable block is found. * * Comment blocks consist of a contiguous sequence of COMMENT cards. The * text of each card should start and end with the 3 characters "AST". * The block is delimited above by a card containing all +'s (except * for the two "AST" strings), and below by a card containing all -'s. * * The block is assumed to start on the card which is adjacent to the * current card on entry. * Parameters: * this * Pointer to the FitsChan. * incr * This should be either +1 or -1, and is the increment between * adjacent cards in the comment block. A value of +1 means * that the card following the current card is taken as the first in * the block, and subsequent cards are checked. The block must then * end with a line of -'s. If -1 is supplied, then the card * preceding the current card is taken as the first in the block, * and preceding cards are checked. The block must then end with * a row of +'s. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * 1 if a block was found and deleted, 0 otherwise. * Notes: * - The pointer to the current card is returned unchanged. */ /* Local Variables: */ FitsCard *card0; /* Pointer to current FitsCard on entry */ char del; /* Delimiter character */ char *text; /* Pointer to the comment text */ int i; /* Card index within the block */ int ncard; /* No. of cards in the block */ int ret; /* The returned flag */ size_t len; /* Length of the comment text */ /* Check the global status. */ if( !astOK ) return 0; /* Save the pointer to the current card. */ card0 = this->card; /* Initialise the returned flag to indicate that we have not found a comment block. */ ret = 0; /* Move on to the first card in the block. If this is not possible (due to us already being at the start or end of the FitsChan), then return. */ if( MoveCard( this, incr, method, class, status ) == 1 ) { /* Store the character which is used in the delimiter line for the comment block. */ del = ( incr == 1 ) ? '-' : '+'; /* Initialise the number of cards in the comment block to zero. */ ncard = 0; /* Loop round until the end (or start) of the comment block is found. Leave the loop if an error occurs. */ while( astOK ) { /* Is this card a comment card? If not, then we have failed to find a complete comment block. Break out of the loop. */ if( CardType( this, status ) != AST__COMMENT ) break; /* Increment the number of cards in the comment block. */ ncard++; /* Get the text of the comment, and its length. */ text = CardComm( this, status ); if( text ){ len = strlen( text ); /* Check the first 3 characters. Break out of the loop if they are not "AST". */ if( strncmp( "AST", text, 3 ) ) break; /* Check the last 3 characters. Break out of the loop if they are not "AST". */ if( strcmp( "AST", text + len - 3 ) ) break; /* If the comment is the appropriate block delimiter (a line of +'s or -'s depending on the direction), then set the flag to indicate that we have a complete comment block and leave the loop. Allow spaces to be included. Exclude the "AST" strings at begining and end from the check. */ ret = 1; for( i = 3; i < len - 3; i++ ) { if( text[ i ] != del && text[ i ] != ' ' ) { ret = 0; break; } } } if( ret ) break; /* Move on to the next card. If this is not possible (due to us already being at the start or end of the FitsChan), then break out of the loop. */ if( MoveCard( this, incr, method, class, status ) == 0 ) break; } /* Re-instate the original current card. */ this->card = card0; /* If we found a complete comment block, mark it (which is equivalent to deleting it except that memory of the cards location within the FitsChan is preserved for future use), and then re-instate the original current card. */ if( ret && astOK ) { for( i = 0; i < ncard; i++ ) { MoveCard( this, incr, method, class, status ); MarkCard( this, status ); } this->card = card0; } } /* If an error occurred, indicate that coment block has been deleted. */ if( !astOK ) ret = 0; return ret; } static char *ConcatWAT( AstFitsChan *this, int iaxis, const char *method, const char *class, int *status ){ /* * Name: * ConcatWAT * Purpose: * Concatenate all the IRAF "WAT" keywords for an axis. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *ConcatWAT( AstFitsChan *this, int iaxis, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function searches the supplied FitsChan for any keywords of * the form "WATi_j", where i and j are integers and i is equal to the * supplied "iaxis" value plus one, and concatenates their string * values into a single string. Such keywords are created by IRAF to * describe their non-standard ZPX and TNX projections. * Parameters: * this * The FistChan. * iaxis * The zero-based index of the axis to be retrieved. * method * The name of the calling method to include in error messages. * class * The object type to include in error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated, null terminated string * containing a copy of the concatentated WAT values. This string must * be freed by the caller (using astFree) when no longer required. * * A NULL pointer will be returned if there are no WAT kewyords for * the requested axis in the FitsChan. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ char keyname[ FITSNAMLEN + 5 ];/* Keyword name */ char *wat; /* Pointer to a single WAT string */ char *result; /* Returned string */ int watlen; /* Length of total WAT string (inc. term null)*/ int j; /* WAT index */ size_t size; /* Length of string value */ /* Initialise returned value. */ result = NULL; /* Check inherited status */ if( !astOK ) return result; /* Rewind the FitsChan. */ astClearCard( this ); /* Concatenate all the IRAF "WAT" keywords together for this axis. These keywords are marked as having been used, so that they are not written out when the FitsChan is deleted. */ watlen = 1; j = 1; size = 0; sprintf( keyname, "WAT%d_%.3d", iaxis + 1, j ); while( astOK ) { /* Search forward from the current card for the next WAT card. If no found, try searching again from the start of the FitsChan. If not found evenm then, break. */ if( ! FindKeyCard( this, keyname, method, class, status ) ) { astClearCard( this ); if( ! FindKeyCard( this, keyname, method, class, status ) ) break; } wat = (char *) CardData( this, &size, status ); result = (char *) astRealloc( (void *) result, watlen - 1 + size ); if( result ) { strcpy( result + watlen - 1, wat ); watlen += size - 1; MarkCard( this, status ); MoveCard( this, 1, method, class, status ); j++; sprintf( keyname, "WAT%d_%.3d", iaxis + 1, j ); } else { break; } } /* Return the result. */ return result; } static int CountFields( const char *temp, char type, const char *method, const char *class, int *status ){ /* * Name: * CountFields * Purpose: * Count the number of field specifiers in a template string. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int CountFields( const char *temp, char type, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns the number of fields which include the * specified character type in the supplied string. * Parameters: * temp * Pointer to a null terminated string holding the template. * type * A single character giving the field type to be counted (e.g. * 'd', 'c' or 'f'). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The number of fields. * Notes: * - No error is reported if the parameter "type" is not a valid * field type specifier, but zero will be returned. * - An error is reported if the template has any invalid field * specifiers in it. * - A value of zero is returned if an error has already occurred, * or if this function should fail for any reason. */ /* Local Variables: */ const char *b; /* Pointer to next template character */ int nf; /* No. of fields found so far */ /* Check global status. */ if( !astOK ) return 0; /* Initialise a pointer to the start of the template string. */ b = temp; /* Initialise the number of fields found so far. */ nf = 0; /* Go through the string. */ while( *b && astOK ){ /* If the current character is a '%', a field is starting. */ if( *b == '%' ){ /* Skip over the field width (if supplied). */ if( isdigit( (int) *(++b) ) ) b++; /* Report an error if the end of the string occurs within the field. */ if( !*b ) { astError( AST__BDFMT, "%s(%s): Incomplete field specifier found " "at end of filter template '%s'.", status, method, class, temp ); break; /* Report an error if the field type is illegal. */ } else if( *b != 'd' && *b != 'c' && *b != 'f' ) { astError( AST__BDFMT, "%s(%s): Illegal field type or width " "specifier '%c' found in filter template '%s'.", status, method, class, *b, temp ); break; } /* Compare the field type with the supplied type, and increment the number of fields found if it is the correct type. */ if( *b == type ) nf++; } /* Move on to the next character. */ b++; } /* If an error has occurred, return 0. */ if( !astOK ) nf = 0; /* Return the answer. */ return nf; } static void CreateKeyword( AstFitsChan *this, const char *name, char keyword[ FITSNAMLEN + 1 ], int *status ){ /* * Name: * CreateKeyword * Purpose: * Create a unique un-used keyword for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void CreateKeyword( AstFitsChan *this, const char *name, * char keyword[ FITSNAMLEN + 1 ], int *status ) * Class Membership: * FitsChan member function. * Description: * This function takes a name which forms the basis of a FITS * keyword and appends a sequence number (encoded as a pair of * legal FITS keyword characters) so as to generate a unique FITS * keyword which has not previously been used in the FitsChan * supplied. * * It is intended for use when several keywords with the same name * must be stored in a FitsChan, since to comply strictly with the * FITS standard keywords should normally be unique (otherwise * external software which processes the keywords might omit one or * other of the values). * * An attempt is also made to generate keywords in a form that is * unlikely to clash with those from other sources (in as far as * this is possible with FITS). In any event, a keyword that * already appears in the FitsChan will not be re-used. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a constant null-terminated string containing the * name on which the new keyword should be based. This should be * a legal FITS keyword in itself, except that it should be at * least two characters shorter than the maximum length, in * order to accommodate the sequence number characters. * * If this string is too long, it will be silently * truncated. Mixed case is permitted, as all characters * supplied are converted to upper case before use. * keyword * A character array in which the generated unique keyword will * be returned, null terminated. * status * Pointer to the inherited status variable. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *seq_chars = SEQ_CHARS;/* Pointer to characters used for encoding */ char seq_char; /* The first sequence character */ const char *class; /* Object clas */ int found; /* Keyword entry found in list? */ int limit; /* Sequence number has reached limit? */ int nc; /* Number of basic keyword characters */ int seq; /* The sequence number */ /* Check the global error status. */ if( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Store the object class. */ class = astGetClass( this ); /* On the first invocation only, determine the number of characters being used to encode sequence number information and save this value. */ if( createkeyword_seq_nchars < 0 ) createkeyword_seq_nchars = (int) strlen( seq_chars ); /* Copy the name supplied into the output array, converting to upper case. Leave space for two characters to encode a sequence number. Terminate the resulting string. */ for( nc = 0; name[ nc ] && ( nc < ( FITSNAMLEN - 2 ) ); nc++ ) { keyword[ nc ] = toupper( name[ nc ] ); } keyword[ nc ] = '\0'; /* We now search the list of sequence numbers already allocated to find the next one to use for this keyword. */ if( this->keyseq ) { found = astMapGet0I( this->keyseq, keyword, &seq ); } else { found = 0; this->keyseq = astKeyMap( "", status ); } /* If the keyword was not found in the list, create a new list entry to describe it. */ if( !found ) seq = 0; /* If OK, loop to find a new sequence number which results in a FITS keyword that hasn't already been used to store data in the FitsChan. */ if( astOK ) { while( 1 ) { /* Determine if the sequence number just obtained has reached the upper limit. This is unlikely to happen in practice, but if it does, we simply re-use this maximum value. Otherwise, we increment the sequence number last used for this keyword to obtain a new one. */ limit = ( seq >= ( createkeyword_seq_nchars * createkeyword_seq_nchars - 1 ) ); if( !limit ) seq++; /* Encode the sequence number into two characters and append them to the original keyword (with a terminating null). */ seq_char = seq_chars[ seq / createkeyword_seq_nchars ]; keyword[ nc ] = seq_char; keyword[ nc + 1 ] = seq_chars[ seq % createkeyword_seq_nchars ]; keyword[ nc + 2 ] = '\0'; /* If the upper sequence number limit has not been reached, try to look up the resulting keyword in the FitsChan to see if it has already been used. Quit searching when a suitable keyword is found. */ if ( limit || !HasCard( this, keyword, "astWrite", class, status ) ) break; } /* Store the update sequence number in the keymap. The keys into this keymap are the base keyword name without the appended sequence string, so temporaily terminate the returned keyword name to exclude the sequence string. */ keyword[ nc ] = '\0'; astMapPut0I( this->keyseq, keyword, seq, NULL ); keyword[ nc ] = seq_char; } } static double DateObs( const char *dateobs, int *status ) { /* * Name: * DateObs * Purpose: * Convert a FITS DATE-OBS keyword value to a MJD. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double DateObs( const char *dateobs, int *status ) * Class Membership: * FitsChan member function. * Description: * Extracts the date and time fields from the supplied string and converts * them into a modified Julian Date. Supports both old "dd/mm/yy" * format, and the new "ccyy-mm-ddThh:mm:ss[.sss...]" format. * Parameters: * dateobs * Pointer to the DATE-OBS string. * status * Pointer to the inherited status variable. * Returned Value: * The Modified Julian Date corresponding to the supplied DATE-OBS * string. * Notes: * - The value AST__BAD is returned (without error) if the supplied * string does not conform to the requirements of a FITS DATE-OBS value, * or if an error has already occurred. */ /* Local Variables: */ double days; /* The hours, mins and secs as a fraction of a day */ double ret; /* The returned MJD value */ double secs; /* The total value of the two seconds fields */ int dd; /* The day field from the supplied string */ int fsc; /* The fractional seconds field from the supplied string */ int hr; /* The hour field from the supplied string */ int j; /* SLALIB status */ int len; /* The length of the supplied string */ int mm; /* The month field from the supplied string */ int mn; /* The minute field from the supplied string */ int nc; /* Number of characters used */ int ok; /* Was the string of a legal format? */ int rem; /* The least significant digit in fsc */ int sc; /* The whole seconds field from the supplied string */ int yy; /* The year field from the supplied string */ /* Check the global status. */ if( !astOK ) return AST__BAD; /* Initialise the returned value. */ ret = AST__BAD; /* Save the length of the supplied string. */ len = (int) strlen( dateobs ); /* Extract the year, month, day, hour, minute, second and fractional seconds fields from the supplied string. Assume initially that the string does not match any format. */ ok = 0; /* First check for the old "dd/mm/yy" format. */ if( nc = 0, ( astSscanf( dateobs, " %2d/%2d/%d %n", &dd, &mm, &yy, &nc ) == 3 ) && ( nc >= len ) ){ ok = 1; hr = 0; mn = 0; sc = 0; fsc = 0; /* Otherwise, check for the new short format "ccyy-mm-dd". */ } else if( nc = 0, ( astSscanf( dateobs, " %4d-%2d-%2d %n", &yy, &mm, &dd, &nc ) == 3 ) && ( nc >= len ) ){ ok = 1; hr = 0; mn = 0; sc = 0; fsc = 0; /* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss" without a fractional seconds field or the trailing Z. */ } else if( nc = 0, ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d %n", &yy, &mm, &dd, &hr, &mn, &sc, &nc ) == 6 ) && ( nc >= len ) ){ ok = 1; fsc = 0; /* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss.sss" with a fractional seconds field but without the trailing Z. */ } else if( nc = 0, ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d.%d %n", &yy, &mm, &dd, &hr, &mn, &sc, &fsc, &nc ) == 7 ) && ( nc >= len ) ){ ok = 1; /* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ssZ" without a fractional seconds field but with the trailing Z. */ } else if( nc = 0, ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2dZ %n", &yy, &mm, &dd, &hr, &mn, &sc, &nc ) == 6 ) && ( nc >= len ) ){ ok = 1; fsc = 0; /* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss.sssZ" with a fractional seconds field and the trailing Z. */ } else if( nc = 0, ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d.%dZ %n", &yy, &mm, &dd, &hr, &mn, &sc, &fsc, &nc ) == 7 ) && ( nc >= len ) ){ ok = 1; } /* If the supplied string was legal, create a MJD from the separate fields. */ if( ok ) { /* Get the MJD at the start of the day. */ palCaldj( yy, mm, dd, &ret, &j ); /* If succesful, convert the hours, minutes and seconds to a fraction of a day, and add it onto the MJD found above. */ if( j == 0 ) { /* Obtain a floating point representation of the fractional seconds field. */ secs = 0.0; while ( fsc > 0 ) { rem = ( fsc % 10 ); fsc /= 10; secs = 0.1 * ( secs + (double) rem ); } /* Add on the whole seconds field. */ secs += (double) sc; /*Convert the hours, minutes and seconds to a fractional day. */ palDtf2d( hr, mn, secs, &days, &j ); /* If succesful, add this onto the returned MJD. */ if( j == 0 ) { ret = ret + days; /* If the conversion to MJD failed, return AST__BAD. */ } else { ret = AST__BAD; } } else { ret = AST__BAD; } } /* Return the result. */ return ret; } static void DeleteCard( AstFitsChan *this, const char *method, const char *class, int *status ){ /* * Name: * DeleteCard * Purpose: * Delete the current card from a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void DeleteCard( AstFitsChan *this, const char *method, * const char *class ) * Class Membership: * FitsChan member function. * Description: * The current card is removed from the circular linked list of structures * stored in the supplied FitsChan, and the memory used to store the * structure is then freed. * Parameters: * this * Pointer to the FitsChan containing the list. * method * Name of calling method. * class * Object class. * Notes: * - This function returns without action if the FitsChan is * currently at "end-of-file". * - The next card becomes the current card. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ FitsCard *card; /* Pointer to the current card */ FitsCard *next; /* Pointer to next card in list */ FitsCard *prev; /* Pointer to previous card in list */ /* Return if the supplied object or current card is NULL. */ if( !this || !this->card ) return; /* Get a pointer to the card to be deleted (the current card). */ card = (FitsCard *) this->card; /* Remove it from the KeyMap holding all keywords. */ astMapRemove( this->keywords, card->name ); /* Move the current card on to the next card. */ MoveCard( this, 1, method, class, status ); /* Save pointers to the previous and next cards in the list. */ prev = GetLink( card, PREVIOUS, method, class, status ); next = GetLink( card, NEXT, method, class, status ); /* If the backwards link points back to the supplied card, then it must be the only one left on the list. */ if( prev == card ) prev = NULL; if( next == card ) next = NULL; /* If the list head is to be deleted, store a value for the new list head. */ if( this->head == (void *) card ) this->head = (void *) next; /* Free the memory used to hold the data value. */ (void) astFree( card->data ); /* Free the memory used to hold any comment. */ if( card->comment ) (void) astFree( (void *) card->comment ); /* Free the memory used to hold the whole structure. */ (void) astFree( (void *) card ); /* Fix up the links between the two adjacent cards in the list, unless the supplied card was the last one in the list. */ if( prev && next ){ next->prev = prev; prev->next = next; } else { this->head = NULL; this->card = NULL; } /* Return. */ return; } static void DelFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astDelFits f AST_DELFITS * Purpose: * Delete the current FITS card in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astDelFits( AstFitsChan *this ) f CALL AST_DELFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function deletes the current FITS card from a FitsChan. The f This routine deletes the current FITS card from a FitsChan. The * current card may be selected using the Card attribute (if its index c is known) or by using astFindFits (if only the FITS keyword is f is known) or by using AST_FINDFITS (if only the FITS keyword is * known). * * After deletion, the following card becomes the current card. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - This function returns without action if the FitsChan is * initially positioned at the "end-of-file" (i.e. if the Card * attribute exceeds the number of cards in the FitsChan). * - If there are no subsequent cards in the FitsChan, then the * Card attribute is left pointing at the "end-of-file" after * deletion (i.e. is set to one more than the number of cards in * the FitsChan). *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Delete the current card. The next card will be made the current card. */ DeleteCard( this, "astDelFits", astGetClass( this ), status ); } static void DistortMaps( AstFitsChan *this, FitsStore *store, char s, int naxes, AstMapping **map1, AstMapping **map2, AstMapping **map3, AstMapping **map4, const char *method, const char *class, int *status ){ /* * Name: * DistortMap * Purpose: * Create a Mapping representing a FITS-WCS Paper IV distortion code. * Type: * Private function. * Synopsis: * void DistortMaps( AstFitsChan *this, FitsStore *store, char s, * int naxes, AstMapping **map1, AstMapping **map2, * AstMapping **map3, AstMapping **map4, * const char *method, const char *class ) * Class Membership: * FitsChan * Description: * This function checks the CTYPE keywords in the supplied FitsStore to see * if they contain a known distortion code (following the syntax described * in FITS-WCS paper IV). If so, Mappings are returned which represent the * distortions to be applied at each stage in the pixel->IWC chain. If * any distortion codes are found in the FitsStore CTYPE values, whether * recognised or not, the CTYPE values in the FitsStore are modified to * remove the distortion code. Warnings about any unknown or inappropriate * distortion codes are added to the FitsChan. * Parameters: * this * The FitsChan. ASTWARN cards may be added to this FitsChan if any * anomalies are found in the keyword values in the FitsStore. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * map1 * Address of a location at which to store a pointer to a Mapping * which describes any distortion to be applied to pixel * coordinates, prior to performing the translation specified by the * CRPIXj keywords. NULL is returned if no distortion is necessary. * map2 * Address of a location at which to store a pointer to a Mapping * which describes any distortion to be applied to translated pixel * coordinates, prior to performing the PC matrix multiplication. * NULL is returned if no distortion is necessary. * map3 * Address of a location at which to store a pointer to a Mapping * which describes any distortion to be applied to unscaled IWC * coordinates, prior to performing the CDELT matrix multiplication. * NULL is returned if no distortion is necessary. * map4 * Address of a location at which to store a pointer to a Mapping * which describes any distortion to be applied to scaled IWC * coordinates, after performing the CDELT matrix multiplication. * NULL is returned if no distortion is necessary. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. */ /* Local Variables: */ AstMapping *tmap1; /* Mapping pointer */ AstMapping *tmap2; /* Mapping pointer */ char *ctype; /* Pointer to CTYPE value */ char code[ 4 ]; /* Projection code extracted from CTYPE */ char dist[ 4 ]; /* Distortion code extracted from CTYPE */ char msgbuf[ 250 ]; /* Buffer for warning message */ char type[ 5 ]; /* Axis type extracted from CTYPE */ double *dim; /* Array holding array dimensions */ int found_axes[ 2 ]; /* Index of axes with the distortion code */ int i; /* FITS axis index */ int nc; /* No. of characters in CTYPE without "-SIP" */ int nfound; /* No. of axes with the distortion code */ int warned; /* Have any ASTWARN cards been issued? */ /* Initialise pointers to the returned Mappings. */ *map1 = NULL; *map2 = NULL; *map3 = NULL; *map4 = NULL; /* Check the global status. */ if ( !astOK ) return; /* Allocate memory to hold the image dimensions. */ dim = (double *) astMalloc( sizeof(double)*naxes ); if( dim ){ /* Note the image dimensions, if known. If not, store AST__BAD values. */ for( i = 0; i < naxes; i++ ){ if( !astGetFitsF( this, FormatKey( "NAXIS", i + 1, -1, ' ', status ), dim + i ) ) dim[ i ] = AST__BAD; } /* First check each known distortion type... */ /* "-SIP": Spitzer (http://irsa.ipac.caltech.edu/data/SPITZER/docs/files/spitzer/shupeADASS.pdf) ============= */ /* Spitzer distortion is limited to 2D. Check the first two axes to see if they have "-SIP" codes at the end of their CTYPE values. If they do, terminate the ctype string in order to exclude the distortion code (this is so that later functions do not need to allow for the possibility of a distortion code being present in the CTYPE value). */ ctype = GetItemC( &(store->ctype), 0, 0, s, NULL, method, class, status ); if( ctype ){ nc = astChrLen( ctype ) - 4; if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) { ctype[ nc ] = 0; ctype = GetItemC( &(store->ctype), 1, 0, s, NULL, method, class, status ); if( ctype ) { nc = astChrLen( ctype ) - 4; if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) { ctype[ nc ] = 0; /* Create a Mapping describing the distortion (other axes are passed unchanged by this Mapping), and add it in series with the returned map2 (Spitzer distortion is applied to the translated pixel coordinates). */ tmap1 = SIPMapping( dim, store, s, naxes, method, class, status ); if( ! *map2 ) { *map2 = tmap1; } else { tmap2 = (AstMapping *) astCmpMap( *map2, tmap1, 1, "", status ); *map2 = astAnnul( *map2 ); tmap1 = astAnnul( tmap1 ); *map2 = tmap2; } } } } } /* Check that the "-SIP" code is not included in any axes other than axes 0 and 1. Issue a warning if it is, and remove it. */ warned = 0; for( i = 2; i < naxes; i++ ){ ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( ctype ){ nc = astChrLen( ctype ) - 4; if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) { if( !warned ){ warned = 1; sprintf( msgbuf, "The \"-SIP\" distortion code can only be " "used on axes 1 and 2, but was found in keyword " "%s (='%s'). The distortion will be ignored.", FormatKey( "CTYPE", i + 1, -1, ' ', status ), ctype ); Warn( this, "distortion", msgbuf, method, class, status ); } ctype[ nc ] = 0; } } } /* "-ZPX": IRAF (http://iraf.noao.edu/projects/ccdmosaic/zpx.html) ============= */ /* An IRAF ZPX header uses a ZPX projection within each CTYPE value in place of the basic ZPN projection. The SpecTrans function converts -ZPX" to "-ZPN-ZPX" (i.e. a basic projection of ZPN with a distortion code of "-ZPX"). This function then traps and processes the "-ZPX" distortion code. */ /* Look for axes that have the "-ZPX" code in their CTYPE values. If any are found, check that there are exactly two such axes, and terminate the ctype strings in order to exclude the distortion code (this is so that later functions do not need to allow for the possibility of a distortion code being present in the CTYPE value)*/ nfound = 0; for( i = 0; i < naxes; i++ ){ ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( ctype && 3 == astSscanf( ctype, "%4s-%3s-%3s", type, code, dist ) ){ if( !strcmp( "ZPX", dist ) ){ if( nfound < 2 ) found_axes[ nfound ] = i; nfound++; ctype[ 8 ] = 0; } } } /* Issue a warning if more than two ZPX axes were found. */ if( nfound > 2 ) { Warn( this, "distortion", "More than two axes were found " "with the \"-ZPX\" projection code. A ZPN projection " "will be used instead.", method, class, status ); /* Otherwise, create a Mapping describing the distortion (other axes are passed unchanged by this Mapping), and add it in series with the returned map4 (ZPX distortion is applied to the translated, rotated, scaled IWC coordinates). */ } else if( nfound == 2 ){ tmap1 = ZPXMapping( this, store, s, naxes, found_axes, method, class, status ); if( ! *map4 ) { *map4 = tmap1; } else { tmap2 = (AstMapping *) astCmpMap( *map4, tmap1, 1, "", status ); *map4 = astAnnul( *map4 ); tmap1 = astAnnul( tmap1 ); *map4 = tmap2; } } /* (There are currently no other supported distortion codes.) */ /* Finally, check all axes looking for any remaining (and therefore unsupported) distortion codes. Issue a warning about them and remove them. =================================================================== */ /* Indicate that we have not yet issued a warning. */ warned = 0; /* Do each IWC axis. */ for( i = 0; i < naxes; i++ ){ /* Get the CTYPE value for this axis. */ ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( ctype ) { /* See if has the "4-3-3" form described in FITS-WCS paper IV. */ if( 3 == astSscanf( ctype, "%4s-%3s-%3s", type, code, dist ) ){ /* Add an ASTWARN card to the FitsChan. Only issue one warning (this avoids multiple warnings about the same distortion code in multiple CTYPE values). */ if( !warned ){ warned = 1; sprintf( msgbuf, "The header contains CTYPE values (e.g. " "%s = '%s') which " "include a distortion code \"-%s\". AST " "currently ignores this distortion. The code " "has been removed from the CTYPE values.", FormatKey( "CTYPE", i + 1, -1, ' ', status ), ctype, dist ); Warn( this, "distortion", msgbuf, method, class, status ); } /* Terminate the CTYPE value in the FitsStore in order to exclude the distortion code. This means that later functions will not need to take account of distortion codes. */ ctype[ 8 ] = 0; } } } } /* Free resources. */ dim = astFree( dim ); } static void DSBSetUp( AstFitsChan *this, FitsStore *store, AstDSBSpecFrame *dsb, char s, double crval, const char *method, const char *class, int *status ){ /* * Name: * DSBSetUp * Purpose: * Modify an AstDSBSpecFrame object to reflect the contents of a FitsStore. * Type: * Private function. * Synopsis: * void DSBSetUp( AstFitsChan *this, FitsStore *store, * AstDSBSpecFrame *dsb, char s, double crval, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function sets the attributes of the supplied DSBSpecFrame to * reflect the values in the supplied FitsStore. * Parameters: * this * The FitsChan. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * dsb * Pointer to the DSBSpecFrame. * s * Alternate axis code. * crval * The spectral CRVAL value, in the spectral system represented by * the supplied DSBSPecFrame. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This implementation follows the conventions of the FITS-CLASS encoding. */ /* Local Variables: */ AstDSBSpecFrame *dsb_src; /* New DSBSpecFrame in which StdOfRest is source */ AstDSBSpecFrame *dsb_topo;/* New DSBSpecFrame in which StdOfRest is topo */ AstFrameSet *fs; /* FrameSet connecting two standards of rest */ double dsbcentre; /* Topocentric reference (CRVAL) frequency */ double in[2]; /* Source rest and image frequencies */ double lo; /* Topocentric Local Oscillator frequency */ double out[2]; /* Topocentric rest and image frequencies */ /* Check the global status. */ if ( !astOK ) return; /* In order to determine the topocentric IF, we need the topocentric frequencies corresponding to the RESTFREQ and IMAGFREQ values in the FITS header. The values stored in the FITS header are measured in Hz, in the source's rest frame, so we need a mapping from frequency in the source rest frame to topocentric frequency. Take a copy of the supplied DSBSpecFrame and then set its attributes to represent frequency in the sources rest frame. */ dsb_src = astCopy( dsb ); astSetStdOfRest( dsb_src, AST__SCSOR ); astSetSystem( dsb_src, AST__FREQ ); astSetUnit( dsb_src, 0, "Hz" ); /* Take a copy of this DSBSpecFrame and set its standard of rest to topocentric. */ dsb_topo = astCopy( dsb_src ); astSetStdOfRest( dsb_topo, AST__TPSOR ); /* Now get the Mapping between these. */ fs = astConvert( dsb_src, dsb_topo, "" ); dsb_src = astAnnul( dsb_src ); dsb_topo = astAnnul( dsb_topo ); /* Check a conversion was found. */ if( fs != NULL ) { /* Use this Mapping to transform the rest frequency and the image frequency from the standard of rest of the source to that of the observer. */ in[ 0 ] = astGetRestFreq( dsb ); in[ 1 ] = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status ); astTran1( fs, 2, in, 1, out ); /* The intermediate frequency is half the distance between these two frequencies. Note, the IF value is signed so as to put the rest frequency in the observed sideband. */ if( out[ 0 ] != AST__BAD && out[ 1 ] != AST__BAD ) { /* Store the spectral CRVAL value as the centre frequency of the DSBSpecFrame. The public astSetD method interprets the supplied value as a value in the spectral system described by the other SpecFrame attributes. */ astSetD( dsb, "DSBCentre", crval ); /* To calculate the topocentric IF we need the topocentric frequency equivalent of CRVAL. So take a copy of the DSBSpecFrame, then set it to represent topocentric frequency, and read back the DSBCentre value. */ dsb_topo = astCopy( dsb ); astSetStdOfRest( dsb_topo, AST__TPSOR ); astSetSystem( dsb_topo, AST__FREQ ); astSetUnit( dsb_topo, 0, "Hz" ); dsbcentre = astGetD( dsb_topo, "DSBCentre" ); dsb_topo = astAnnul( dsb_topo ); /* We also need the topocentric Local Oscillator frequency. This is assumed to be half way between the topocentric IMAGFREQ and RESTFREQ values. */ lo = 0.5*( out[ 1 ] + out[ 0 ] ); /* Set the IF to be the difference between the Local Oscillator frequency and the CRVAL frequency. */ astSetIF( dsb, lo - dsbcentre ); /* Set the DSBSpecFrame to represent the observed sideband */ astSetC( dsb, "SideBand", "observed" ); } /* Free resources. */ fs = astAnnul( fs ); } } static int DSSFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * DSSFromStore * Purpose: * Store WCS keywords in a FitsChan using DSS encoding. * Type: * Private function. * Synopsis: * int DSSFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using DSS encoding. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ const char *comm; /* Pointer to comment string */ char *cval; /* Pointer to string keyword value */ const char *pltdecsn;/* PLTDECSN keyword value */ double amdx[20]; /* AMDXi keyword value */ double amdy[20]; /* AMDYi keyword value */ double cdelt; /* CDELT element */ double cnpix1; /* CNPIX1 keyword value */ double cnpix2; /* CNPIX2 keyword value */ double pc; /* PC element */ double pltdecd; /* PLTDECD keyword value */ double pltdecm; /* PLTDECM keyword value */ double pltdecs; /* PLTDECS keyword value */ double pltrah; /* PLTRAH keyword value */ double pltram; /* PLTRAM keyword value */ double pltras; /* PLTRAS keyword value */ double pltscl; /* PLTSCL keyword value */ double ppo1; /* PPO1 keyword value */ double ppo2; /* PPO2 keyword value */ double ppo3; /* PPO3 keyword value */ double ppo4; /* PPO4 keyword value */ double ppo5; /* PPO5 keyword value */ double ppo6; /* PPO6 keyword value */ double pvx[22]; /* X projection parameter values */ double pvy[22]; /* Y projection parameter values */ double val; /* General purpose value */ double xpixelsz; /* XPIXELSZ keyword value */ double ypixelsz; /* YPIXELSZ keyword value */ int i; /* Loop count */ int gottpn; /* Is the projection a "TPN" projection? */ int m; /* Parameter index */ int ret; /* Returned value. */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Check the image is 2 dimensional. */ if( GetMaxJM( &(store->crpix), ' ', status ) != 1 ) return ret; /* Check the first axis is RA with a TAN or TPN projection. */ cval = GetItemC( &(store->ctype), 0, 0, ' ', NULL, method, class, status ); if( !cval ) return ret; gottpn = !strcmp( "RA---TPN", cval ); if( strcmp( "RA---TAN", cval ) && !gottpn ) return ret; /* Check the second axis is DEC with a TAN or TPN projection. */ cval = GetItemC( &(store->ctype), 1, 0, ' ', NULL, method, class, status ); if( !cval ) return ret; if( gottpn ) { if( strcmp( "DEC--TPN", cval ) ) return ret; } else { if( strcmp( "DEC--TAN", cval ) ) return ret; } /* Check that LONPOLE is undefined or is 180 degrees. */ val = GetItem( &(store->lonpole), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD && val != 180.0 ) return ret; /* Check that the RA/DEC system is FK5. */ cval = GetItemC( &(store->radesys), 0, 0, ' ', NULL, method, class, status ); if( !cval || strcmp( "FK5", cval ) ) return ret; /* Check that equinox is not defined or is 2000.0 */ val = GetItem( &(store->equinox), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD && val != 2000.0 ) return ret; /* Get the pixel sizes from the PC/CDELT keywords. They must be defined and not be zero. */ cdelt = GetItem( &(store->cdelt), 0, 0, ' ', NULL, method, class, status ); if( cdelt == AST__BAD ) return ret; pc = GetItem( &(store->pc), 0, 0, ' ', NULL, method, class, status ); if( pc == AST__BAD ) pc = 1.0; xpixelsz = cdelt*pc; cdelt = GetItem( &(store->cdelt), 1, 0, ' ', NULL, method, class, status ); if( cdelt == AST__BAD ) return ret; pc = GetItem( &(store->pc), 1, 1, ' ', NULL, method, class, status ); if( pc == AST__BAD ) pc = 1.0; ypixelsz = cdelt*pc; if( xpixelsz == 0.0 || ypixelsz == 0.0 ) return ret; xpixelsz *= -1000.0; ypixelsz *= 1000.0; /* Check the off-diagonal PC terms are zero. DSS does not allow any rotation. */ val = GetItem( &(store->pc), 0, 1, ' ', NULL, method, class, status ); if( val != AST__BAD && val != 0.0 ) return ret; val = GetItem( &(store->pc), 1, 0, ' ', NULL, method, class, status ); if( val != AST__BAD && val != 0.0 ) return ret; /* Get the required projection parameter values from the store, supplying appropriate values if a simple TAN projection is being used. */ for( m = 0; m < 22; m++ ){ pvx[ m ] = GetItem( &(store->pv), 0, m, ' ', NULL, method, class, status ); if( pvx[ m ] == AST__BAD || !gottpn ) pvx[ m ] = ( m == 1 ) ? 1.0 : 0.0; pvy[ m ] = GetItem( &(store->pv), 1, m, ' ', NULL, method, class, status ); if( pvy[ m ] == AST__BAD || !gottpn ) pvy[ m ] = ( m == 1 ) ? 1.0 : 0.0; } /* Check that no other projection parameters have been set. */ if( GetMaxJM( &(store->pv), ' ', status ) > 21 ) return ret; /* Check that specific parameters take their required zero value. */ if( pvx[ 3 ] != 0.0 || pvy[ 3 ] != 0.0 ) return ret; for( m = 11; m < 17; m++ ){ if( pvx[ m ] != 0.0 || pvy[ m ] != 0.0 ) return ret; } if( pvx[ 18 ] != 0.0 || pvy[ 18 ] != 0.0 ) return ret; if( pvx[ 20 ] != 0.0 || pvy[ 20 ] != 0.0 ) return ret; /* Check that other projection parameters are related correctly. */ if( !EQUAL( 2*pvx[ 17 ], pvx[ 19 ] ) ) return ret; if( !EQUAL( pvx[ 17 ], pvx[ 21 ] ) ) return ret; if( !EQUAL( 2*pvy[ 17 ], pvy[ 19 ] ) ) return ret; if( !EQUAL( pvy[ 17 ], pvy[ 21 ] ) ) return ret; /* Initialise all polynomial co-efficients to zero. */ for( m = 0; m < 20; m++ ){ amdx[ m ] = 0.0; amdy[ m ] = 0.0; } /* Polynomial co-efficients. There is redundancy here too, so we arbitrarily choose to leave AMDX/Y7 and AMDX/Y12 set to zero. */ amdx[ 0 ] = 3600.0*pvx[ 1 ]; amdx[ 1 ] = 3600.0*pvx[ 2 ]; amdx[ 2 ] = 3600.0*pvx[ 0 ]; amdx[ 3 ] = 3600.0*pvx[ 4 ]; amdx[ 4 ] = 3600.0*pvx[ 5 ]; amdx[ 5 ] = 3600.0*pvx[ 6 ]; amdx[ 7 ] = 3600.0*pvx[ 7 ]; amdx[ 8 ] = 3600.0*pvx[ 8 ]; amdx[ 9 ] = 3600.0*pvx[ 9 ]; amdx[ 10 ] = 3600.0*pvx[ 10 ]; amdx[ 12 ] = 3600.0*pvx[ 17 ]; amdy[ 0 ] = 3600.0*pvy[ 1 ]; amdy[ 1 ] = 3600.0*pvy[ 2 ]; amdy[ 2 ] = 3600.0*pvy[ 0 ]; amdy[ 3 ] = 3600.0*pvy[ 4 ]; amdy[ 4 ] = 3600.0*pvy[ 5 ]; amdy[ 5 ] = 3600.0*pvy[ 6 ]; amdy[ 7 ] = 3600.0*pvy[ 7 ]; amdy[ 8 ] = 3600.0*pvy[ 8 ]; amdy[ 9 ] = 3600.0*pvy[ 9 ]; amdy[ 10 ] = 3600.0*pvy[ 10 ]; amdy[ 12 ] = 3600.0*pvy[ 17 ]; /* The plate scale is the mean of the first X and Y co-efficients. */ pltscl = 0.5*( amdx[ 0 ] + amdy[ 0 ] ); /* There is redundancy in the DSS encoding. We can choose an arbitrary pixel corner (CNPIX1, CNPIX2) so long as we use the corresponding origin for the cartesian co-ordinate system in which the plate centre is specified (PPO3, PPO6). Arbitrarily set CNPIX1 and CNPIX2 to one. */ cnpix1 = 1.0; cnpix2 = 1.0; /* Find the corresponding plate centre PPO3 and PPO6 (other co-efficients are set to zero). */ ppo1 = 0.0; ppo2 = 0.0; val = GetItem( &(store->crpix), 0, 0, ' ', NULL, method, class, status ); if( val == AST__BAD ) return ret; ppo3 = xpixelsz*( val + cnpix1 - 0.5 ); ppo4 = 0.0; ppo5 = 0.0; val = GetItem( &(store->crpix), 0, 1, ' ', NULL, method, class, status ); if( val == AST__BAD ) return ret; ppo6 = ypixelsz*( val + cnpix2 - 0.5 ); /* The reference RA. Get it in degrees. */ val = GetItem( &(store->crval), 0, 0, ' ', NULL, method, class, status ); if( val == AST__BAD ) return ret; /* Convert to hours and ensure it is in the range 0 to 24 */ val /= 15.0; while( val < 0 ) val += 24.0; while( val >= 24.0 ) val -= 24.0; /* Split into hours, mins and seconds. */ pltrah = (int) val; val = 60.0*( val - pltrah ); pltram = (int) val; pltras = 60.0*( val - pltram ); /* The reference DEC. Get it in degrees. */ val = GetItem( &(store->crval), 1, 0, ' ', NULL, method, class, status ); if( val == AST__BAD ) return ret; /* Ensure it is in the range -180 to +180 */ while( val < -180.0 ) val += 360.0; while( val >= 180.0 ) val -= 360.0; /* Save the sign. */ if( val > 0.0 ){ pltdecsn = "+"; } else { pltdecsn = "-"; val = -val; } /* Split into degrees, mins and seconds. */ pltdecd = (int) val; val = 60.0*( val - pltdecd ); pltdecm = (int) val; pltdecs = 60.0*( val - pltdecm ); /* Store the DSS keywords in the FitsChan. */ SetValue( this, "CNPIX1", &cnpix1, AST__FLOAT, "X corner (pixels)", status ); SetValue( this, "CNPIX2", &cnpix2, AST__FLOAT, "Y corner (pixels)", status ); SetValue( this, "PPO1", &ppo1, AST__FLOAT, "Orientation co-efficients", status ); SetValue( this, "PPO2", &ppo2, AST__FLOAT, "", status ); SetValue( this, "PPO3", &ppo3, AST__FLOAT, "", status ); SetValue( this, "PPO4", &ppo4, AST__FLOAT, "", status ); SetValue( this, "PPO5", &ppo5, AST__FLOAT, "", status ); SetValue( this, "PPO6", &ppo6, AST__FLOAT, "", status ); SetValue( this, "XPIXELSZ", &xpixelsz, AST__FLOAT, "X pixel size (microns)", status ); SetValue( this, "YPIXELSZ", &ypixelsz, AST__FLOAT, "Y pixel size (microns)", status ); SetValue( this, "PLTRAH", &pltrah, AST__FLOAT, "RA at plate centre", status ); SetValue( this, "PLTRAM", &pltram, AST__FLOAT, "", status ); SetValue( this, "PLTRAS", &pltras, AST__FLOAT, "", status ); SetValue( this, "PLTDECD", &pltdecd, AST__FLOAT, "DEC at plate centre", status ); SetValue( this, "PLTDECM", &pltdecm, AST__FLOAT, "", status ); SetValue( this, "PLTDECS", &pltdecs, AST__FLOAT, "", status ); SetValue( this, "PLTDECSN", &pltdecsn, AST__STRING, "", status ); SetValue( this, "PLTSCALE", &pltscl, AST__FLOAT, "Plate scale (arcsec/mm)", status ); comm = "Plate solution x co-efficients"; for( i = 0; i < 20; i++ ){ SetValue( this, FormatKey( "AMDX", i + 1, -1, ' ', status ), amdx + i, AST__FLOAT, comm, status ); comm = NULL; } comm = "Plate solution y co-efficients"; for( i = 0; i < 20; i++ ){ SetValue( this, FormatKey( "AMDY", i + 1, -1, ' ', status ), amdy + i, AST__FLOAT, comm, status ); comm = NULL; } /* If no error has occurred, return one. */ if( astOK ) ret = 1; /* Return the answer. */ return ret; } static void DSSToStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * DSSToStore * Purpose: * Extract WCS information from the supplied FitsChan using a DSS * encoding, and store it in the supplied FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void DSSToStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function extracts DSS keywords from the supplied FitsChan, and * stores the corresponding WCS information in the supplied FitsStore. * The conversion from DSS encoding to standard WCS encoding is * described in an ear;y draft of the Calabretta & Greisen paper * "Representations of celestial coordinates in FITS" (A&A, in prep.), * and uses the now deprecated "TAN with polynomial corrections", * which is still supported by the WcsMap class as type AST__TPN. * Here we use "lambda=1" (i.e. plate co-ordinate are measured in mm, * not degrees). * * It is assumed that DSS images are 2 dimensional. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore structure. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char *text; /* Pointer to textual keyword value */ char pltdecsn[11]; /* First 10 non-blank characters from PLTDECSN keyword */ char keyname[10]; /* Buffer for keyword name */ double amdx[20]; /* AMDXi keyword value */ double amdy[20]; /* AMDYi keyword value */ double cnpix1; /* CNPIX1 keyword value */ double cnpix2; /* CNPIX2 keyword value */ double crval2; /* Equivalent CRVAL2 keyword value */ double dummy; /* Unused keyword value */ double pltdecd; /* PLTDECD keyword value */ double pltdecm; /* PLTDECM keyword value */ double pltdecs; /* PLTDECS keyword value */ double pltrah; /* PLTRAH keyword value */ double pltram; /* PLTRAM keyword value */ double pltras; /* PLTRAS keyword value */ double ppo3; /* PPO3 keyword value */ double ppo6; /* PPO6 keyword value */ double pv; /* Projection parameter value */ double xpixelsz; /* XPIXELSZ keyword value */ double ypixelsz; /* YPIXELSZ keyword value */ int i; /* Loop count */ /* Check the inherited status. */ if( !astOK ) return; /* Get the optional DSS keywords, supplying defaults for any missing keywords. */ cnpix1 = 0.0; cnpix2 = 0.0; GetValue( this, "CNPIX1", AST__FLOAT, &cnpix1, 0, 1, method, class, status ); GetValue( this, "CNPIX2", AST__FLOAT, &cnpix2, 0, 1, method, class, status ); /* Get the required DSS keywords. Report an error if any are missing. */ GetValue( this, "PPO3", AST__FLOAT, &ppo3, 1, 1, method, class, status ); GetValue( this, "PPO6", AST__FLOAT, &ppo6, 1, 1, method, class, status ); GetValue( this, "XPIXELSZ", AST__FLOAT, &xpixelsz, 1, 1, method, class, status ); GetValue( this, "YPIXELSZ", AST__FLOAT, &ypixelsz, 1, 1, method, class, status ); GetValue( this, "PLTRAH", AST__FLOAT, &pltrah, 1, 1, method, class, status ); GetValue( this, "PLTRAM", AST__FLOAT, &pltram, 1, 1, method, class, status ); GetValue( this, "PLTRAS", AST__FLOAT, &pltras, 1, 1, method, class, status ); GetValue( this, "PLTDECD", AST__FLOAT, &pltdecd, 1, 1, method, class, status ); GetValue( this, "PLTDECM", AST__FLOAT, &pltdecm, 1, 1, method, class, status ); GetValue( this, "PLTDECS", AST__FLOAT, &pltdecs, 1, 1, method, class, status ); /* Copy the first 10 non-blank characters from the PLTDECSN keyword. */ GetValue( this, "PLTDECSN", AST__STRING, &text, 1, 1, method, class, status ); if( astOK ) { text += strspn( text, " " ); text[ strcspn( text, " " ) ] = 0; strncpy( pltdecsn, text, 10 ); } /* Read other related keywords. We do not need these, but we read them so that they are not propagated to any output FITS file. */ GetValue( this, "PLTSCALE", AST__FLOAT, &dummy, 0, 1, method, class, status ); GetValue( this, "PPO1", AST__FLOAT, &dummy, 0, 1, method, class, status ); GetValue( this, "PPO2", AST__FLOAT, &dummy, 0, 1, method, class, status ); GetValue( this, "PPO4", AST__FLOAT, &dummy, 0, 1, method, class, status ); GetValue( this, "PPO5", AST__FLOAT, &dummy, 0, 1, method, class, status ); /* Get the polynomial co-efficients. These can be defaulted if they are missing, so do not report an error. */ for( i = 0; i < 20; i++ ){ (void) sprintf( keyname, "AMDX%d", i + 1 ); amdx[i] = AST__BAD; GetValue( this, keyname, AST__FLOAT, amdx + i, 0, 1, method, class, status ); (void) sprintf( keyname, "AMDY%d", i + 1 ); amdy[i] = AST__BAD; GetValue( this, keyname, AST__FLOAT, amdy + i, 0, 1, method, class, status ); } /* Check the above went OK. */ if( astOK ) { /* Calculate and store the equivalent PV projection parameters. */ if( amdx[2] != AST__BAD ) { pv = amdx[2]/3600.0; SetItem( &(store->pv), 0, 0, ' ', pv, status ); } if( amdx[0] != AST__BAD ) { pv = amdx[0]/3600.0; SetItem( &(store->pv), 0, 1, ' ', pv, status ); } if( amdx[1] != AST__BAD ) { pv = amdx[1]/3600.0; SetItem( &(store->pv), 0, 2, ' ', pv, status ); } if( amdx[3] != AST__BAD && amdx[6] != AST__BAD ) { pv = ( amdx[3] + amdx[6] )/3600.0; SetItem( &(store->pv), 0, 4, ' ', pv, status ); } if( amdx[4] != AST__BAD ) { pv = amdx[4]/3600.0; SetItem( &(store->pv), 0, 5, ' ', pv, status ); } if( amdx[5] != AST__BAD && amdx[6] != AST__BAD ) { pv = ( amdx[5] + amdx[6] )/3600.0; SetItem( &(store->pv), 0, 6, ' ', pv, status ); } if( amdx[7] != AST__BAD && amdx[11] != AST__BAD ) { pv = ( amdx[7] + amdx[11] )/3600.0; SetItem( &(store->pv), 0, 7, ' ', pv, status ); } if( amdx[8] != AST__BAD ) { pv = amdx[8]/3600.0; SetItem( &(store->pv), 0, 8, ' ', pv, status ); } if( amdx[9] != AST__BAD && amdx[11] != AST__BAD ) { pv = ( amdx[9] + amdx[11] )/3600.0; SetItem( &(store->pv), 0, 9, ' ', pv, status ); } if( amdx[10] != AST__BAD ) { pv = amdx[10]/3600.0; SetItem( &(store->pv), 0, 10, ' ', pv, status ); } if( amdx[12] != AST__BAD ) { pv = amdx[12]/3600.0; SetItem( &(store->pv), 0, 17, ' ', pv, status ); SetItem( &(store->pv), 0, 19, ' ', 2*pv, status ); SetItem( &(store->pv), 0, 21, ' ', pv, status ); } if( amdy[2] != AST__BAD ) { pv = amdy[2]/3600.0; SetItem( &(store->pv), 1, 0, ' ', pv, status ); } if( amdy[0] != AST__BAD ) { pv = amdy[0]/3600.0; SetItem( &(store->pv), 1, 1, ' ', pv, status ); } if( amdy[1] != AST__BAD ) { pv = amdy[1]/3600.0; SetItem( &(store->pv), 1, 2, ' ', pv, status ); } if( amdy[3] != AST__BAD && amdy[6] != AST__BAD ) { pv = ( amdy[3] + amdy[6] )/3600.0; SetItem( &(store->pv), 1, 4, ' ', pv, status ); } if( amdy[4] != AST__BAD ) { pv = amdy[4]/3600.0; SetItem( &(store->pv), 1, 5, ' ', pv, status ); } if( amdy[5] != AST__BAD && amdy[6] != AST__BAD ) { pv = ( amdy[5] + amdy[6] )/3600.0; SetItem( &(store->pv), 1, 6, ' ', pv, status ); } if( amdy[7] != AST__BAD && amdy[11] != AST__BAD ) { pv = ( amdy[7] + amdy[11] )/3600.0; SetItem( &(store->pv), 1, 7, ' ', pv, status ); } if( amdy[8] != AST__BAD ) { pv = amdy[8]/3600.0; SetItem( &(store->pv), 1, 8, ' ', pv, status ); } if( amdy[9] != AST__BAD && amdy[11] != AST__BAD ) { pv = ( amdy[9] + amdy[11] )/3600.0; SetItem( &(store->pv), 1, 9, ' ', pv, status ); } if( amdy[10] != AST__BAD ) { pv = amdy[10]/3600.0; SetItem( &(store->pv), 1, 10, ' ', pv, status ); } if( amdy[12] != AST__BAD ) { pv = amdy[12]/3600.0; SetItem( &(store->pv), 1, 17, ' ', pv, status ); SetItem( &(store->pv), 1, 19, ' ', 2*pv, status ); SetItem( &(store->pv), 1, 21, ' ', pv, status ); } /* Calculate and store the equivalent CRPIX values. */ if( xpixelsz != 0.0 ) { SetItem( &(store->crpix), 0, 0, ' ', ( ppo3/xpixelsz ) - cnpix1 + 0.5, status ); } else if( astOK ){ astError( AST__BDFTS, "%s(%s): FITS keyword XPIXELSZ has illegal " "value 0.0", status, method, class ); } if( ypixelsz != 0.0 ) { SetItem( &(store->crpix), 0, 1, ' ', ( ppo6/ypixelsz ) - cnpix2 + 0.5, status ); } else if( astOK ){ astError( AST__BDFTS, "%s(%s): FITS keyword YPIXELSZ has illegal " "value 0.0", status, method, class ); } /* Calculate and store the equivalent CRVAL values. */ SetItem( &(store->crval), 0, 0, ' ', 15.0*( pltrah + pltram/60.0 + pltras/3600.0 ), status ); crval2 = pltdecd + pltdecm/60.0 + pltdecs/3600.0; if( !strcmp( pltdecsn, "-") ) crval2 = -crval2; SetItem( &(store->crval), 1, 0, ' ', crval2, status ); /* Calculate and store the equivalent PC matrix. */ SetItem( &(store->pc), 0, 0, ' ', -0.001*xpixelsz, status ); SetItem( &(store->pc), 1, 1, ' ', 0.001*ypixelsz, status ); /* Set values of 1.0 for the CDELT values. */ SetItem( &(store->cdelt), 0, 0, ' ', 1.0, status ); SetItem( &(store->cdelt), 1, 0, ' ', 1.0, status ); /* Store remaining constant items */ SetItem( &(store->lonpole), 0, 0, ' ', 180.0, status ); SetItem( &(store->equinox), 0, 0, ' ', 2000.0, status ); SetItemC( &(store->radesys), 0, 0, ' ', "FK5", status ); SetItem( &(store->wcsaxes), 0, 0, ' ', 2.0, status ); store->naxis = 2; SetItemC( &(store->ctype), 0, 0, ' ', "RA---TPN", status ); SetItemC( &(store->ctype), 1, 0, ' ', "DEC--TPN", status ); } } static void EmptyFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astEmptyFits f AST_EMPTYFITS * Purpose: * Delete all cards in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astEmptyFits( AstFitsChan *this ) f CALL AST_EMPTYFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * deletes all cards and associated information from a FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - This method simply deletes the cards currently in the FitsChan. c Unlike astWriteFits, f Unlike AST_WRITEFITS, * they are not first written out to the sink function or sink file. * - Any Tables or warnings stored in the FitsChan are also deleted. * - This method attempt to execute even if an error has occurred * previously. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *class; /* Pointer to string holding object class */ const char *method; /* Pointer to string holding calling method */ int old_ignore_used; /* Original setting of ignore_used variable */ /* Check a FitsChan was supplied. */ if( !this ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Store the method and class strings. */ method = "astEmpty"; class = astGetClass( this ); /* Delete all cards from the circular linked list stored in the FitsChan, starting with the card at the head of the list. */ old_ignore_used = ignore_used; ignore_used = 0; astClearCard( this ); while( !astFitsEof( this ) ) DeleteCard( this, method, class, status ); ignore_used = old_ignore_used; /* Delete the KeyMap which holds keywords and the latest sequence number used by each of them. */ if( this->keyseq ) this->keyseq = astAnnul( this->keyseq ); /* Delete the KeyMap holding the keyword names. */ if( this->keywords ) this->keywords = astAnnul( this->keywords ); /* Free any memory used to hold the Warnings attribute value. */ this->warnings = astFree( this->warnings ); /* Other objects in the FitsChan structure. */ if( this->tables ) this->tables = astAnnul( this->tables ); } static int EncodeFloat( char *buf, int digits, int width, int maxwidth, double value, int *status ){ /* * * Name: * EncodeFloat * Purpose: * Formats a floating point value. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int EncodeFloat( char *buf, int digits, int width, int maxwidth, * double value, int *status ) * Class Membership: * FitsChan method. * Description: * This function formats the value using a G format specified in order * to use the minimum field width (trailing zeros are not printed). * However, the G specifier does not include a decimal point unless it * is necessary. FITS requires that floating point values always include * a decimal point, so this function inserts one, if necessary. * Parameters: * buf * A character string into which the value is written. * digits * The number of digits after the decimal point. If the supplied value * is negative, the number of digits actually used may be reduced if * the string would otherwise extend beyond the number of columns * allowed by the FITS standard. If the value is positive, the * specified number of digits are always produced, even if it means * breaking the FITS standard. * width * The minimum field width to use. The value is right justified in * this field width. * maxwidth * The maximum field width to use. A value of zero is returned if * the maximum field width is exceeded. * value * The value to format. * status * Pointer to the inherited status variable. * Returned Value: * The field width actually used, or zero if the value could not be * formatted. This does not include the trailing null character. * Notes: * - If there is room, a trailing zero is also added following the * inserted decimal point. */ /* Local Variables: */ char *c; char *w, *r; int i; int ldigits; int n; int ret; /* Check the global error status. */ if ( !astOK ) return 0; /* The supplied value of "digits" may be negative. Obtain the positive value giving the initial number of decimal digits to use. */ ldigits = ( digits > 0 ) ? digits : -digits; /* Loop until a suitably encoded value has been obtained. */ while( 1 ){ /* Write the value into the buffer. Most are formatted with a G specifier. This will result in values between -0.001 and -0.0001 being formatted without an exponent, and thus occupying (ldigits+6) characters. With an exponent, these values would be formatted in (ldigits+5) characters thus saving one character. This is important because the default value of ldigits is 15, resulting in 21 characters being used by the G specifier. This is one more than the maximum allowed by the FITS standard. Using an exponent instead would result in 20 characters being used without any loss of precision, thus staying within the FITS limit. Note, the precision used with the E specifier is one less than with the G specifier because the digit to the left of the decimal place is significant with the E specifier, and so we only need (ldigits-1) significant digits to the right of the decimal point. */ if( value > -0.001 && value < -0.0001 ) { (void) sprintf( buf, "%*.*E", width, ldigits - 1, value ); } else { (void) sprintf( buf, "%*.*G", width, ldigits, value ); } /* Check that the value zero is not encoded with a minus sign (e.g. "-0."). This also rounds out long sequences of zeros or nines. */ CheckZero( buf, value, width, status ); /* If the formatted value includes an exponent, it will have 2 digits. If the exponent includes a leading zero, remove it. */ if( ( w = strstr( buf, "E-0" ) ) ) { w += 2; } else if( ( w = strstr( buf, "E+0" ) ) ){ w += 2; } else if( ( w = strstr( buf, "E0" ) ) ){ w += 1; } /* If a leading zero was found, shuffle everything down from the start of the string by one character, over-writing the redundant zero, and insert a space at the start of the string. */ if( w ) { r = w - 1 ; while( w != buf ) *(w--) = *(r--); *w = ' '; } /* If the used field width was too large, reduce it and try again, so long as we are allowed to change the number of digits being used. */ ret = strlen( buf ); if( ret > width && digits < 0 ){ ldigits -= ( ret - width ); /* Otherwise leave the loop. Return zero field width if the maximum field width was exceeded. */ } else { if( ret > maxwidth ) ret = 0; break; } } /* If a formatted value was obtained, we need to ensure that the it includes a decimal point. */ if( ret ){ /* Get a pointer to the first digit in the buffer. */ c = strpbrk( buf, "0123456789" ); /* Something funny is going on if there are no digits in the buffer, so return a zero field width. */ if( !c ){ ret = 0; /* Otherwise... */ } else { /* Find the number of digits following and including the first digit. */ n = strspn( c, "0123456789" ); /* If the first non-digit character is a decimal point, do nothing. */ if( c[ n ] != '.' ){ /* If there are two or more leading spaces, move the start of the string two character to the left, and insert ".0" in the gap created. This keeps the field right justified within the desired field width. */ if( buf[ 0 ] == ' ' && buf[ 1 ] == ' ' ){ for( i = 2; i < c - buf + n; i++ ) buf[ i - 2 ] = buf[ i ]; c[ n - 2 ] = '.'; c[ n - 1 ] = '0'; /* If there is just one leading space, move the start of the string one character to the left, and insert "." in the gap created. This keeps the field right justified within the desired field width. */ } else if( buf[ 0 ] == ' ' ){ for( i = 0; i < n; i++ ) c[ i - 1 ] = c[ i ]; c[ n - 1 ] = '.'; /* If there are no leading spaces we need to move the end of the string to the right. This will result in the string no longer being right justified in the required field width. Return zero if there is insufficient room for an extra character. */ } else { ret++; if( ret > maxwidth ){ ret = 0; /* Otherwise, more the end of the string one place to the right and insert the decimal point. */ } else { for( i = strlen( c ); i >= n; i-- ) c[ i + 1 ] = c[ i ]; c[ n ] = '.'; } } } } } /* Return the field width. */ return ret; } static int EncodeValue( AstFitsChan *this, char *buf, int col, int digits, const char *method, int *status ){ /* * Name: * EncodeValue * Purpose: * Encode the current card's keyword value into a string. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int EncodeValue( AstFitsChan *this, char *buf, int col, int digits, * const char *method, int *status ) * Class Membership: * FitsChan member function. * Description: * This function encodes the keyword value defined in the current card * of the supplied FitsChan and stores it at the start of the supplied * buffer. The number of characters placed in the buffer is returned * (not including a terminating null). * Parameters: * this * Pointer to the FitsChan. * buf * The buffer to receive the formatted value. This should be at least * 70 characters long. * col * The column number within the FITS header card corresponding to the * start of "buf". * digits * The number of digits to use when formatting floating point * values. If the supplied value is negative, the number of digits * actually used may be reduced if the string would otherwise extend * beyond the number of columns allowed by the FITS standard. If the * value is positive, the specified number of digits are always * produced, even if it means breaking the FITS standard. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The number of columns used by the encoded value. * Notes: * - The function returns 0 if an error has already occurred * or if an error occurs for any reason within this function. */ /* Local Variables: */ char *c; /* Pointer to next character */ char *name; /* Pointer to the keyword name */ double dval; /* Keyword value */ void *data; /* Pointer to keyword value */ int i; /* Loop count */ int ilen; /* Length of imaginary part */ int len; /* Returned length */ int quote; /* Quote character found? */ int rlen; /* Length of real part */ int type; /* Data type for keyword in current card */ /* Check the global status. */ if( !astOK ) return 0; /* Initialise returned length. */ len = 0; /* Get the data type of the keyword. */ type = CardType( this, status ); /* Get a pointer to the data value in the current card. */ data = CardData( this, NULL, status ); /* Return if there is no defined value associated with the keyword in the current card. */ if( type != AST__UNDEF ) { /* Get the name of the keyword. */ name = CardName( this, status ); /* Go through each supported data type (roughly in the order of decreasing usage)... */ /* AST__FLOAT - stored internally in a variable of type "double". Right justified to column 30 in the header card. */ if( type == AST__FLOAT ){ dval = *( (double *) data ); len = EncodeFloat( buf, digits, FITSRLCOL - FITSNAMLEN - 2, AST__FITSCHAN_FITSCARDLEN - col + 1, dval, status ); if( len <= 0 && astOK ) { astError( AST__BDFTS, "%s(%s): Cannot encode floating point value " "%g into a FITS header card for keyword '%s'.", status, method, astGetClass( this ), dval, name ); } /* AST__STRING & AST__CONTINUE - stored internally in a null terminated array of type "char". The encoded string is enclosed in single quotes, starting at FITS column 11 and ending in at least column 20. Single quotes in the string are replaced by two adjacent single quotes. */ } else if( type == AST__STRING || type == AST__CONTINUE ){ c = (char *) data; /* Enter the opening quote. */ len = 0; buf[ len++ ] = '\''; /* Inspect each character, looking for quotes. */ for ( i = 0; c[ i ]; ) { quote = ( c[ i ] == '\'' ); /* If it will not fit into the header card (allowing for doubled quotes), give up here. */ if ( len + ( quote ? 2 : 1 ) > AST__FITSCHAN_FITSCARDLEN - col ) break; /* Otherwise, copy it into the output buffer and double any quotes. */ buf[ len++ ] = c[ i ]; if ( quote ) buf[ len++ ] = '\''; /* Look at the next character. */ i++; } /* Pad the string out to the required minimum length with blanks and add the final quote. */ while( len < FITSSTCOL - col ) buf[ len++ ] = ' '; buf[ len++ ] = '\''; /* Inspect any characters that weren't used. If any are non-blank, report an error. */ for ( ; c[ i ]; i++ ) { if ( !isspace( c[ i ] ) ) { astError( AST__BDFTS, "%s(%s): Cannot encode string '%s' into a FITS " "header card for keyword '%s'.", status, method, astGetClass( this ), (char *) data, name ); break; } } /* INTEGER - stored internally in a variable of type "int". Right justified to column 30 in the header card. */ } else if( type == AST__INT ){ len = sprintf( buf, "%*d", FITSRLCOL - col + 1, *( (int *) data ) ); if( len < 0 || len > AST__FITSCHAN_FITSCARDLEN - col ) { astError( AST__BDFTS, "%s(%s): Cannot encode integer value %d into a " "FITS header card for keyword '%s'.", status, method, astGetClass( this ), *( (int *) data ), name ); } /* LOGICAL - stored internally in a variable of type "int". Represented by a "T" or "F" in column 30 of the FITS header card. */ } else if( type == AST__LOGICAL ){ for( i = 0; i < FITSRLCOL - col; i++ ) buf[ i ] = ' '; if( *( (int *) data ) ){ buf[ FITSRLCOL - col ] = 'T'; } else { buf[ FITSRLCOL - col ] = 'F'; } len = FITSRLCOL - col + 1; /* AST__COMPLEXF - stored internally in an array of two "doubles". The real part is right justified to FITS column 30. The imaginary part is right justified to FITS column 50. */ } else if( type == AST__COMPLEXF ){ dval = ( (double *) data )[ 0 ]; rlen = EncodeFloat( buf, digits, FITSRLCOL - FITSNAMLEN - 2, AST__FITSCHAN_FITSCARDLEN - col + 1, dval, status ); if( rlen <= 0 || rlen > AST__FITSCHAN_FITSCARDLEN - col ) { astError( AST__BDFTS, "%s(%s): Cannot encode real part of a complex " "floating point value [%g,%g] into a FITS header card " "for keyword '%s'.", status, method, astGetClass( this ), dval, ( (double *) data )[ 1 ], name ); } else { dval = ( (double *) data )[ 1 ]; ilen = EncodeFloat( buf + rlen, digits, FITSIMCOL - FITSRLCOL, AST__FITSCHAN_FITSCARDLEN - col - rlen, dval, status ); if( ilen <= 0 ) { astError( AST__BDFTS, "%s(%s): Cannot encode imaginary part of a " "complex floating point value [%g,%g] into a FITS header " "card for keyword '%s'.", status, method, astGetClass( this ), ( (double *) data )[ 0 ], dval, name ); } else { len = ilen + rlen; } } /* AST__COMPLEXI - stored internally in a an array of two "ints". */ } else if( type == AST__COMPLEXI ){ rlen = sprintf( buf, "%*d", FITSRLCOL - col + 1, ( (int *) data )[ 0 ] ); if( rlen < 0 || rlen > AST__FITSCHAN_FITSCARDLEN - col ) { astError( AST__BDFTS, "%s(%s): Cannot encode real part of a complex " "integer value [%d,%d] into a FITS header card " "for keyword '%s'.", status, method, astGetClass( this ), ( (int *) data )[ 0 ], ( (int *) data )[ 1 ], name ); } else { ilen = sprintf( buf + rlen, "%*d", FITSIMCOL - FITSRLCOL + 1, ( (int *) data )[ 1 ] ); if( ilen < 0 || ilen > AST__FITSCHAN_FITSCARDLEN - col - rlen ) { astError( AST__BDFTS, "%s(%s): Cannot encode imaginary part of a " "complex integer value [%d,%d] into a FITS header card " "for keyword '%s'.", status, method, astGetClass( this ), ( (int *) data )[ 0 ], ( (int *) data )[ 1 ], name ); } else { len = ilen + rlen; } } /* Report an internal (ast) programming error if the keyword is of none of the above types. */ } else if( astOK ){ astError( AST__INTER, "EncodeValue: AST internal programming error - " "FITS %s data-type not yet supported.", status, type_names[ type ] ); } } /* If an error has occurred, return zero length. */ if( !astOK ) len = 0; /* Return the answer. */ return len; } static AstGrismMap *ExtractGrismMap( AstMapping *map, int iax, AstMapping **new_map, int *status ){ /* * Name: * ExtractGrismMap * Purpose: * Extract a GrismMap from the end of the supplied Mapping. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstGrismMap *ExtractGrismMap( AstMapping *map, int iax, * AstMapping **new_map, int *status ) * Class Membership: * FitsChan member function. * Description: * This function examines the supplied Mapping; if the specified output * coordinate of the Mapping is created directly by an un-inverted GrismMap, * then a pointer to the GrismMap is returned as the function value. A new * Mapping is also returned via parameter "new_map" which is a copy of * the supplied Mapping, except that the GrismMap is replaced with a * UnitMap. If no GrismMap is found, NULL is returned for both Mappings. * The condition that "the specified output coordinate of the Mapping is * created directly by an un-inverted GrismMap" means that the output * of the GrismMap is no subsequently modified by any further Mappings * before being returned as the "iax"th output of the supplied Mapping. * This means the GrismMap must be "at the end of" a CmpMap, not in * the middle of the CmpMap. * Parameters: * map * Pointer to the Mapping to check. * iax * The index for the output coordinate to be checked. * new_map * Pointer to a location at which to return a pointer to a new * Mapping which is a copy of "map" except that the GrismMap is * replaced by a UnitMap. NULL is returned if the specified output * was not created by a GrismMap. * status * Pointer to the inherited status variable. * Returned Value: * The extracted GrismMap, or NULL if the specified output was not * created by a GrismMap. */ /* Local Variables: */ AstMapping *mapa; /* First component Mapping */ AstMapping *mapb; /* Second component Mapping */ AstMapping *new_mapa; /* Replacement for first component Mapping */ AstMapping *new_mapb; /* Replacement for second component Mapping */ AstGrismMap *ret; /* Returned GrismMap */ int inva; /* Invert attribute for mapa within the CmpMap */ int invb; /* Invert attribute for mapb within the CmpMap */ int na; /* Number of outputs for mapa */ int old_inva; /* Current Invert attribute for mapa */ int old_invb; /* Current Invert attribute for mapb */ int series; /* Are component Mappings applied in series? */ /* Initialise */ ret = NULL; *new_map = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* If the supplied Mapping is a GrismMap which has not been inverted, return it as the function value and return a UnitMap as the new Mapping. */ if( astIsAGrismMap( map ) ) { if( !astGetInvert( map ) ) { ret = astClone( map ); *new_map = (AstMapping *) astUnitMap( 1, "", status ); } /* If the supplied Mapping is a CmpMap, get its two component Mappings, see if they are applied in parallel or series, and get the Invert attribute values which the component Mappings had at the time the CmpMap was created. */ } else if( astIsACmpMap( map ) ) { astDecompose( map, &mapa, &mapb, &series, &inva, &invb ); /* Temporaily reset the Invert attributes of the component Mappings back to the values they had when the CmpMap was created. */ old_inva = astGetInvert( mapa ); old_invb = astGetInvert( mapb ); astSetInvert( mapa, inva ); astSetInvert( mapb, invb ); /* If the supplied Mapping is a series CmpMap, attempt to extract a GrismMap from the second component Mapping ("mapb"). The first component Mapping ("mapa") is unchanged. We do not need to consdier the first component since we are only interested in GrismMaps which are at the end of the CmpMap. */ if( series ) { ret = ExtractGrismMap( mapb, iax, &new_mapb, status ); if( ret ) new_mapa = astClone( mapa ); /* If the supplied Mapping is a parallel CmpMap, attempt to extract a GrismMap from the component Mapping which produces output "iax". The other component Mapping is unchanged. */ } else { na = astGetNout( mapa ); if( iax < na ) { ret = ExtractGrismMap( mapa, iax, &new_mapa, status ); if( ret ) new_mapb = astClone( mapb ); } else { ret = ExtractGrismMap( mapb, iax - na, &new_mapb, status ); if( ret ) new_mapa = astClone( mapa ); } } /* If succesful, create a new CmpMap to return. */ if( ret ) { *new_map = (AstMapping *) astCmpMap( new_mapa, new_mapb, series, "", status ); new_mapa = astAnnul( new_mapa ); new_mapb = astAnnul( new_mapb ); } /* Re-instate the original Invert attributes of the component Mappings. */ astSetInvert( mapa, old_inva ); astSetInvert( mapb, old_invb ); /* Annul the component Mapping pointers. */ mapa = astAnnul( mapa ); mapb = astAnnul( mapb ); } /* Return the result. */ return ret; } static int MakeBasisVectors( AstMapping *map, int nin, int nout, double *g0, AstPointSet *psetg, AstPointSet *psetw, int *status ){ /* * Name: * MakeBasisVectors * Purpose: * Create a set of basis vectors in grid coordinates * Type: * Private function. * Synopsis: * #include "fitschan.h" * int MakeBasisVectors( AstMapping *map, int nin, int nout, * double *g0, AstPointSet *psetg, * AstPointSet *psetw, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a set of unit vectors in grid coordinates, * one for each grid axis. Each unit vector is parallel to the * corresponding grid axis, and rooted at a specified grid position * ("g0"). The IWC coordinates corresponding to "g0" and to the end of * each of the unit vectors are also returned, together with a flag * indicating if all the IWC coordinate values are good. * Parameters: * map * A pointer to a Mapping which transforms grid coordinates into * intermediate world coordinates (IWC). The number of outputs must * be greater than or equal to the number of inputs. * nin * The number of inputs for "map" (i.e. the number of grid axes). * nout * The number of outputs for "map" (i.e. the number of IWC axes). * g0 * Pointer to an array of holding the grid coordinates at the * "root" position. * psetg * A pointer to a PointSet which can be used to hold the required * grid positions. This should have room for nin+1 positions. On * return, the first position holds "g0", and the subsequent "nin" * positions hold are offset from "g0" by unit vectors along the * corresponding grid axis. * psetw * A pointer to a PointSet which can be used to hold the required * IWC position. This should also have room for nin+1 positions. On * return, the values are the IWC coordinates corresponding to the * grid positions returned in "psetg". * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if all the axis values in "psetw" are good. * Zero is returned otherwise. * Notes: * - Zero is returned if an error occurs. */ /* Local Variables: */ double **ptrg; double **ptrw; double *c; int i; int ii; int j; int ret; /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Get pointers to the data in the two supplied PointSets. */ ptrg = astGetPoints( psetg ); ptrw = astGetPoints( psetw ); /* Check the pointers can be used safely. */ if( astOK ) { /* Assume success. */ ret = 1; /* Store the required grid positions in PointSet "pset1". The first position is the supplied root grid position, g0. The next "nin" positions are offset from the root position by a unit vector along each grid axis in turn. Store values for each grid axis in turn. */ for( i = 0; i < nin; i++ ) { /* Get a pointer to the first axis value for this grid axis. */ c = ptrg[ i ]; /* Initially set all values for this axis to the supplied root grid value. */ for( ii = 0; ii < nin + 1; ii++ ) c[ ii ] = g0[ i ]; /* Modify the value corresponding to the vector along this grid axis. */ c[ i + 1 ] += 1.0; } /* Transform these grid positions in IWC positions using the supplied Mapping. */ (void) astTransform( map, psetg, 1, psetw ); /* Check that all the transformed positions are good. */ for( j = 0; j < nout; j++ ) { c = ptrw[ j ]; for( ii = 0; ii < nin + 1; ii++, c++ ) { if( *c == AST__BAD ) { ret = 0; break; } } } } /* Return the result. */ return ret; } static int FindBasisVectors( AstMapping *map, int nin, int nout, double *dim, AstPointSet *psetg, AstPointSet *psetw, int *status ){ /* * Name: * FindBasisVectors * Purpose: * Find the a set of basis vectors in grid coordinates * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FindBasisVectors( AstMapping *map, int nin, int nout, * double *dim, AstPointSet *psetg, * AstPointSet *psetw, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a set of unit vectors in grid coordinates, * one for each grid axis. Each unit vector is parallel to the * corresponding grid axis, and rooted at a specified grid position * ("g0"). The IWC coordinates corresponding to "g0" and to the end of * each of the unit vectors are also returned, together with a flag * indicating if all the IWC coordinate values are good. * Parameters: * map * A pointer to a Mapping which transforms grid coordinates into * intermediate world coordinates (IWC). The number of outputs must * be greater than or equal to the number of inputs. * nin * The number of inputs for "map" (i.e. the number of grid axes). * nout * The number of outputs for "map" (i.e. the number of IWC axes). * dim * Array dimensions, in pixels, if known (otherwise supplied a NULL * pointer to values of AST__BAD). * psetg * A pointer to a PointSet which can be used to hold the required * grid position. This should have room for nin+1 positions. On * return, the first position holds the "root" position and the * subsequent "nin" positions hold are offset from root position * by unit vectors along the corresponding grid axis. * psetw * A pointer to a PointSet which can be used to hold the required * IWC position. This should also have room for nin+1 positions. On * return, the values are the IWC coordinates corresponding to the * grid positions returned in "psetg". * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if a set of basis vectors was found * succesfully. Zero is returned otherwise. * Notes: * - Zero is returned if an error occurs. */ /* Local Variables: */ double *g0; double dd; double ddlim; int i; int ii; int ret; /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Allocate an array to store the candidate root position. */ g0 = astMalloc( sizeof( double )*(size_t) nin ); if( astOK ) { /* First try the grid centre, if known. */ ddlim = 0; ret = 0; if( dim ) { ret = 1; for( i = 0; i < nin; i++ ) { if( dim[ i ] != AST__BAD ) { g0[ i ] = 0.5*( 1 + dim[ i ] ); if( dim[ i ] > ddlim ) ddlim = dim[ i ]; } else { ret = 0; break; } } } if( ret ) ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status ); /* If this did not produce a set of good IWC positions, try grid position (1,1,1...). */ if( !ret ) { for( i = 0; i < nin; i++ ) g0[ i ] = 1.0; ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status ); } /* If this did not produce a set of good IWC positions, try a sequence of grid positions which move an increasing distance along each grid axis from (1,1,1,...). Stop when we get further than "ddlim" from the origin. */ dd = 10.0; if( ddlim == 0.0 ) ddlim = 10240.0; while( !ret && dd <= ddlim ) { /* First try positions which extend across the middle of the data set. If the image dimensions are known, make the line go from the "bottom left corner" towards the "top right corner", taking the aspect ratio of the image into account. Otherise, just use a vector of (1,1,1,..) */ for( i = 0; i < nin; i++ ) { if( dim && dim[ i ] != AST__BAD ) { g0[ i ] = dd*dim[ i ]/ddlim; } else { g0[ i ] = dd; } } ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status ); /* If the above didn't produce good positions, try moving out along each grid axis in turn. */ for( ii = 0; !ret && ii < nin; ii++ ) { for( i = 0; i < nin; i++ ) g0[ i ] = 1.0; g0[ ii ] = dd; ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status ); } /* Go further out from the origin for the next set of tests (if any). */ dd *= 2.0; } } /* Free resources. */ g0 = astFree( g0 ); /* Return the result. */ return ret; } static int FindLonLatSpecAxes( FitsStore *store, char s, int *axlon, int *axlat, int *axspec, const char *method, const char *class, int *status ) { /* * Name: * FindLonLatSpecAxes * Purpose: * Search the CTYPE values in a FitsStore for celestial and spectral axes. * Type: * Private function. * Synopsis: * int FindLonLatSpecAxes( FitsStore *store, char s, int *axlon, int *axlat, * int *axspec, const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * The supplied FitsStore is searched for axes with a specified axis * description character which describe celestial longitude or latitude * or spectral position. * Parameters: * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * axlon * Address of a location at which to return the index of the * longitude axis (if found). This is the value of "i" within the * keyword name "CTYPEi". A value of -1 is returned if no longitude * axis is found. * axlat * Address of a location at which to return the index of the * latitude axis (if found). This is the value of "i" within the * keyword name "CTYPEi". A value of -1 is returned if no latitude * axis is found. * axspec * Address of a location at which to return the index of the * spectral axis (if found). This is the value of "i" within the * keyword name "CTYPEi". A value of -1 is returned if no spectral * axis is found. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * One is returned if both celestial axes were found. Zero is returned if * either axis was not found. The presence of a spectral axis does not * affect the returned value. * Notes: * - If an error occurs, zero is returned. */ /* Local Variables: */ char *assys; char *astype; char algcode[5]; char stype[5]; const char *ctype; double dval; int i; int wcsaxes; /* Initialise */ *axlon = -1; *axlat = -1; *axspec = -1; /* Check the global status. */ if ( !astOK ) return 0; /* Obtain the number of FITS WCS axes in the header. If the WCSAXES header was specified, use it. Otherwise assume it is the same as the number of pixel axes. */ dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) { wcsaxes = (int) dval + 0.5; } else { wcsaxes = store->naxis; } /* Loop round the FITS WCS axes, getting each CTYPE value. */ for( i = 0; i < wcsaxes && astOK; i++ ){ ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); /* Check a value was found. */ if( ctype ) { /* First check for spectral axes, either FITS-WCS or AIPS-like. */ if( IsSpectral( ctype, stype, algcode, status ) || IsAIPSSpectral( ctype, &astype, &assys, status ) ) { *axspec = i; /* Otherwise look for celestial axes. Celestial axes must have a "-" as the fifth character in CTYPE. */ } else if( ctype[4] == '-' ) { /* See if this is a longitude axis (e.g. if the first 4 characters of CTYPE are "RA--" or "xLON" or "yzLN" ). */ if( !strncmp( ctype, "RA--", 4 ) || !strncmp( ctype, "AZ--", 4 ) || !strncmp( ctype + 1, "LON", 3 ) || !strncmp( ctype + 2, "LN", 2 ) ){ *axlon = i; /* Otherwise see if it is a latitude axis. */ } else if( !strncmp( ctype, "DEC-", 4 ) || !strncmp( ctype, "EL--", 4 ) || !strncmp( ctype + 1, "LAT", 3 ) || !strncmp( ctype + 2, "LT", 2 ) ){ *axlat = i; } } } } /* Indicate failure if an error occurred. */ if( !astOK ) { *axlon = -1; *axlat = -1; *axspec = -1; } /* Return the result. */ return ( *axlat != -1 && *axlon != -1 ); } static void FindWcs( AstFitsChan *this, int last, int all, int rewind, const char *method, const char *class, int *status ){ /* * Name: * FindWcs * Purpose: * Find the first or last FITS WCS related keyword in a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FindWcs( AstFitsChan *this, int last, int all, int rewind, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A search is made through the FitsChan for the first or last card * which relates to a FITS WCS keyword (any encoding). If "last" is * non-zero, the next card becomes the current card. If "last" is * zero, the WCS card is left as the current card. Cards marked as * having been read are included or not, as specified by "all". * Parameters: * this * Pointer to the FitsChan. * last * If non-zero, the last WCS card is searched for. Otherwise, the * first WCS card is searched for. * all * If non-zero, then cards marked as having been read are included * in the search. Otherwise such cards are ignored. * rewind * Only used if "last" is zero (i.e. the first card is being * searched for). If "rewind" is non-zero, then the search starts * from the first card in the FitsChan. If zero, the search starts * from the current card. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - The FitsChan is left at end-of-file if no FITS-WCS keyword cards * are found in the FitsChan. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *keyname; /* Keyword name from current card */ int nfld; /* Number of fields in keyword template */ int old_ignore_used; /* Original value of variable ignore_used */ /* Check the global status. Also check the FitsChan is not empty. */ if( !astOK || !this->head ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Indicate that we should, or should not, skip over cards marked as having been read. */ old_ignore_used = ignore_used; ignore_used = all ? 0 : 1; /* If required, set the FitsChan to start or end of file. */ if( last ) { astSetCard( this, INT_MAX ); } else if( rewind ) { astClearCard( this ); } /* If the current card is marked as used, and we are skipping used cards, move on to the next unused card */ if( CARDUSED( this->card ) ) MoveCard( this, last?-1:1, method, class, status ); /* Check each card moving backwards from the end to the start, or forwards from the start to the end, until a WCS keyword is found, or the other end of the FitsChan is reached. */ while( astOK ){ /* Get the keyword name from the current card. */ keyname = CardName( this, status ); /* Save a pointer to the keyword if it is the first non-null, non-comment card. */ if( keyname ) { /* If it matches any of the WCS keywords, move on one card and break out of the loop. */ if( Match( keyname, "CRVAL%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CRPIX%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CDELT%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CROTA%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CTYPE%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CUNIT%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PC%3d%3d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CD%3d%3d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CD%1d_%1d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PC%1d_%1d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "LONGPOLE", 0, NULL, &nfld, method, class, status ) || Match( keyname, "LONPOLE%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "LATPOLE%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PROJP%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PV%d_%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PS%d_%d%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "EPOCH", 0, NULL, &nfld, method, class, status ) || Match( keyname, "EQUINOX%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "MJD-OBS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "DATE-OBS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "TIMESYS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "RADECSYS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "RADESYS%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "C%1dVAL%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "C%1dPIX%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "C%1dELT%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "C%1dYPE%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "C%1dNIT%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CNPIX1", 0, NULL, &nfld, method, class, status ) || Match( keyname, "CNPIX2", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PPO%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "AMDX%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "AMDY%d", 0, NULL, &nfld, method, class, status ) || Match( keyname, "XPIXELSZ", 0, NULL, &nfld, method, class, status ) || Match( keyname, "YPIXELSZ", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTRAH", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTRAM", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTRAS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTDECD", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTDECM", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTDECS", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTDECSN", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PLTSCALE", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PPO1", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PPO2", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PPO4", 0, NULL, &nfld, method, class, status ) || Match( keyname, "PPO5", 0, NULL, &nfld, method, class, status ) || Match( keyname, "WCSNAME%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "SPECSYS%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "SSYSSRC%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "ZSOURCE%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "VELOSYS%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "RESTFRQ%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "MJD_AVG%0c", 0, NULL, &nfld, method, class, status ) || Match( keyname, "OBSGEO-X", 0, NULL, &nfld, method, class, status ) || Match( keyname, "OBSGEO-Y", 0, NULL, &nfld, method, class, status ) || Match( keyname, "OBSGEO-Z", 0, NULL, &nfld, method, class, status ) ) { if( last ) MoveCard( this, 1, method, class, status ); break; } } /* Leave the FitsChan at end-of-file if no WCS cards were found. */ if( (last && FitsSof( this, status ) ) || (!last && astFitsEof( this ) ) ) { astSetCard( this, INT_MAX ); break; } else { MoveCard( this, last?-1:1, method, class, status ); } } /* Re-instate the original flag indicating if cards marked as having been read should be skipped over. */ ignore_used = old_ignore_used; /* Return. */ return; } static int FindString( int n, const char *list[], const char *test, const char *text, const char *method, const char *class, int *status ){ /* * Name: * FindString * Purpose: * Find a given string within an array of character strings. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FindString( int n, const char *list[], const char *test, * const char *text, const char *method, const char *class, int *status ) * Class Membership: * FitsChan method. * Description: * This function identifies a supplied string within a supplied * array of valid strings, and returns the index of the string within * the array. The test option may not be abbreviated, but case is * insignificant. * Parameters: * n * The number of strings in the array pointed to be "list". * list * A pointer to an array of legal character strings. * test * A candidate string. * text * A string giving a description of the object, parameter, * attribute, etc, to which the test value refers. * This is only for use in constructing error messages. It should * start with a lower case letter. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The index of the identified string within the supplied array, starting * at zero. * Notes: * - A value of -1 is returned if an error has already occurred, or * if this function should fail for any reason (for instance if the * supplied option is not specified in the supplied list). */ /* Local Variables: */ int ret; /* The returned index */ /* Check global status. */ if( !astOK ) return -1; /* Compare the test string with each element of the supplied list. Leave the loop when a match is found. */ for( ret = 0; ret < n; ret++ ) { if( !Ustrcmp( test, list[ ret ], status ) ) break; } /* Report an error if the supplied test string does not match any element in the supplied list. */ if( ret >= n && astOK ) { astError( AST__RDERR, "%s(%s): Illegal value '%s' supplied for %s.", status, method, class, test, text ); ret = -1; } /* Return the answer. */ return ret; } static int FitOK( int n, double *act, double *est, double tol, int *status ) { /* * Name: * FitOK * Purpose: * See if a fit is usable. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FitOK( int n, double *act, double *est, double tol, int *status ) * Class Membership: * FitsChan member function. * Description: * This function is supplied with a set of actual data values, and the * corresponding values estimated by some fitting process. It tests * that the RMS residual between them is no more than "tol". * Parameters: * n * Number of data points. * act * Pointer to the start of the actual data values. * est * Pointer to the start of the estimated data values. * tol * The largest acceptable RMS error between "act" and "est". * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if the two sets of values agree. Zero is * returned otherwise. * Notes: * - Zero is returned if an error occurs. */ /* Local Variables: */ int ret, i; double s1, s2; double *px, *py, diff, mserr; /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Initialise the sum of the squared residuals, and the number summed. */ s1 = 0.0; s2 = 0.0; /* Initialise pointers to the next actual and estimated values to use. */ px = act; py = est; /* Loop round all pairs of good actual and estimate value. */ for( i = 0; i < n; i++, px++, py++ ){ if( *px != AST__BAD && *py != AST__BAD ) { /* Increment the sums need to find the RMS residual between the actual and estimated values. */ diff = *px - *py; s1 += diff*diff; s2 += 1.0; } } /* If the sums are usable... */ if( s2 > 0.0 ) { /* Form the mean squared residual, and check if it is less than the squared error limit. */ mserr = s1/s2; if( mserr < tol*tol ) ret = 1; } /* Return the result. */ return ret; } static int FitsFromStore( AstFitsChan *this, FitsStore *store, int encoding, double *dim, AstFrameSet *fs, const char *method, const char *class, int *status ){ /* * Name: * FitsFromStore * Purpose: * Store WCS keywords in a FitsChan. * Type: * Private function. * Synopsis: * int FitsFromStore( AstFitsChan *this, FitsStore *store, int encoding, * double *dim, AstFrameSet *fs, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using a specified encoding. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * encoding * The encoding to use. * dim * Pointer to an array holding the array dimensions (AST__BAD * indicates that the dimenson is not known). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ int ret; /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Set the current card so that it points to the last WCS-related keyword in the FitsChan (whether previously read or not). Any new WCS related keywords either over-write pre-existing cards for the same keyword, or (if no pre-existing card exists) are inserted after the last WCS related keyword. */ FindWcs( this, 1, 1, 0, method, class, status ); /* Do each non-standard FITS encoding... */ if( encoding == DSS_ENCODING ){ ret = DSSFromStore( this, store, method, class, status ); } else if( encoding == FITSPC_ENCODING ){ ret = PCFromStore( this, store, method, class, status ); } else if( encoding == FITSIRAF_ENCODING ){ ret = IRAFFromStore( this, store, method, class, status ); } else if( encoding == FITSAIPS_ENCODING ){ ret = AIPSFromStore( this, store, method, class, status ); } else if( encoding == FITSAIPSPP_ENCODING ){ ret = AIPSPPFromStore( this, store, method, class, status ); } else if( encoding == FITSCLASS_ENCODING ){ ret = CLASSFromStore( this, store, fs, dim, method, class, status ); /* Standard FITS-WCS encoding */ } else { ret = WcsFromStore( this, store, method, class, status ); } /* If there are any Tables in the FitsStore move the KeyMap that contains them from the FitsStore to the FitsChan, from where they can be retrieved using the public astGetTables method. */ if( astMapSize( store->tables ) > 0 ) { if( !this->tables ) this->tables = astKeyMap( " ", status ); astMapCopy( this->tables, store->tables ); (void) astAnnul( store->tables ); store->tables = astKeyMap( " ", status ); } /* If an error has occurred, return zero. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static FitsStore *FitsToStore( AstFitsChan *this, int encoding, const char *method, const char *class, int *status ){ /* * Name: * FitsToStore * Purpose: * Return a pointer to a FitsStore structure containing WCS information * read from the supplied FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * FitsStore *FitsToStore( AstFitsChan *this, int encoding, * const char *method, const char *class ) * Class Membership: * FitsChan member function. * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function creates a new FitsStore containing WCS information * read from the supplied FitsChan using the specified encoding. An * error is reported and a null pointer returned if the FitsChan does * not contain usable WCS information with the specified encoding. * Parameters: * this * Pointer to the FitsChan. * encoding * The encoding to use. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * Returned Value: * A pointer to a new FitsStore, or NULL if an error has occurred. The * FitsStore should be released using FreeStore function when it is no * longer needed. */ /* Local Variables: */ AstFitsChan *trans; FitsStore *ret; /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Allocate memory for the new FitsStore, and store NULL pointers in it. */ ret = (FitsStore *) astMalloc( sizeof(FitsStore) ); if( ret ) { ret->cname = NULL; ret->ctype = NULL; ret->ctype_com = NULL; ret->cunit = NULL; ret->ps = NULL; ret->radesys = NULL; ret->wcsname = NULL; ret->wcsaxes = NULL; ret->pc = NULL; ret->cdelt = NULL; ret->crpix = NULL; ret->crval = NULL; ret->equinox = NULL; ret->latpole = NULL; ret->lonpole = NULL; ret->mjdobs = NULL; ret->mjdavg = NULL; ret->dut1 = NULL; ret->pv = NULL; ret->specsys = NULL; ret->ssyssrc = NULL; ret->obsgeox = NULL; ret->obsgeoy = NULL; ret->obsgeoz = NULL; ret->restfrq = NULL; ret->restwav = NULL; ret->zsource = NULL; ret->velosys = NULL; ret->asip = NULL; ret->bsip = NULL; ret->apsip = NULL; ret->bpsip = NULL; ret->imagfreq = NULL; ret->axref = NULL; ret->naxis = 0; ret->timesys = NULL; ret->tables = astKeyMap( "", status ); ret->skyref = NULL; ret->skyrefp = NULL; ret->skyrefis = NULL; } /* Call the routine apropriate to the encoding. */ if( encoding == DSS_ENCODING ){ DSSToStore( this, ret, method, class, status ); /* All other foreign encodings are treated as variants of FITS-WCS. */ } else { /* Create a new FitsChan containing standard translations for any non-standard keywords in the supplied FitsChan. The non-standard keywords are marked as provisionally read in the supplied FitsChan. */ trans = SpecTrans( this, encoding, method, class, status ); /* Copy the required values to the FitsStore, using keywords in "trans" in preference to those in "this". */ WcsToStore( this, trans, ret, method, class, status ); /* Delete the temporary FitsChan holding translations of non-standard keywords. */ if( trans ) trans = (AstFitsChan *) astDelete( trans ); /* Store the number of pixel axes. This is taken as the highest index used in any primary CRPIX keyword. */ ret->naxis = GetMaxJM( &(ret->crpix), ' ', status ) + 1; } /* If an error has occurred, free the returned FitsStore, and return a null pointer. */ if( !astOK ) ret = FreeStore( ret, status ); /* Return the answer. */ return ret; } static void FreeItem( double ****item, int *status ){ /* * Name: * FreeItem * Purpose: * Frees all dynamically allocated memory associated with a specified * item in a FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FreeItem( double ****item, int *status ); * Class Membership: * FitsChan member function. * Description: * Frees all dynamically allocated memory associated with the specified * item in a FitsStore. A NULL pointer is stored in the FitsStore. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crval) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (j), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (i) or projection parameter (m). * status * Pointer to the inherited status variable. * Notes: * - This function attempt to execute even if an error has occurred. */ /* Local Variables: */ int si; /* Integer co-ordinate version index */ int j; /* Intermediate co-ordinate axis index */ int oldstatus; /* Old error status value */ int oldreport; /* Old error reporting value */ /* Other initialisation to avoid compiler warnings. */ oldreport = 0; /* Check the supplied pointer */ if( item && *item ){ /* Start a new error reporting context. */ oldstatus = astStatus; if( !astOK ) { oldreport = astReporting( 0 ); astClearStatus; } /* Loop round each coordinate version. */ for( si = 0; si < astSizeOf( (void *) *item )/sizeof(double **); si++ ){ /* Check the pointer stored for this co-ordinate version is not null. */ if( (*item)[si] ) { /* Loop round the intermediate axes. */ for( j = 0; j < astSizeOf( (void *) (*item)[si] )/sizeof(double *); j++ ){ /* Free the pixel axis/parameter index pointer. */ (*item)[si][j] = (double *) astFree( (void *) (*item)[si][j] ); } /* Free the intermediate axes pointer */ (*item)[si] = (double **) astFree( (void *) (*item)[si] ); } } /* Free the co-ordinate versions pointer */ *item = (double ***) astFree( (void *) *item ); /* If there was an error status on entry to this function, re-instate it. Otherwise, allow any new error status to remain. */ if( oldstatus ){ if( !astOK ) astClearStatus; astSetStatus( oldstatus ); astReporting( oldreport ); } } } static void FreeItemC( char *****item, int *status ){ /* * Name: * FreeItemC * Purpose: * Frees all dynamically allocated memory associated with a specified * string item in a FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FreeItemC( char *****item, int *status ) * Class Membership: * FitsChan member function. * Description: * Frees all dynamically allocated memory associated with the specified * string item in a FitsStore. A NULL pointer is stored in the FitsStore. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->ctype) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (j), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element (a char pointyer) for every pixel axis (i) or * projection parameter (m). * status * Pointer to the inherited status variable. * Notes: * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ int si; /* Integer co-ordinate version index */ int i; /* Intermediate co-ordinate axis index */ int jm; /* Pixel co-ordinate axis or parameter index */ int oldstatus; /* Old error status value */ int oldreport; /* Old error reporting value */ /* Other initialisation to avoid compiler warnings. */ oldreport = 0; /* Check the supplied pointer */ if( item && *item ){ /* Start a new error reporting context. */ oldstatus = astStatus; if( !astOK ) { oldreport = astReporting( 0 ); astClearStatus; } /* Loop round each coordinate version. */ for( si = 0; si < astSizeOf( (void *) *item )/sizeof(char ***); si++ ){ /* Check the pointer stored for this co-ordinate version is not null. */ if( (*item)[si] ) { /* Loop round the intermediate axes. */ for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(char **); i++ ){ /* Check the pointer stored for this intermediate axis is not null. */ if( (*item)[si][i] ) { /* Loop round the pixel axes or parameter values. */ for( jm = 0; jm < astSizeOf( (void *) (*item)[si][i] )/sizeof(char *); jm++ ){ /* Free the string. */ (*item)[si][i][jm] = (char *) astFree( (void *) (*item)[si][i][jm] ); } /* Free the pixel axes/parameter pointer */ (*item)[si][i] = (char **) astFree( (void *) (*item)[si][i] ); } } /* Free the intermediate axes pointer */ (*item)[si] = (char ***) astFree( (void *) (*item)[si] ); } } /* Free the co-ordinate versions pointer */ *item = (char ****) astFree( (void *) *item ); /* If there was an error status on entry to this function, re-instate it. Otherwise, allow any new error status to remain. */ if( oldstatus ){ if( !astOK ) astClearStatus; astSetStatus( oldstatus ); astReporting( oldreport ); } } } static FitsStore *FreeStore( FitsStore *store, int *status ){ /* * Name: * FreeStore * Purpose: * Free dynamic arrays stored in a FitsStore structure. * Type: * Private function. * Synopsis: * FitsStore *FreeStore( FitsStore *store, int *status ) * Class Membership: * FitsChan * Description: * This function frees all dynamically allocated arrays stored in the * supplied FitsStore structure, and returns a NULL pointer. * Parameters: * store * Pointer to the structure to clean. * status * Pointer to the inherited status variable. * Notes: * - This function attempts to execute even if an error exists on entry. */ /* Return if no FitsStore was supplied. */ if( !store ) return NULL; /* Free each of the dynamic arrays stored in the FitsStore. */ FreeItemC( &(store->cname), status ); FreeItemC( &(store->ctype), status ); FreeItemC( &(store->ctype_com), status ); FreeItemC( &(store->cunit), status ); FreeItemC( &(store->radesys), status ); FreeItemC( &(store->wcsname), status ); FreeItemC( &(store->specsys), status ); FreeItemC( &(store->ssyssrc), status ); FreeItemC( &(store->ps), status ); FreeItemC( &(store->timesys), status ); FreeItem( &(store->pc), status ); FreeItem( &(store->cdelt), status ); FreeItem( &(store->crpix), status ); FreeItem( &(store->crval), status ); FreeItem( &(store->equinox), status ); FreeItem( &(store->latpole), status ); FreeItem( &(store->lonpole), status ); FreeItem( &(store->mjdobs), status ); FreeItem( &(store->dut1), status ); FreeItem( &(store->mjdavg), status ); FreeItem( &(store->pv), status ); FreeItem( &(store->wcsaxes), status ); FreeItem( &(store->obsgeox), status ); FreeItem( &(store->obsgeoy), status ); FreeItem( &(store->obsgeoz), status ); FreeItem( &(store->restfrq), status ); FreeItem( &(store->restwav), status ); FreeItem( &(store->zsource), status ); FreeItem( &(store->velosys), status ); FreeItem( &(store->asip), status ); FreeItem( &(store->bsip), status ); FreeItem( &(store->apsip), status ); FreeItem( &(store->bpsip), status ); FreeItem( &(store->imagfreq), status ); FreeItem( &(store->axref), status ); store->tables = astAnnul( store->tables ); FreeItem( &(store->skyref), status ); FreeItem( &(store->skyrefp), status ); FreeItemC( &(store->skyrefis), status ); return (FitsStore *) astFree( (void *) store ); } static char *FormatKey( const char *key, int c1, int c2, char s, int *status ){ /* * Name: * FormatKey * Purpose: * Format a keyword name with indices and co-ordinate version character. * Type: * Private function. * Synopsis: * char *FormatKey( const char *key, int c1, int c2, char s, int *status ) * Class Membership: * FitsChan * Description: * This function formats a keyword name by including the supplied * axis/parameter indices and co-ordinate version character. * Parameters: * key * The base name of the keyword (e.g. "CD", "CRVAL", etc). * c1 * An integer value to append to the end of the keyword. Ignored if * less than zero. * c2 * A second integer value to append to the end of the keyword. Ignored if * less than zero. This second integer is preceded by an underscore. * s * The co-ordinate version character to append to the end of the * final string. Ignored if blank. * status * Pointer to the inherited status variable. * Returned Value; * A pointer to a static character buffer containing the final string. * NULL if an error occurs. */ /* Local Variables: */ astDECLARE_GLOBALS char *ret; int len; int nc; /* Initialise */ ret = NULL; /* Check inherited status */ if( !astOK ) return ret; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* No characters stored yet. A value of -1 is used to indicate that an error has occurred. */ len = 0; /* Store the supplied keyword base name. */ if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%s", key ) ) >= 0 ){ len += nc; } else { len = -1; } /* If index c1 has been supplied, append it to the end of the string. */ if( c1 >= 0 ) { if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%d", c1 ) ) >= 0 ){ len += nc; } else { len = -1; } /* If index c2 has been supplied, append it to the end of the string, preceded by an underscore. */ if( c2 >= 0 ) { if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "_%d", c2 ) ) >= 0 ){ len += nc; } else { len = -1; } } } /* If a co-ordinate version character has been supplied, append it to the end of the string. */ if( s != ' ' ) { if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%c", s ) ) >= 0 ){ len += nc; } else { len = -1; } } /* Report an error if necessary */ if( len < 0 && astOK ) { astError( AST__INTER, "FormatKey(fitschan): AST internal error; failed " "to format the keyword %s with indices %d and %d, and " "co-ordinate version %c.", status, key, c1, c2, s ); ret = NULL; } else { ret = formatkey_buff; } return formatkey_buff; } static AstObject *FsetFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * FsetFromStore * Purpose: * Create a FrameSet using the the information previously stored in * the suppllied FitsStore structure. * Type: * Private function. * Synopsis: * AstObject *FsetFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function creates a new FrameSet containing WCS information * stored in the supplied FitsStore. A null pointer is returned and no * error is reported if this is not possible. * Parameters: * this * The FitsChan from which the keywords were read. Warning messages * are added to this FitsChan if the celestial co-ordinate system is * not recognized. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new FrameSet, or a null pointer if no FrameSet * could be constructed. * Notes: * - The pixel Frame is given a title of "Pixel Coordinates", and * each axis in the pixel Frame is given a label of the form "Pixel * axis ", where is the axis index (starting at one). * - The FITS CTYPE keyword values are used to set the labels for any * non-celestial axes in the physical coordinate Frames, and the FITS * CUNIT keywords are used to set the corresponding units strings. * - On exit, the pixel Frame is the base Frame, and the physical * Frame derived from the primary axis descriptions is the current Frame. * - Extra Frames are added to hold any secondary axis descriptions. All * axes within such a Frame refer to the same coordinate version ('A', * 'B', etc). */ /* Local Variables: */ AstFrame *frame; /* Pointer to pixel Frame */ AstFrameSet *ret; /* Pointer to returned FrameSet */ char buff[ 20 ]; /* Buffer for axis label */ char s; /* Co-ordinate version character */ int i; /* Pixel axis index */ int physical; /* Index of primary physical co-ordinate Frame */ int pixel; /* Index of pixel Frame in returned FrameSet */ int use; /* Has this co-ordinate version been used? */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return (AstObject *) ret; /* Only proceed if there are some axes. */ if( store->naxis ) { /* Create a Frame describing the pixel coordinate system. Give it the Domain GRID. */ frame = astFrame( store->naxis, "Title=Pixel Coordinates,Domain=GRID", status ); /* Store labels for each pixel axis. */ if( astOK ){ for( i = 0; i < store->naxis; i++ ){ sprintf( buff, "Pixel axis %d", i + 1 ); astSetLabel( frame, i, buff ); } } /* Create the FrameSet initially holding just the pixel coordinate frame (this becomes the base Frame). */ ret = astFrameSet( frame, "", status ); /* Annul the pointer to the pixel coordinate Frame. */ frame = astAnnul( frame ); /* Get the index of the pixel Frame in the FrameSet. */ pixel = astGetCurrent( ret ); /* Produce the Frame describing the primary axis descriptions, and add it into the FrameSet. */ AddFrame( this, ret, pixel, store->naxis, store, ' ', method, class, status ); /* Get the index of the primary physical co-ordinate Frame in the FrameSet. */ physical = astGetCurrent( ret ); /* Loop, producing secondary axis Frames for each of the co-ordinate versions stored in the FitsStore. */ for( s = 'A'; s <= GetMaxS( &(store->crval), status ) && astOK; s++ ){ /* Only use this co-ordinate version character if any of the required keywords (for any axis) are stored in the FitsStore. */ use = 0; for( i = 0; i < store->naxis; i++ ){ if( GetItem( &(store->crval), i, 0, s, NULL, method, class, status ) != AST__BAD || GetItem( &(store->crpix), 0, i, s, NULL, method, class, status ) != AST__BAD || GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ) != NULL ){ use = 1; break; } } /* If this co-ordinate version has been used, add a Frame to the returned FrameSet holding this co-ordinate version. */ if( use ) AddFrame( this, ret, pixel, store->naxis, store, s, method, class, status ); } /* Ensure the pixel Frame is the Base Frame and the primary physical Frame is the Current Frame. */ astSetBase( ret, pixel ); astSetCurrent( ret, physical ); /* Remove any unneeded Frames that hold a FITS representation of offset coordinates. */ TidyOffsets( ret, status ); /* If an error has occurred, free the returned FrameSet and return a null pointer. */ if( !astOK ) ret = astAnnul( ret ); } /* Return the answer. */ return (AstObject *) ret; } static FitsStore *FsetToStore( AstFitsChan *this, AstFrameSet *fset, int naxis, double *dim, int encoding, const char *class, const char *method, int *status ){ /* * Name: * FsetToStore * Purpose: * Fill a FitsStore structure with a description of the supplied * FrameSet. * Type: * Private function. * Synopsis: * FitsStore *FsetToStore( AstFitsChan *this, AstFrameSet *fset, int naxis, * double *dim, int encoding, const char *class, * const char *method, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function creates a new FitsStore containing WCS information * read from the supplied FitsChan using the specified encoding. An * error is reported and a null pointer returned if the FitsChan does * not contain usable WCS information with the specified encoding. * Parameters: * this * Pointer to the FitsChan. * fset * Pointer to the FrameSet. * naxis * The number of axes in the Base Frame of the supplied FrameSet. * dim * Pointer to an array of pixel axis dimensions. Individual elements * will be AST__BAD if dimensions are not known. * encoding * The encoding being used. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a new FitsStore, or NULL if an error has occurred. The * FitsStore should be released using FreeStore function when it is no * longer needed. * Notes: * - A NULL pointer will be returned if this function is invoked * with the AST error status set, or if it should fail for any * reason. * - The Base Frame in the FrameSet is used as the pixel Frame, and * the Current Frame is used to create the primary axis descriptions. * Attempts are made to create secondary axis descriptions for any * other Frames in the FrameSet (up to a total of 26). */ /* Local Variables: */ AstFrame *frame; /* A Frame */ const char *id; /* Frame Ident string */ int nfrm; /* Number of Frames in FrameSet */ char *sid; /* Pointer to array of version letters */ int frms[ 'Z' + 1 ]; /* Array of Frame indices */ FitsStore *ret; /* Returned FitsStore */ char s; /* Next available co-ordinate version character */ char s0; /* Co-ordinate version character */ int ibase; /* Base Frame index */ int icurr; /* Current Frame index */ int ifrm; /* Next Frame index */ int isoff; /* Is the Frame an offset SkyFrame? */ int primok; /* Primary Frame stored succesfully? */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Allocate memory for the new FitsStore, and store NULL pointers in it. */ ret = (FitsStore *) astMalloc( sizeof(FitsStore) ); if( astOK ) { ret->cname = NULL; ret->ctype = NULL; ret->ctype_com = NULL; ret->cunit = NULL; ret->ps = NULL; ret->radesys = NULL; ret->wcsname = NULL; ret->wcsaxes = NULL; ret->pc = NULL; ret->cdelt = NULL; ret->crpix = NULL; ret->crval = NULL; ret->equinox = NULL; ret->latpole = NULL; ret->lonpole = NULL; ret->dut1 = NULL; ret->mjdobs = NULL; ret->mjdavg = NULL; ret->pv = NULL; ret->specsys = NULL; ret->ssyssrc = NULL; ret->obsgeox = NULL; ret->obsgeoy = NULL; ret->obsgeoz = NULL; ret->restfrq = NULL; ret->restwav = NULL; ret->zsource = NULL; ret->velosys = NULL; ret->asip = NULL; ret->bsip = NULL; ret->apsip = NULL; ret->bpsip = NULL; ret->imagfreq = NULL; ret->axref = NULL; ret->naxis = naxis; ret->timesys = NULL; ret->tables = astKeyMap( "", status ); ret->skyref = NULL; ret->skyrefp = NULL; ret->skyrefis = NULL; /* Obtain the index of the Base Frame (i.e. the pixel frame ). */ ibase = astGetBase( fset ); /* Obtain the index of the Current Frame (i.e. the Frame to use as the primary physical coordinate frame). */ icurr = astGetCurrent( fset ); /* Does the current Frame contain a SkyFrame that describes offset coordinates? */ isoff = IsSkyOff( fset, icurr, status ); /* Add a description of the primary axes to the FitsStore, based on the Current Frame in the FrameSet. */ primok = AddVersion( this, fset, ibase, icurr, ret, dim, ' ', encoding, isoff, method, class, status ); /* Do not add any alternate axis descriptions if the primary axis descriptions could not be produced. */ if( primok && astOK ) { /* Get the number of Frames in the FrameSet. */ nfrm = astGetNframe( fset ); /* We now need to allocate a version letter to each Frame. Allocate memory to hold the version letter assigned to each Frame. */ sid = (char *) astMalloc( ( nfrm + 1 )*sizeof( char ) ); /* The frms array has an entry for each of the 26 possible version letters (starting at A and ending at Z). Each entry holds the index of the Frame which has been assigned that version character. Initialise this array to indicate that no version letters have yet been assigned. */ for( s = 'A'; s <= 'Z'; s++ ) { frms[ (int) s ] = 0; } /* Loop round all frames (excluding the current and base and IWC Frames which do not need version letters). If the Frame has an Ident attribute consisting of a single upper case letter, use it as its version letter unless that letter has already been given to an earlier frame. IWC Frames are not written out - identify them by giving them a "sid" value of 1 (an illegal FITS axis description character). */ for( ifrm = 1; ifrm <= nfrm; ifrm++ ){ sid[ ifrm ] = 0; if( ifrm != icurr && ifrm != ibase ) { frame = astGetFrame( fset, ifrm ); if( astChrMatchN( astGetDomain( frame ), "IWC", 3 ) ) { sid[ ifrm ] = 1; } else { id = astGetIdent( frame ); if( strlen( id ) == 1 && isupper( id[ 0 ] ) ) { if( frms[ (int) id[ 0 ] ] == 0 ) { frms[ (int) id[ 0 ] ] = ifrm; sid[ ifrm ] = id[ 0 ]; } } } (void) astAnnul( frame ); } } /* Now go round all the Frames again, looking for Frames which did not get a version letter assigned to it on the previous loop. Assign them letters now, selected them from the letters not already assigned (lowest to highest). */ s = 'A' - 1; for( ifrm = 1; ifrm <= nfrm; ifrm++ ){ if( ifrm != icurr && ifrm != ibase && sid[ ifrm ] != 1 ) { if( sid[ ifrm ] == 0 ){ while( frms[ (int) ++s ] != 0 ); if( s <= 'Z' ) { sid[ ifrm ] = s; frms[ (int) s ] = ifrm; } } } } /* If the primary headers describe offset coordinates, create an alternate axis description for the correspondsing absolute coordinate system. */ if( isoff && ++s <= 'Z' ) { (void) AddVersion( this, fset, ibase, icurr, ret, dim, s, encoding, -1, method, class, status ); } /* Now go through all the other Frames in the FrameSet, attempting to create alternate axis descriptions for each one. */ for( ifrm = 1; ifrm <= nfrm; ifrm++ ){ s0 = sid[ ifrm ]; if( s0 != 0 && s0 != 1 ) { /* Does it contain an offset sky frame? */ isoff = IsSkyOff( fset, ifrm, status ); /* Write out the Frame - offset if it is offset, absolute otherwise. */ (void) AddVersion( this, fset, ibase, ifrm, ret, dim, s0, encoding, isoff, method, class, status ); /* If the Frame is offset, create an extra alternate axis description for the correspondsing absolute coordinate system. */ if( isoff && ++s <= 'Z' ) { (void) AddVersion( this, fset, ibase, ifrm, ret, dim, s, encoding, -1, method, class, status ); } } } /* Free memory holding version letters */ sid = (char *) astFree( (void *) sid ); } /* If an error has occurred, or if the primary Frame could not be cerated, free the returned FitsStore, and return a null pointer. */ if( !astOK || !primok ) ret = FreeStore( ret, status ); } /* Return the answer. */ return ret; } static int GetClean( AstFitsChan *this, int *status ) { /* * Name: * GetClean * Purpose: * Return the value of the Clean attribute. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetClean( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns the value of the Clean attribute. Since this * attribute controls the behaviour of the FitsChan in the event of an * error condition, it is is necessary to ignore any inherited error * condition when getting the attribute value. This is why the * astMAKE_GET macro is not used. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The Clean value to use. */ /* Return if no FitsChan pointer was supplied. */ if ( !this ) return 0; /* Return the attribute value, supplying a default value of 0 (false). */ return ( this->clean == -1 ) ? 0 : (this->clean ? 1 : 0 ); } static int GetObjSize( AstObject *this_object, int *status ) { /* * Name: * GetObjSize * Purpose: * Return the in-memory size of an Object. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetObjSize( AstObject *this, int *status ) * Class Membership: * FitsChan member function (over-rides the astGetObjSize protected * method inherited from the parent class). * Description: * This function returns the in-memory size of the supplied FitsChan, * in bytes. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The Object size, in bytes. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to FitsChan structure */ FitsCard *card; /* Pointer to next FitsCard */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointers to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Invoke the GetObjSize method inherited from the parent class, and then add on any components of the class structure defined by thsi class which are stored in dynamically allocated memory. */ result = (*parent_getobjsize)( this_object, status ); result += astTSizeOf( this->warnings ); result += astGetObjSize( this->keyseq ); result += astGetObjSize( this->keywords ); result += astGetObjSize( this->tables ); card = (FitsCard *) ( this->head ); while( card ) { result += astTSizeOf( card ); result += card->size; result += astTSizeOf( card->comment ); card = GetLink( card, NEXT, "astGetObjSize", "FitsChan", status ); if( (void *) card == this->head ) break; } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static int GetCDMatrix( AstFitsChan *this, int *status ){ /* * Name: * GetCDMatrix * Purpose: * Get the value of the CDMatrix attribute. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetCDMatrix( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * If the CDMatrix attribute has been set, then its value is returned. * Otherwise, the supplied FitsChan is searched for keywords of the * form CDi_j. If any are found a non-zero value is returned. Otherwise * a zero value is returned. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The attribute value to use. * Notes: * - A value of zero is returned if an error has already occurred * or if an error occurs for any reason within this function. */ /* Local Variables... */ int ret; /* Returned value */ int icard; /* Index of current card on entry */ /* Check the global status. */ if( !astOK ) return 0; /* If a value has been supplied for the CDMatrix attribute, use it. */ if( astTestCDMatrix( this ) ) { ret = this->cdmatrix; /* Otherwise, check for the existence of CDi_j keywords... */ } else { /* Save the current card index, and rewind the FitsChan. */ icard = astGetCard( this ); astClearCard( this ); /* If the FitsChan contains any keywords with the format "CDi_j" then return 1. Otherwise return zero. */ ret = astKeyFields( this, "CD%1d_%1d", 0, NULL, NULL ) ? 1 : 0; /* Reinstate the original current card index. */ astSetCard( this, icard ); } /* Return the result. */ return astOK ? ret : 0; } static int GetEncoding( AstFitsChan *this, int *status ){ /* * Name: * GetEncoding * Purpose: * Get the value of the Encoding attribute. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetEncoding( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * If the Encoding attribute has been set, then its value is returned. * Otherwise, an attempt is made to determine the encoding scheme by * looking for selected keywords within the FitsChan. Checks are made * for the following keywords in the order specified, and the * corresponding encoding is adopted when the first one is found ( where * i, j and m are integers and s is a single upper case character): * * 1) Any keywords starting with "BEGAST" = Native encoding * 2) DELTAV and VELO-xxx (or VLSR) keywords = FITS-CLASS. * 3) Any AIPS spectral CTYPE values: * Any of CDi_j, PROJP, LONPOLE, LATPOLE = FITS-AIPS++ encoding: * None of the above = FITS-AIPS encoding. * 4) Any keywords matching PCiiijjj = FITS-PC encoding * 5) Any keywords matching CDiiijjj = FITS-IRAF encoding * 6) Any keywords matching CDi_j, AND at least one of RADECSYS, PROJPi * or CmVALi = FITS-IRAF encoding * 7) Any keywords RADECSYS, PROJPi or CmVALi, and no CDi_j or PCi_j * keywords, = FITS-PC encoding * 8) Any keywords matching CROTAi = FITS-AIPS encoding * 9) Keywords matching CRVALi = FITS-WCS encoding * 10) The PLTRAH keyword = DSS encoding * 11) If none of the above keywords are found, Native encoding is assumed. * * For cases 2) to 9), a check is also made that the header contains * at least one of each keyword CTYPE, CRPIX and CRVAL. If not, then * the checking process continues to the next case. This goes some way * towards ensuring that the critical keywords used to determine the * encoding are part of a genuine WCS description and have not just been * left in the header by accident. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The encoding scheme identifier. * Notes: * - The function returns UNKNOWN_ENCODING if an error has already occurred * or if an error occurs for any reason within this function. */ /* Local Variables... */ int hascd; /* Any CDi_j keywords found? */ int haspc; /* Any PCi_j keywords found? */ int haswcs; /* Any CRVAL, CTYPE and CRPIX found? */ int icard; /* Index of current card on entry */ int ret; /* Returned value */ /* Check the global status. */ if( !astOK ) return UNKNOWN_ENCODING; /* If a value has been supplied for the Encoding attribute, use it. */ if( astTestEncoding( this ) ) { ret = this->encoding; /* Otherwise, check for the existence of certain critcal keywords... */ } else { /* See if the header contains some CTYPE, CRPIX and CRVAL keywords. */ haswcs = astKeyFields( this, "CTYPE%d", 0, NULL, NULL ) && astKeyFields( this, "CRPIX%d", 0, NULL, NULL ) && astKeyFields( this, "CRVAL%d", 0, NULL, NULL ); /* See if there are any CDi_j keywords. */ hascd = astKeyFields( this, "CD%1d_%1d", 0, NULL, NULL ); /* See if there are any PCi_j keywords. */ haspc = astKeyFields( this, "PC%1d_%1d", 0, NULL, NULL ); /* Save the current card index, and rewind the FitsChan. */ icard = astGetCard( this ); astClearCard( this ); /* If the FitsChan contains any keywords starting with "BEGAST", then return "Native" encoding. */ if( astKeyFields( this, "BEGAST%2f", 0, NULL, NULL ) ){ ret = NATIVE_ENCODING; /* Otherwise, look for a FITS-CLASS signature... */ } else if( haswcs && LooksLikeClass( this, "astGetEncoding", "AstFitsChan", status ) ){ ret = FITSCLASS_ENCODING; /* Otherwise, if the FitsChan contains any CTYPE keywords which have the peculiar form used by AIPS, then use "FITS-AIPS" or "FITS-AIPS++" encoding. */ } else if( haswcs && HasAIPSSpecAxis( this, "astGetEncoding", "AstFitsChan", status ) ){ if( hascd || astKeyFields( this, "PROJP%d", 0, NULL, NULL ) || astKeyFields( this, "LONPOLE", 0, NULL, NULL ) || astKeyFields( this, "LATPOLE", 0, NULL, NULL ) ) { ret = FITSAIPSPP_ENCODING; } else { ret = FITSAIPS_ENCODING; } /* Otherwise, if the FitsChan contains any keywords with the format "PCiiijjj" then return "FITS-PC" encoding. */ } else if( haswcs && astKeyFields( this, "PC%3d%3d", 0, NULL, NULL ) ){ ret = FITSPC_ENCODING; /* Otherwise, if the FitsChan contains any keywords with the format "CDiiijjj" then return "FITS-IRAF" encoding. */ } else if( haswcs && astKeyFields( this, "CD%3d%3d", 0, NULL, NULL ) ){ ret = FITSIRAF_ENCODING; /* Otherwise, if the FitsChan contains any keywords with the format "CDi_j" AND there is a RADECSYS. PROJPi or CmVALi keyword, then return "FITS-IRAF" encoding. If "CDi_j" is present but none of the others are, return "FITS-WCS" encoding. */ } else if( haswcs && hascd ) { if( ( astKeyFields( this, "RADECSYS", 0, NULL, NULL ) && !astKeyFields( this, "RADESYS", 0, NULL, NULL ) ) || ( astKeyFields( this, "PROJP%d", 0, NULL, NULL ) && !astKeyFields( this, "PV%d_%d", 0, NULL, NULL ) ) || ( astKeyFields( this, "C%1dVAL%d", 0, NULL, NULL )) ){ ret = FITSIRAF_ENCODING; } else { ret = FITSWCS_ENCODING; } /* Otherwise, if the FitsChan contains any keywords with the format RADECSYS. PROJPi or CmVALi keyword, then return "FITS-PC" encoding, so long as there are no FITS-WCS equivalent keywords. */ } else if( haswcs && !haspc && !hascd && ( ( astKeyFields( this, "RADECSYS", 0, NULL, NULL ) && !astKeyFields( this, "RADESYS", 0, NULL, NULL ) ) || ( astKeyFields( this, "PROJP%d", 0, NULL, NULL ) && !astKeyFields( this, "PV%d_%d", 0, NULL, NULL ) ) || astKeyFields( this, "C%1dVAL%d", 0, NULL, NULL ) ) ) { ret = FITSPC_ENCODING; /* Otherwise, if the FitsChan contains any keywords with the format "CROTAi" then return "FITS-AIPS" encoding. */ } else if( haswcs && astKeyFields( this, "CROTA%d", 0, NULL, NULL ) ){ ret = FITSAIPS_ENCODING; /* Otherwise, if the FitsChan contains any keywords with the format "CRVALi" then return "FITS-WCS" encoding. */ } else if( haswcs && astKeyFields( this, "CRVAL%d", 0, NULL, NULL ) ){ ret = FITSWCS_ENCODING; /* Otherwise, if the FitsChan contains the "PLTRAH" keywords, use "DSS" encoding. */ } else if( astKeyFields( this, "PLTRAH", 0, NULL, NULL ) ){ ret = DSS_ENCODING; /* If none of these conditions is met, assume Native encoding. */ } else { ret = NATIVE_ENCODING; } /* Reinstate the original current card index. */ astSetCard( this, icard ); } /* Return the encoding scheme. */ return astOK ? ret : UNKNOWN_ENCODING; } static void GetFiducialNSC( AstWcsMap *map, double *phi, double *theta, int *status ){ /* * Name: * GetFiducialNSC * Purpose: * Return the Native Spherical Coordinates at the fiducial point of a * WcsMap projection. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void GetFiducialNSC( AstWcsMap *map, double *phi, double *theta, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns the native spherical coords corresponding at * the fiducial point of a WcsMap. * * The values of parameters 1 and 2 on the longitude axis of the WcsMap * are usually used as the native spherical coordinates of the * fiducial point. The default values for these parameters are equal * to the native spherical coordinates of the projection reference point. * The exception is that a TPN projection always uses the default * values, since the projection parameters are used to store polynomial * coefficients. * Parameters: * map * Pointer to the WcsMap. * phi * Address of a location at which to return the native spherical * longitude at the fiducial point (radians). * theta * Address of a location at which to return the native spherical * latitude at the fiducial point (radians). * status * Pointer to the inherited status variable. */ /* Local Variables: */ int axlon; /* Index of longitude axis */ /* Initialise */ *phi = AST__BAD; *theta = AST__BAD; /* Check the inherited status. */ if( !astOK ) return; /* If this is not a TPN projection get he value of the required projection parameters (the default values for these are equal to the fixed native shperical coordinates at the projection reference point). */ if( astGetWcsType( map ) != AST__TPN ) { axlon = astGetWcsAxis( map, 0 ); if( astGetPV( map, axlon, 0 ) != 0.0 ) { *phi = AST__DD2R*astGetPV( map, axlon, 1 ); *theta = AST__DD2R*astGetPV( map, axlon, 2 ); } else { *phi = astGetNatLon( map ); *theta = astGetNatLat( map ); } /* If this is a TPN projection, the returned values are always the fixed native shperical coordinates at the projection reference point). */ } else { *phi = astGetNatLon( map ); *theta = astGetNatLat( map ); } } static void GetFiducialPPC( AstWcsMap *map, double *x0, double *y0, int *status ){ /* * Name: * GetFiducialPPC * Purpose: * Return the IWC at the fiducial point of a WcsMap projection. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void GetFiducialPPC( AstWcsMap *map, double *x0, double *y0, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns the projection plane coords corresponding to * the native spherical coords of the fiducial point of a FITS-WCS * header. Note, projection plane coordinates (PPC) are equal to * Intermediate World Coordinates (IWC) except for cases where the * fiducial point does not correspond to the projection reference point. * In these cases, IWC and PPC will be connected by a translation * which ensures that the fiducial point corresponds to the origin of * IWC. * * The values of parameters 1 and 2 on the longitude axis of * the WcsMap are used as the native spherical coordinates of the * fiducial point. The default values for these parameters are equal * to the native spherical coordinates of the projection reference point. * Parameters: * map * Pointer to the WcsMap. * x0 * Address of a location at which to return the PPC X axis value at * the fiducial point (radians). * y0 * Address of a location at which to return the PPC Y axis value at * the fiducial point (radians). * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPointSet *pset1; /* Pointer to the native spherical PointSet */ AstPointSet *pset2; /* Pointer to the intermediate world PointSet */ double **ptr1; /* Pointer to pset1 data */ double **ptr2; /* Pointer to pset2 data */ int axlat; /* Index of latitude axis */ int axlon; /* Index of longitude axis */ int i; /* Loop count */ int naxes; /* Number of axes */ /* Initialise */ *x0 = AST__BAD; *y0 = AST__BAD; /* Check the inherited status. */ if( !astOK ) return; /* Save number of axes in the WcsMap. */ naxes = astGetNin( map ); /* Allocate resources. */ pset1 = astPointSet( 1, naxes, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( 1, naxes, "", status ); ptr2 = astGetPoints( pset2 ); /* Check pointers can be used safely. */ if( astOK ) { /* Get the indices of the longitude and latitude axes in WcsMap. */ axlon = astGetWcsAxis( map, 0 ); axlat = astGetWcsAxis( map, 1 ); /* Use zero on all non-celestial axes. */ for( i = 0; i < naxes; i++ ) ptr1[ i ][ 0 ] = 0.0; /* Get the native spherical coords at the fiducial point. */ GetFiducialNSC( map, ptr1[ axlon ], ptr1[ axlat ], status ); /* Use the inverse WcsMap to convert the native longitude and latitude of the fiducial point into PPC (x,y). */ (void) astTransform( map, pset1, 0, pset2 ); /* Return the calculated PPC coords. */ *x0 = ptr2[ axlon ][ 0 ]; *y0 = ptr2[ axlat ][ 0 ]; } /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); } static int GetFiducialWCS( AstWcsMap *wcsmap, AstMapping *map2, int colon, int colat, double *fidlon, double *fidlat, int *status ){ /* * Name: * GetFiducialWCS * Purpose: * Decide on the celestial coordinates of the fiducial point. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetFiducialWCS( AstWcsMap wcsmap, AstMapping map2, int colon, * int colat, double *fidlon, double *fidlat, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns the celestial longitude and latitude values * to use for the fiducial point. These are the values stored in FITS * keywords CRVALi. * Parameters: * wcsmap * The WcsMap which converts Projection Plane Coordinates into * native spherical coordinates. The number of outputs from this * Mapping should match the number of inputs to "map2". * map2 * The Mapping which converts native spherical coordinates into WCS * coordinates. * colon * The index of the celestial longitude output from "map2". * colat * The index of the celestial latitude output from "map2". * fidlon * Pointer to a location at which to return the celestial longitude * value at the fiducial point. The value is returned in radians. * fidlat * Pointer to a location at which to return the celestial latitude * value at the fiducial point. The value is returned in radians. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the fiducial point longitude or latitude could not be * determined. One otherwise. */ /* Local Variables: */ AstPointSet *pset1; /* Pointer to the native spherical PointSet */ AstPointSet *pset2; /* Pointer to the WCS PointSet */ double **ptr1; /* Pointer to pset1 data */ double **ptr2; /* Pointer to pset2 data */ int axlat; /* Index of latitude axis */ int axlon; /* Index of longitude axis */ int iax; /* Axis index */ int naxin; /* Number of IWC axes */ int naxout; /* Number of WCS axes */ int ret; /* The returned FrameSet */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Allocate resources. */ naxin = astGetNin( map2 ); naxout = astGetNout( map2 ); pset1 = astPointSet( 1, naxin, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( 1, naxout, "", status ); ptr2 = astGetPoints( pset2 ); if( astOK ) { /* Get the indices of the latitude and longitude outputs in the WcsMap. These are not necessarily the same as "colat" and "colon" because "map2" may contain a PermMap. */ axlon = astGetWcsAxis( wcsmap, 0 ); axlat = astGetWcsAxis( wcsmap, 1 ); /* Use zero on all non-celestial axes. */ for( iax = 0; iax < naxin; iax++ ) ptr1[ iax ][ 0 ] = 0.0; /* Get the native spherical coords at the fiducial point. */ GetFiducialNSC( wcsmap, ptr1[ axlon ], ptr1[ axlat ], status ); /* The fiducial point in the celestial coordinate system is found by transforming the fiducial point in native spherical co-ordinates into absolute physical coordinates using map2. */ (void) astTransform( map2, pset1, 1, pset2 ); /* Store the returned WCS values. */ *fidlon = ptr2[ colon ][ 0 ]; *fidlat = ptr2[ colat ][ 0 ]; /* Indicate if we have been succesfull. */ if( astOK && *fidlon != AST__BAD && *fidlat != AST__BAD ) ret = 1; } /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Return the result. */ return ret; } static const char *GetFitsSor( const char *string, int *status ) { /* * Name: * GetFitsSor * Purpose: * Get the string used to represent an AST spectral standard of rest. * Type: * Private function. * Synopsis: * #include "fitschan.h" * const char *GetFitsSor( const char *string, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a pointer to a static string which is the * FITS equivalent to a given SpecFrame StdOfRest value. * Parameters: * string * Pointer to a constant null-terminated string containing the * SpecFrame StdOfRest value. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a static null-terminated string containing the FITS * equivalent to the supplied string. NULL is returned if the supplied * string has no FITS equivalent. * Notes: * - A NULL pointer value will be returned if this function is * invoked wth the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ const char *result; /* Pointer value to return */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Compare the supplied string with SpecFrame value for which there is a known FITS equivalent. */ if( !strcmp( string, "Topocentric" ) ){ result = "TOPOCENT"; } else if( !strcmp( string, "Geocentric" )){ result = "GEOCENTR"; } else if( !strcmp( string, "Barycentric" )){ result = "BARYCENT"; } else if( !strcmp( string, "Heliocentric" )){ result = "HELIOCEN"; } else if( !strcmp( string, "LSRK" )){ result = "LSRK"; } else if( !strcmp( string, "LSRD" )){ result = "LSRD"; } else if( !strcmp( string, "Galactic" )){ result = "GALACTOC"; } else if( !strcmp( string, "Local_group" )){ result = "LOCALGRP"; } else if( !strcmp( string, "Source" )){ result = "SOURCE"; } else { result = NULL; } /* Return the answer. */ return result; } static double GetItem( double ****item, int i, int jm, char s, char *name, const char *method, const char *class, int *status ){ /* * Name: * GetItem * Purpose: * Retrieve a value for a axis keyword value from a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double GetItem( double ****item, int i, int jm, char s, char *name, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The requested keyword value is retrieved from the specified array, * at a position indicated by the axis and co-ordinate version. * AST__BAD is returned if the array does not contain the requested * value. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crval) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (j) or projection parameter (m). * i * The zero based intermediate axis index in the range 0 to 98. Set * this to zero for keywords (e.g. CRPIX) which are not indexed by * intermediate axis number. * jm * The zero based pixel axis index (in the range 0 to 98) or parameter * index (in the range 0 to WCSLIB_MXPAR-1). Set this to zero for * keywords (e.g. CRVAL) which are not indexed by either pixel axis or * parameter number. * s * The co-ordinate version character (A to Z, or space), case * insensitive * name * A string holding a name for the item of information. A NULL * pointer may be supplied, in which case it is ignored. If a * non-NULL pointer is supplied, an error is reported if the item * of information has not been stored, and the supplied name is * used to identify the information within the error message. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The required keyword value, or AST__BAD if no value has previously * been stored for the keyword (or if an error has occurred). */ /* Local Variables: */ double ret; /* Returned keyword value */ int si; /* Integer co-ordinate version index */ /* Initialise */ ret = AST__BAD; /* Check the inherited status. */ if( !astOK ) return ret; /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "GetItem(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); /* Check the intermediate axis index is within range. */ } else if( i < 0 || i > 98 ) { astError( AST__INTER, "GetItem(fitschan): AST internal error; " "intermediate axis index %d is invalid.", status, i ); /* Check the pixel axis or parameter index is within range. */ } else if( jm < 0 || jm > 99 ) { astError( AST__INTER, "GetItem(fitschan): AST internal error; " "pixel axis or parameter index %d is invalid.", status, jm ); /* Otherwise, if the array holding the required keyword is not null, proceed... */ } else if( *item ){ /* Find the number of coordinate versions in the supplied array. Only proceed if it encompasses the requested co-ordinate version. */ if( astSizeOf( (void *) *item )/sizeof(double **) > si ){ /* Find the number of intermediate axes in the supplied array. Only proceed if it encompasses the requested intermediate axis. */ if( astSizeOf( (void *) (*item)[si] )/sizeof(double *) > i ){ /* Find the number of pixel axes or parameters in the supplied array. Only proceed if it encompasses the requested index. */ if( astSizeOf( (void *) (*item)[si][i] )/sizeof(double) > jm ){ /* Return the required keyword value. */ ret = (*item)[si][i][jm]; } } } } /* If required, report an error if the requested item of information has not been stored. */ if( ret == AST__BAD && name && astOK ){ astError( AST__NOFTS, "%s(%s): No value can be found for %s.", status, method, class, name ); } return ret; } static int GetMaxJM( double ****item, char s, int *status ){ /* * Name: * GetMaxJM * Purpose: * Return the largest pixel axis or parameter index stored for an * numerical axis keyword value in a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetMaxJM( double ****item, char s, int *status) * Class Membership: * FitsChan member function. * Description: * The number of pixel axis numbers or projection parameters stored for * a specified axis keyword is found and returned. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crpix) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (j) or projection parameter (m). * s * The co-ordinate version character (A to Z, or space), case * insensitive * status * Pointer to the inherited status variable. * Returned Value: * The maximum pixel axis number or projection parameter index (zero * based). */ /* Local Variables: */ int jm; /* Number of parameters/pixel axes */ int i; /* Intermediate axis index */ int ret; /* Returned axis index */ int si; /* Integer co-ordinate version index */ /* Initialise */ ret = -1; /* Check the inherited status. */ if( !astOK ) return ret; /* If the array holding the required keyword is not null, proceed... */ if( *item ){ /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "GetMaxJM(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); return ret; } /* Find the number of coordinate versions in the supplied array. Only proceed if it encompasses the requested co-ordinate version. */ if( astSizeOf( (void *) *item )/sizeof(double **) > si ){ /* Check that the pointer to the array of intermediate axis values is not null. */ if( (*item)[si] ){ /* Loop round each used element in this array. */ for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(double *); i++ ){ if( (*item)[si][i] ){ /* Get the size of the pixel axis/projection parameter array for the current intermediate axis, and subtract 1 to get the largest index. */ jm = astSizeOf( (void *) (*item)[si][i] )/sizeof(double) - 1; /* Ignore any trailing unused (AST__BAD) values. */ while( jm >= 0 && (*item)[si][i][jm] == AST__BAD ) jm--; /* Update the returned value if the current value is larger. */ if( jm > ret ) ret = jm; } } } } } return ret; } static int GetMaxJMC( char *****item, char s, int *status ){ /* * Name: * GetMaxJMC * Purpose: * Return the largest pixel axis or parameter index stored for an * character-valued axis keyword value in a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetMaxJMC( char *****item, char s, int *status) * Class Membership: * FitsChan member function. * Description: * The number of pixel axis numbers or projection parameters stored for * a specified axis keyword is found and returned. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->ctype) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword string pointers. These arrays of keyword * string pointers have one element for every pixel axis (j) or * projection parameter (m). * s * The co-ordinate version character (A to Z, or space), case * insensitive * status * Pointer to the inherited status variable. * Returned Value: * The maximum pixel axis number or projection parameter index (zero * based). */ /* Local Variables: */ int jm; /* Number of parameters/pixel axes */ int i; /* Intermediate axis index */ int ret; /* Returned axis index */ int si; /* Integer co-ordinate version index */ /* Initialise */ ret = -1; /* Check the inherited status. */ if( !astOK ) return ret; /* If the array holding the required keyword is not null, proceed... */ if( *item ){ /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "GetMaxJMC(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); return ret; } /* Find the number of coordinate versions in the supplied array. Only proceed if it encompasses the requested co-ordinate version. */ if( astSizeOf( (void *) *item )/sizeof(char ***) > si ){ /* Check that the pointer to the array of intermediate axis values is not null. */ if( (*item)[si] ){ /* Loop round each used element in this array. */ for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(char **); i++ ){ if( (*item)[si][i] ){ /* Get the size of the pixel axis/projection parameter array for the current intermediate axis, and subtract 1 to get the largest index. */ jm = astSizeOf( (void *) (*item)[si][i] )/sizeof(char *) - 1; /* Ignore any trailing unused (NULL) values. */ while( jm >= 0 && (*item)[si][i][jm] == NULL ) jm--; /* Update the returned value if the current value is larger. */ if( jm > ret ) ret = jm; } } } } } return ret; } static int GetMaxI( double ****item, char s, int *status ){ /* * Name: * GetMaxI * Purpose: * Return the largest WCS axis index stored for an axis keyword value in * a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetMaxJM( double ****item, char s) * Class Membership: * FitsChan member function. * Description: * The number of Wcs axis numbers stored for a specified axis keyword is * found and returned. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crval) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (j) or projection parameter (m). * s * The co-ordinate version character (A to Z, or space), case * insensitive * Returned Value: * The maximum WCS axis index (zero based). */ /* Local Variables: */ int ret; /* Returned axis index */ int si; /* Integer co-ordinate version index */ /* Initialise */ ret = -1; /* Check the inherited status. */ if( !astOK ) return ret; /* If the array holding the required keyword is not null, proceed... */ if( *item ){ /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "GetMaxI(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); return ret; } /* Find the number of coordinate versions in the supplied array. Only proceed if it encompasses the requested co-ordinate version. */ if( astSizeOf( (void *) *item )/sizeof(double **) > si ){ /* Check that the pointer to the array of intermediate axis values is not null. */ if( (*item)[si] ){ /* Get the size of the intermediate axis array and subtract 1 to get the largest index. */ ret = astSizeOf( (void *) (*item)[si] )/sizeof(double *) - 1; /* Ignore any trailing unused (NULL) values. */ while( ret >= 0 && (*item)[si][ret] == NULL ) ret--; } } } return ret; } static char GetMaxS( double ****item, int *status ){ /* * Name: * GetMaxS * Purpose: * Return the largest (i.e. closest to Z) coordinate version character * stored for a axis keyword value in a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char GetMaxS( double ****item, int *status) * Class Membership: * FitsChan member function. * Description: * The largest (i.e. closest to Z) coordinate version character * stored for a axis keyword value in a FitStore structure is found * and returned. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crval) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (j) or projection parameter (m). * status * Pointer to the inherited status variable. * Returned Value: * The highest coordinate version character. */ /* Local Variables: */ char ret; /* Returned axis index */ int si; /* Integer index into alphabet */ /* Initialise */ ret = ' '; /* Check the inherited status. */ if( !astOK ) return ret; /* If the array holding the required keyword is not null, proceed... */ if( *item ){ /* Find the length of this array, and subtract 1 to get the largest index in the array. */ si = astSizeOf( (void *) *item )/sizeof(double **) - 1; /* Ignore any trailing null (i.e. unused) values. */ while( si >= 0 && !(*item)[si] ) si--; /* Store the corresponding character */ if( si == 0 ) { ret = ' '; } else { ret = 'A' + si - 1; } } return ret; } static char *GetItemC( char *****item, int i, int jm, char s, char *name, const char *method, const char *class, int *status ){ /* * Name: * GetItemC * Purpose: * Retrieve a string value for a axis keyword value from a FitStore * structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *GetItemC( char *****item, int i, int jm, char s, char *name, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The requested keyword string value is retrieved from the specified * array, at a position indicated by the axis and co-ordinate version. * NULL is returned if the array does not contain the requested * value. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->ctype) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword string pointers. These arrays of keyword * string pointers have one element for every pixel axis (j) or * projection parameter (m). * i * The zero based intermediate axis index in the range 0 to 98. Set * this to zero for keywords (e.g. CRPIX) which are not indexed by * intermediate axis number. * jm * The zero based pixel axis index (in the range 0 to 98) or parameter * index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for * keywords (e.g. CTYPE) which are not indexed by either pixel axis or * parameter number. * s * The co-ordinate version character (A to Z, or space), case * insensitive * name * A string holding a name for the item of information. A NULL * pointer may be supplied, in which case it is ignored. If a * non-NULL pointer is supplied, an error is reported if the item * of information has not been stored, and the supplied name is * used to identify the information within the error message. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the required keyword string value, or NULL if no value * has previously been stored for the keyword (or if an error has * occurred). */ /* Local Variables: */ char *ret; /* Returned keyword value */ int si; /* Integer co-ordinate version index */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "GetItemC(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); /* Check the intermediate axis index is within range. */ } else if( i < 0 || i > 98 ) { astError( AST__INTER, "GetItemC(fitschan): AST internal error; " "intermediate axis index %d is invalid.", status, i ); /* Check the pixel axis or parameter index is within range. */ } else if( jm < 0 || jm > 99 ) { astError( AST__INTER, "GetItem(fitschan): AST internal error; " "pixel axis or parameter index %d is invalid.", status, jm ); /* Otherwise, if the array holding the required keyword is not null, proceed... */ } else if( *item ){ /* Find the number of coordinate versions in the supplied array. Only proceed if it encompasses the requested co-ordinate version. */ if( astSizeOf( (void *) *item )/sizeof(char ***) > si ){ /* Find the number of intermediate axes in the supplied array. Only proceed if it encompasses the requested intermediate axis. */ if( astSizeOf( (void *) (*item)[si] )/sizeof(char **) > i ){ /* Find the number of pixel axes or parameters in the supplied array. Only proceed if it encompasses the requested index. */ if( astSizeOf( (void *) (*item)[si][i] )/sizeof(char *) > jm ){ /* Return the required keyword value. */ ret = (*item)[si][i][jm]; } } } } /* If required, report an error if the requested item of information has not been stored. */ if( !ret && name && astOK ){ astError( AST__NOFTS, "%s(%s): No value can be found for %s.", status, method, class, name ); } return ret; } static AstFitsTable *GetNamedTable( AstFitsChan *this, const char *extname, int extver, int extlevel, int report, const char *method, int *status ){ /* * Name: * GetNamedTable * Purpose: * Return a FitsTable holding the contents of a named FITS binary table. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstFitsTable *GetNamedTable( AstFitsChan *this, const char *extname, * int extver, int extlevel, int report, * const char *method, int *status ) * Class Membership: * FitsChan member function. * Description: * If a table source function has been registered with FitsChan (using * astTableSource), invoke it to read the required table from the external * FITS file. If the extension is available in the FITS file, this will * put a FitsTable into the "tables" KeyMap in the FitsChan structure, * using the FITS extension name as the key - this will replace any * FitsTable already present in the KeyMap with the same key. Finally, * return a pointer to the FitsTable stored in the KeyMap - if any. * * This strategy allows the astPutTables or astPutTable method to be used * as an alternative to registering a table source function with the * FitsChan. Note, any table read using the source function is used * in preference to any table stored in the FitsChan by an earlier call * to astPutTables/astPutTable. * Parameters: * this * Pointer to the FitsChan. * extname * The key associated with the required table - should be the name * of the FITS extension containing the binary table. * extver * The FITS "EXTVER" value for the required table. * extlevel * The FITS "EXTLEVEL" value for the required table. * report * If non-zero, report an error if the named table is not available. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the FitsTable, or NULL if the table is not avalable. */ /* Local Variables: */ AstFitsTable *ret; /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Fitrst attempt to read the required table from the external FITS file. Only proceed if table source function and wrapper have been supplied using astTableSource. */ if( this->tabsource && this->tabsource_wrap ){ /* Invoke the table source function asking it to place the required FITS table in the FitsChan. This is an externally supplied function which may not be thread-safe, so lock a mutex first. Note, a cloned FitsChan pointer is sent to the table source function since the table source function will annul the supplied FitsChan pointer. Also store the channel data pointer in a global variable so that it can be accessed in the source function using macro astChannelData. */ astStoreChannelData( this ); LOCK_MUTEX2; ( *this->tabsource_wrap )( this->tabsource, astClone( this ), extname, extver, extlevel, status ); UNLOCK_MUTEX2; } /* Now get a pointer to the required FitsTable, stored as an entry in the "tables" KeyMap. Report an error if required. */ if( ! (this->tables) || !astMapGet0A( this->tables, extname, &ret ) ){ if( report && astOK ) { astError( AST__NOTAB, "%s(%s): Failed to read FITS binary table " "from extension '%s' (extver=%d, extlevel=%d).", status, method, astGetClass( this ), extname, extver, extlevel ); } } /* Return the result. */ return ret; } static AstKeyMap *GetTables( AstFitsChan *this, int *status ) { /* *++ * Name: c astGetTables f AST_GETTABLES * Purpose: * Retrieve any FitsTables currently in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c AstKeyMap *astGetTables( AstFitsChan *this ) f RESULT = AST_GETTABLES( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: * If the supplied FitsChan currently contains any tables, then this * function returns a pointer to a KeyMap. Each entry in the KeyMap * is a pointer to a FitsTable holding the data for a FITS binary * table. The key used to access each entry is the FITS extension * name in which the table should be stored. * * Tables can be present in a FitsChan as a result either of using the c astPutTable (or astPutTables) f AST_PUTTABLE (or AST_PUTTABLES) * method to store existing tables in the FitsChan, or of using the c astWrite f AST_WRITE * method to write a FrameSet to the FitsChan. For the later case, if * the FitsChan "TabOK" attribute is positive and the FrameSet requires * a look-up table to describe one or more axes, then the "-TAB" * algorithm code described in FITS-WCS paper III is used and the table * values are stored in the FitsChan in the form of a FitsTable object * (see the documentation for the "TabOK" attribute). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetTables() f AST_GETTABLES = INTEGER * A pointer to a deep copy of the KeyMap holding the tables currently * in the FitsChan, or c NULL f AST__NULL * if the FitsChan does not contain any tables. The returned * pointer should be annulled using c astAnnul f AST_ANNUL * when no longer needed. * Notes: * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. *-- */ /* Local Variables: */ AstKeyMap *result; /* Pointer value to return */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* If the FitsChan contains any tables, return a pointer to a copy of the KeyMap containing them. Otherwise, return a NULL pointer. */ if( this->tables && astMapSize( this->tables ) > 0 ) { result = astCopy( this->tables ); } /* Return the result. */ return result; } static int GetUsedPolyTan( AstFitsChan *this, AstFitsChan *out, int latax, int lonax, char s, const char *method, const char *class, int *status ){ /* * Name: * GetUsedPolyTan * Purpose: * Get the value to use for the PolyTan attribute. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetUsedPolyTan( AstFitsChan *this, AstFitsChan *out, int latax, * int lonax, char s, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * If the PolyTan attribute is zero or positive, then its value is * returned. If it is negative, the supplied FitsChan is searched for * keywords of the form PVi_m. If any are found on the latitude axis, * or if any are found on the longitude axis with "m" > 4, +1 is * returned (meaning "use the distorted TAN conventio"). Otherwise 0 * is returned (meaning "use the standard TAN convention"). * * If all the PVi_m values for m > 0 on either axis are zero, a warning is * issued and zero is returned. * Parameters: * this * Pointer to the FitsChan. * out * Pointer to a secondary FitsChan. If the PV values in "this" are * found to be unusable, they will be marked as used in both "this" * and "out". * latax * The one-based index of the latitude axis within the FITS header. * lonax * The one-based index of the longitude axis within the FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * The attribute value to use. * Notes: * - A value of zero is returned if an error has already occurred * or if an error occurs for any reason within this function. */ /* Local Variables... */ char template[ 20 ]; double pval; int lbnd_lat; int lbnd_lon; int m; int nfound1; int nfound2; int ok; int ret; int ubnd_lat; int ubnd_lon; /* Check the global status. */ if( !astOK ) return 0; /* Get the value of the PolyTan attribute. */ ret = astGetPolyTan( this ); /* If it is negative, we examine the FitsChan to see which convention to use. */ if( ret < 0 ) { ret = 0; /* Search the FitsChan for latitude PV cards. */ if( s != ' ' ) { sprintf( template, "PV%d_%%d%c", latax, s ); } else { sprintf( template, "PV%d_%%d", latax ); } nfound1 = astKeyFields( this, template, 1, &ubnd_lat, &lbnd_lat ); /* Search the FitsChan for longitude PV cards. */ if( s != ' ' ) { sprintf( template, "PV%d_%%d%c", lonax, s ); } else { sprintf( template, "PV%d_%%d", lonax ); } nfound2 = astKeyFields( this, template, 1, &ubnd_lon, &lbnd_lon ); /* If any were found with "m" value greater than 4, assume the distorted TAN convention is in use. Otherwise assume the stdanrd TAN convention is in use. */ if( nfound1 || ( nfound2 && ubnd_lon > 4 ) ) ret = 1; /* If the distorted TAN convention is to be used, check that at least one of the PVi_m values is non-zero on each axis. We ignore the PVi_0 (constant) terms in this check. */ if( ret > 0 ) { /* Do the latitude axis first, skipping the first (constant) term. Assume that all latitude pV values are zero until we find one that is not. */ ok = 0; for( m = 1; m <= ubnd_lat && !ok; m++ ) { /* Form the PVi_m keyword name. */ if( s != ' ' ) { sprintf( template, "PV%d_%d%c", latax, m, s ); } else { sprintf( template, "PV%d_%d", latax, m ); } /* Get it's value. */ if( ! GetValue( this, template, AST__FLOAT, &pval, 0, 0, method, class, status ) ) { /* If the PVi_m header is not present in the FitsChan, use a default value. */ pval = ( m == 1 ) ? 1.0 : 0.0; } /* If the PVi_m header has a non-zero value, we can leave the loop. */ if( pval != 0.0 ) ok = 1; } /* If all the latitude PVi_m values are zero, issue a warning and return zero, indicating that a simple undistorted TAN projection should be used. */ if( !ok ) { Warn( this, "badpv", "This FITS header describes a distorted TAN " "projection, but all the distortion coefficients (the " "PVi_m headers) on the latitude axis are zero.", method, class, status ); ret = 0; /* Also, delete the PV keywords so that no attempt is made to use them. */ for( m = 1; m <= ubnd_lat; m++ ) { if( s != ' ' ) { sprintf( template, "PV%d_%d%c", latax, m, s ); } else { sprintf( template, "PV%d_%d", latax, m ); } astClearCard( this ); if( FindKeyCard( this, template, method, class, status ) ) { DeleteCard( this, method, class, status ); } } /* Otherwise, do the same check for the longitude axis. */ } else { ok = 0; for( m = 1; m <= ubnd_lon && !ok; m++ ) { if( s != ' ' ) { sprintf( template, "PV%d_%d%c", lonax, m, s ); } else { sprintf( template, "PV%d_%d", lonax, m ); } if( ! GetValue( this, template, AST__FLOAT, &pval, 0, 0, method, class, status ) ) { pval = ( m == 1 ) ? 1.0 : 0.0; } if( pval != 0.0 ) ok = 1; } if( !ok ) { Warn( this, "badpv", "This FITS header describes a distorted TAN " "projection, but all the distortion coefficients (the " "PVi_m headers) on the longitude axis are zero.", method, class, status ); ret = 0; for( m = 1; m <= ubnd_lon; m++ ) { if( s != ' ' ) { sprintf( template, "PV%d_%d%c", lonax, m, s ); } else { sprintf( template, "PV%d_%d", lonax, m ); } astClearCard( this ); if( FindKeyCard( this, template, method, class, status ) ) { DeleteCard( this, method, class, status ); } } } } } } /* Return the result. */ return astOK ? ret : 0; } static int GoodWarns( const char *value, int *status ){ /* * Name: * GoodWarns * Purpose: * Checks a string to ensure it is a legal list of warning conditions. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GoodWarns( const char *value, int *status ) * Class Membership: * FitsChan member function. * Description: * This function checks the supplied string to ensure it contains a space * separated list of zero or more recognised warning conditions. An * error is reported if it does not. * Parameters: * value * The string to check. * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the supplied string is not a legal list of * conditions, or if an error has already occurred. One is returned * otherwise. */ /* Local Variables: */ char *b; /* Pointer to next buffer element */ const char *c ; /* Pointer to next character */ char buf[100]; /* Buffer for condition name */ int inword; /* Are we in a word? */ int n; /* Number of conditions supplied */ int ret; /* Returned value */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Report an error and return if the pointer is null. */ if( !value ){ astError( AST__ATTIN, "astSetWarnings(fitschan): Null pointer " "supplied for the Warnings attribute." , status); return ret; } /* Initialise things */ inword = 0; buf[ 0 ] = ' '; b = buf + 1; n = 0; ret = 1; /* Loop round each character in the supplied string. */ for( c = value ; c < value + strlen( value ) + 1; c++ ){ /* Have we found the first space or null following a word? */ if( ( !(*c) || isspace( *c ) ) && inword ){ /* Add a space to the end of the buffer and terminate it. */ *(b++) = ' '; *b = 0; /* Check the word is legal by searching for it in the string of all conditions, which should be lower case and have spaces at start and end. The word in the buffer is delimited by spaces and so it will not match a substring within a condition. If it is legal increment the number of conditions found. */ if( strstr( ALLWARNINGS, buf ) ){ n++; /* Otherwise, report an error and break. */ } else { ret = 0; *(--b) = 0; astError( AST__ATTIN, "astSetWarnings(fitschan): Unknown " "condition '%s' specified when setting the Warnings " "attribute.", status, buf + 1 ); break; } /* Reset the pointer to the next character in the buffer, retaining the initial space in the buffer. */ b = buf + 1; /* Indicate we are no longer in a word. */ inword = 0; /* Have we found the first non-space, non-null character following a space? */ } else if( *c && !isspace( *c ) && !inword ){ /* Note we are now in a word. */ inword = 1; } /* If we are in a word, copy the lowercase character to the buffer. */ if( inword ) *(b++) = tolower( *c ); } return ret; } static AstMapping *GrismSpecWcs( char *algcode, FitsStore *store, int i, char s, AstSpecFrame *specfrm, const char *method, const char *class, int *status ) { /* * Name: * GrismSpecWcs * Purpose: * Create a Mapping describing a FITS-WCS grism-dispersion algorithm * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *GrismSpecWcs( char *algcode, FitsStore *store, int i, char s, * AstSpecFrame *specfrm, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function uses the contents of the supplied FitsStore to create * a Mapping which goes from Intermediate World Coordinate (known as "w" * in the context of FITS-WCS paper III) to the spectral system * described by the supplied SpecFrame. * * The returned Mapping implements the grism "GRA" and "GRI" algorithms * described in FITS-WCS paper III. * Parameters: * algcode * Pointer to a string holding the code for the required algorithm * ("-GRA" or "-GRI"). * store * Pointer to the FitsStore structure holding the values to use for * the WCS keywords. * i * The zero-based index of the spectral axis within the FITS header * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * specfrm * Pointer to the SpecFrame. This specifies the "S" system - the * system in which the CRVAL kewyords (etc) are specified. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a Mapping, or NULL if an error occurs. */ /* Local Variables: */ AstFrameSet *fs; AstMapping *gmap; AstMapping *map1; AstMapping *map2; AstMapping *map2a; AstMapping *map2b; AstMapping *ret; AstMapping *smap; AstSpecFrame *wfrm; double crv; double dg; double gcrv; double pv; double wcrv; /* Check the global status. */ ret = NULL; if( !astOK ) return ret; /* The returned Mapping will be a CmpMap including a GrismMap. This GrismMap will produced wavelength as output. We also need the Mapping from wavelength to the system represented by the supplied SpecFrame. To get this, we first create a copy of the supplied SpecFrame (in order to inherit the standard of rest, epoch, etc), and set its System to wavlength in vacuum (for "-GRI") or air (for "-GRA"), and then use astConvert to get the Mapping from the SpecFrame system to relevant form of wavelength. */ wfrm = astCopy( specfrm ); astSetSystem( wfrm, strcmp( algcode, "-GRI" )?AST__AIRWAVE:AST__WAVELEN ); astSetUnit( wfrm, 0, "m" ); fs = astConvert( specfrm, wfrm, "" ); if( fs ) { smap = astGetMapping( fs, AST__BASE, AST__CURRENT ); fs = astAnnul( fs ); /* Get the CRVAL value for the spectral axis (this will be in the S system). */ crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( crv == AST__BAD ) crv = 0.0; /* Convert it to the wavelength system (vacuum or air) in metres. */ astTran1( smap, 1, &crv, 1, &wcrv ); /* Create a GrismMap, and then use the projection parameters stored in the FitsStore to set its attributes (convert degrees values to radians and supply the defaults specified in FITS-WCS paper III). The FITS paper specifies units in which these parameters should be stored in a FITS header - distances are in metres and angles in degrees. */ gmap = (AstMapping *) astGrismMap( "", status ); pv = GetItem( &(store->pv), i, 0, s, NULL, method, class, status ); astSetGrismG( gmap, ( pv != AST__BAD )?pv:0.0 ); pv = GetItem( &(store->pv), i, 1, s, NULL, method, class, status ); astSetGrismM( gmap, ( pv != AST__BAD )?(int) ( pv + 0.5 ):0); pv = GetItem( &(store->pv), i, 2, s, NULL, method, class, status ); astSetGrismAlpha( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 ); pv = GetItem( &(store->pv), i, 3, s, NULL, method, class, status ); astSetGrismNR( gmap, ( pv != AST__BAD )?pv:1.0 ); pv = GetItem( &(store->pv), i, 4, s, NULL, method, class, status ); astSetGrismNRP( gmap, ( pv != AST__BAD )?pv:0.0 ); pv = GetItem( &(store->pv), i, 5, s, NULL, method, class, status ); astSetGrismEps( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 ); pv = GetItem( &(store->pv), i, 6, s, NULL, method, class, status ); astSetGrismTheta( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 ); /* Store the reference wavelength found above as an attribute of the GrismMap. */ astSetGrismWaveR( gmap, wcrv ); /* Invert the GrismMap to get the (Wavelength -> grism parameter) Mapping, and then combine it with the (S -> Wavelength) Mapping to get the (S -> grism parameter) Mapping. */ astInvert( gmap ); map1 = (AstMapping *) astCmpMap( smap, gmap, 1, "", status ); /* Convert the reference point value from wavelength to grism parameter. */ astTran1( gmap, 1, &wcrv, 1, &gcrv ); /* Find the rate of change of grism parameter with respect to the S system at the reference point, dg/dS. */ dg = astRate( map1, &crv, 0, 0 ); if( dg != AST__BAD && dg != 0.0 ) { /* FITS-WCS paper II requires headers to be constructed so that dS/dw = 1.0 at the reference point. Therefore dg/dw = dg/dS. Create a WinMap which scales and shifts the "w" value to get the grism parameter value. */ map2a = (AstMapping *) astZoomMap( 1, dg, "", status ); map2b = (AstMapping *) astShiftMap( 1, &gcrv, "", status ); map2 = (AstMapping *) astCmpMap( map2a, map2b, 1, "", status ); map2a = astAnnul( map2a ); map2b = astAnnul( map2b ); /* The Mapping to be returned is the concatenation of the above Mapping (from w to g) with the Mapping from g to S. */ astInvert( map1 ); ret = (AstMapping *) astCmpMap( map2, map1, 1, "", status ); map2 = astAnnul( map2 ); } map1 = astAnnul( map1 ); smap = astAnnul( smap ); gmap = astAnnul( gmap ); } wfrm = astAnnul( wfrm ); /* Return the result */ return ret; } static int KeyFields( AstFitsChan *this, const char *filter, int maxfld, int *ubnd, int *lbnd, int *status ){ /* *+ * Name: * astKeyFields * Purpose: * Find the ranges taken by integer fields within the keyword names * in a FitsChan. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astKeyFields( AstFitsChan *this, const char *filter, int maxfld, * int *ubnd, int *lbnd ) * Class Membership: * FitsChan method. * Description: * This function returns the number of cards within a FitsChan which * refer to keywords which match the supplied filter template. If the * filter contains any integer field specifiers (e.g. "%d", "%3d", etc), * it also returns the upper and lower bounds found for the integer * fields. * Parameters: * this * Pointer to the FitsChan. * filter * The filter string. * maxfld * The size of the "ubnd" and "lbnd" arrays. * ubnd * A pointer to an integer array in which to return the * upper bound found for each integer field in the filter. * They are stored in the order in which they occur in the filter. * If the filter contains too many fields to fit in the supplied * array, the excess trailing fields are ignored. * lbnd * A pointer to an integer array in which to return the * lower bound found for each integer field in the filter. * Returned Value: * astKeyFields() * The total number of cards matching the supplied filter in the * FitsChan. * Filter Syntax: * - The criteria for a keyword name to match a filter template are * as follows: * - All characters in the template other than "%" (and the field width * and type specifiers which follow a "%") must be matched by an * identical character in the test string. - If a "%" occurs in the template, then the next character in the * template should be a single digit specifying a field width. If it is * zero, then the test string may contain zero or more matching characters. * Otherwise, the test string must contain exactly the specified number * of matching characters (i.e. 1 to 9). The field width digit may be * omitted, in which case the test string must contain one or more matching * characters. The next character in the template specifies the type of * matching characters and must be one of "d", "c" or "f". Decimal digits * are matched by "d", all upper (but not lower) case alphabetical * characters are matched by "c", and all characters which may legally be * found within a FITS keyword name are matched by "f". * Examples: * - The filter "CRVAL1" accepts the single keyword CRVAL1. * - The filter "CRVAL%1d" accepts the single keyword CRVAL0, CRVAL1, * CRVAL2, up to CRVAL9. * - The filter "CRVAL%d" accepts any keyword consisting of the string * "CRVAL" followed by any integer value. * - The filter "CR%0s1" accepts any keyword starting with the string "CR" * and ending with the character "1" (including CR1). * Notes: * - The entire FitsChan is searched, irrespective of the setting of * the Card attribute. * - If "maxfld" is supplied as zero, "ubnd" and "lbnd" are ignored, * but the number of matching cards is still returned as the function value. * - If no matching cards are found in the FitsChan, or if there are no * integer fields in the filter, then the lower and upper bounds are * returned as zero and -1 (i.e. reversed). * - If an error has already occured, or if this function should fail * for any reason, a value of zero is returned for the function value, * and the lower and upper bounds are set to zero and -1. *- */ /* Local Variables: */ const char *class; /* Object class */ const char *method; /* Method name */ int *fields; /* Pointer to array of field values */ int i; /* Field index */ int icard; /* Index of current card on entry */ int nmatch; /* No. of matching cards */ int nf; /* No. of integer fields in the filter */ int nfld; /* No. of integer fields in current keyword name */ /* Initialise the returned values. */ nmatch = 0; for( i = 0; i < maxfld; i++ ){ lbnd[ i ] = 0; ubnd[ i ] = -1; } nf = 0; /* Check the global error status. */ if ( !astOK || !filter ) return nf; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the method name and object class for use in error messages. */ method = "astKeyFields"; class = astGetClass( this ); /* Count the number of integer fields in the filter string. */ nf = CountFields( filter, 'd', method, class, status ); /* If this is larger than the supplied arrays, use the size of the arrays instead. */ if( nf > maxfld ) nf = maxfld; /* Allocate memory to hold the integer field values extracted from each matching keyword. */ fields = (int *) astMalloc( sizeof( int )*(size_t) nf ); /* Save the current card index, and rewind the FitsChan. */ icard = astGetCard( this ); astClearCard( this ); /* Check that the FitsChan is not empty and the pointer can be used. */ if( !astFitsEof( this ) && astOK ){ /* Initialise the returned bounds. Any excess elements in the array are left at the previously initialised values. */ for( i = 0; i < nf; i++ ){ lbnd[ i ] = INT_MAX; ubnd[ i ] = -INT_MAX; } /* Initialise the number of matching keywords. */ nmatch = 0; /* Loop round all the cards in the FitsChan. */ while( !astFitsEof( this ) && astOK ){ /* If the current keyword name matches the filter, update the returned bounds and increment the number of matches. */ if( Match( CardName( this, status ), filter, nf, fields, &nfld, method, class, status ) ){ for( i = 0; i < nf; i++ ){ if( fields[ i ] > ubnd[ i ] ) ubnd[ i ] = fields[ i ]; if( fields[ i ] < lbnd[ i ] ) lbnd[ i ] = fields[ i ]; } nmatch++; } /* Move on to the next card. */ MoveCard( this, 1, method, class, status ); } /* If bounds were not found, returned 0 and -1. */ for( i = 0; i < nf; i++ ){ if( lbnd[ i ] == INT_MAX ){ lbnd[ i ] = 0; ubnd[ i ] = -1; } } } /* Reinstate the original current card index. */ astSetCard( this, icard ); /* Free the memory used to hold the integer field values extracted from each matching keyword. */ fields = (int *) astFree( (void *) fields ); /* If an error has occurred, returned no matches and reversed bounds. */ if( !astOK ){ nmatch = 0; for( i = 0; i < maxfld; i++ ){ lbnd[ i ] = 0; ubnd[ i ] = -1; } } /* Returned the answer. */ return nmatch; } static int FindFits( AstFitsChan *this, const char *name, char card[ AST__FITSCHAN_FITSCARDLEN + 1 ], int inc, int *status ){ /* *++ * Name: c astFindFits f AST_FINDFITS * Purpose: * Find a FITS card in a FitsChan by keyword. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c int astFindFits( AstFitsChan *this, const char *name, char card[ 81 ], c int inc ) f RESULT = AST_FINDFITS( THIS, NAME, CARD, INC, STATUS ) * Class Membership: * FitsChan member function. * Description: * This function searches for a card in a FitsChan by keyword. The * search commences at the current card (identified by the Card * attribute) and ends when a card is found whose FITS keyword * matches the template supplied, or when the last card in the * FitsChan has been searched. * * If the search is successful (i.e. a card is found which matches c the template), the contents of the card are (optionally) f the template), the contents of the card are * returned and the Card attribute is adjusted to identify the card * found or, if required, the one following it. If the search is c not successful, the function returns zero and the Card attribute f not successful, the function returns .FALSE. and the Card attribute * is set to the "end-of-file". * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c name f NAME = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string containing a f A character string containing a * template for the keyword to be found. In the simplest case, * this should simply be the keyword name (the search is case * insensitive and trailing spaces are ignored). However, this * template may also contain "field specifiers" which are * capable of matching a range of characters (see the "Keyword * Templates" section for details). In this case, the first card * with a keyword which matches the template will be found. To * find the next FITS card regardless of its keyword, you should * use the template "%f". c card f CARD = CHARACTER * ( 80 ) (Returned) c An array of at least 81 characters (to allow room for a c terminating null) f A character variable with at least 80 characters * in which the FITS card which is found will be returned. If c the search is not successful (or a NULL pointer is given), a f the search is not successful, a * card will not be returned. c inc f INC = LOGICAL (Given) c If this value is zero (and the search is successful), the f If this value is .FALSE. (and the search is successful), the * FitsChan's Card attribute will be set to the index of the card c that was found. If it is non-zero, however, the Card f that was found. If it is .TRUE., however, the Card * attribute will be incremented to identify the card which * follows the one found. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astFindFits() f AST_FINDFITS = LOGICAL c One if the search was successful, otherwise zero. f .TRUE. if the search was successful, otherwise .FALSE.. * Notes: * - The search always starts with the current card, as identified * by the Card attribute. To ensure you search the entire contents * of a FitsChan, you should first clear the Card attribute (using c astClear). This effectively "rewinds" the FitsChan. f AST_CLEAR). This effectively "rewinds" the FitsChan. * - If a search is unsuccessful, the Card attribute is set to the * "end-of-file" (i.e. to one more than the number of cards in the * FitsChan). No error occurs. c - A value of zero will be returned if this function is invoked f - A value of .FALSE. will be returned if this function is invoked * with the AST error status set, or if it should fail for any * reason. * Examples: c result = astFindFits( fitschan, "%f", card, 1 ); f RESULT = AST_FINDFITS( FITSCHAN, '%f', CARD, .TRUE., STATUS ) * Returns the current card in a FitsChan and advances the Card * attribute to identify the card that follows (the "%f" * template matches any keyword). c result = astFindFits( fitschan, "BITPIX", card, 1 ); f RESULT = AST_FINDFITS( FITSCHAN, 'BITPIX', CARD, .TRUE., STATUS ) * Searches a FitsChan for a FITS card with the "BITPIX" keyword * and returns that card. The Card attribute is then incremented * to identify the card that follows it. c result = astFindFits( fitschan, "COMMENT", NULL, 0 ); f RESULT = AST_FINDFITS( FITSCHAN, 'COMMENT', CARD, .FALSE., STATUS ) * Sets the Card attribute of a FitsChan to identify the next c COMMENT card (if any). The card itself is not returned. f COMMENT card (if any) and returns that card. c result = astFindFits( fitschan, "CRVAL%1d", card, 1 ); f RESULT = AST_FINDFITS( FITSCHAN, 'CRVAL%1d', CARD, .TRUE., STATUS ) * Searches a FitsChan for the next card with a keyword of the * form "CRVALi" (for example, any of the keywords "CRVAL1", * "CRVAL2" or "CRVAL3" would be matched). The card found (if * any) is returned, and the Card attribute is then incremented * to identify the following card (ready to search for another * keyword with the same form, perhaps). * Keyword Templates: * The templates used to match FITS keywords are normally composed * of literal characters, which must match the keyword exactly * (apart from case). However, a template may also contain "field * specifiers" which can match a range of possible characters. This * allows you to search for keywords that contain (for example) * numbers, where the digits comprising the number are not known in * advance. * * A field specifier starts with a "%" character. This is followed * by an optional single digit (0 to 9) specifying a field * width. Finally, there is a single character which specifies the * type of character to be matched, as follows: * * - "c": matches all upper case letters, * - "d": matches all decimal digits, * - "f": matches all characters which are permitted within a FITS * keyword (upper case letters, digits, underscores and hyphens). * * If the field width is omitted, the field specifier matches one * or more characters. If the field width is zero, it matches zero * or more characters. Otherwise, it matches exactly the number of * characters specified. In addition to this: * * - The template "%f" will match a blank FITS keyword consisting * of 8 spaces (as well as matching all other keywords). * - A template consisting of 8 spaces will match a blank keyword * (only). * * For example: * * - The template "BitPix" will match the keyword "BITPIX" only. * - The template "crpix%1d" will match keywords consisting of * "CRPIX" followed by one decimal digit. * - The template "P%c" will match any keyword starting with "P" * and followed by one or more letters. * - The template "E%0f" will match any keyword beginning with "E". * - The template "%f" will match any keyword at all (including a * blank one). *-- */ /* Local Variables: */ char *c; /* Pointer to next character to check */ char *lname; /* Pointer to copy of name without trailing spaces */ const char *class; /* Object class */ const char *method; /* Calling method */ int ret; /* Was a card found? */ /* Check the global status, and supplied keyword name. */ if( !astOK ) return 0; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the calling method and object class. */ method = "astFindFits"; class = astGetClass( this ); /* Get a local copy of the keyword template. */ lname = (char *) astStore( NULL, (void *) name, strlen(name) + 1 ); /* Terminate it to exclude trailing spaces. */ c = lname + strlen(lname) - 1; while( *c == ' ' && c >= lname ) *(c--) = 0; /* Use the private FindKeyCard function to find the card and make it the current card. Always use the supplied current card (if any) if the template is "%f" or "%0f". */ if ( !strcmp( lname, "%f" ) || !strcmp( lname, "%0f" ) ){ ret = astFitsEof( this ) ? 0 : 1; } else { ret = FindKeyCard( this, lname, method, class, status ); } /* Only proceed if the card was found. */ if( ret && astOK ){ /* Format the current card if a destination string was supplied. */ if( card ) FormatCard( this, card, method, status ); /* Increment the current card pointer if required. */ if( inc ) MoveCard( this, 1, method, class, status ); /* Indicate that a card has been formatted. */ ret = 1; } /* Free the memory holding the local copy of the keyword template. */ lname = (char *) astFree( (void *) lname ); /* If an errror has occurred, return zero. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static int FindKeyCard( AstFitsChan *this, const char *name, const char *method, const char *class, int *status ){ /* * Name: * FindKeyCard * Purpose: * Find the next card refering to given keyword. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FindKeyCard( AstFitsChan *this, const char *name, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Finds the next card which refers to the supplied keyword and makes * it the current card. The search starts with the current card and ends * when it reaches the last card. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a string holding the keyword template (using the * syntax expected by the Match function). * method * Pointer to string holding name of calling method. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if a card was found refering to the given * keyword. Otherwise zero is returned. * Notes: * - If a NULL pointer is supplied for "name" then the current card * is left unchanged. * - The current card is set to NULL (end-of-file) if no card can be * found for the supplied keyword. */ /* Local Variables: */ int nfld; /* Number of fields in keyword template */ int ret; /* Was a card found? */ /* Check the global status, and supplied keyword name. */ if( !astOK || !name ) return 0; /* Indicate that no card has been found yet. */ ret = 0; /* Search forward through the list until all cards have been checked. */ while( !astFitsEof( this ) && astOK ){ /* Break out of the loop if the keyword name from the current card matches the supplied keyword name. */ if( Match( CardName( this, status ), name, 0, NULL, &nfld, method, class, status ) ){ ret = 1; break; /* Otherwise, move the current card on to the next card. */ } else { MoveCard( this, 1, method, class, status ); } } /* Return. */ return ret; } static double *FitLine( AstMapping *map, double *g, double *g0, double *w0, double dim, double *tol, int *status ){ /* * Name: * FitLine * Purpose: * Check a Mapping for linearity. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double *FitLine( AstMapping *map, double *g, double *g0, double *w0, * double dim, double *tol, int *status ) * Class Membership: * FitsChan member function. * Description: * This function applies the supplied Mapping to a set of points along * a straight line in the input space. It checks to see if the transformed * positions also lie on a straight line (in the output space). If so, * it returns the vector along this line in the output space which * corresponds to a unit vector along the line in the input space. If * not, a NULL pointer is returned. * * The returned vector is found by doing a least squares fit. * Parameters: * map * A pointer to the Mapping to test. The number of outputs must be * greater than or equal to the number of inputs. * g * A pointer to an array holding a unit vector within the input space * defining the straight line to be checked. The number of elements * within this array should equal the number of inputs for "map". * g0 * A pointer to an array holding a position within the input space * giving the central position of the vector "g". The number of elements * within this array should equal the number of inputs for "map". * w0 * A pointer to an array holding a vector within the output space * which corresponds to "g0". The number of elements within this array * should equal the number of outputs for "map". * dim * The length of the pixel axis, or AST__BAD if unknown. * tol * Pointer to an array holding the tolerance for equality on each * output axis. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to dynamically allocated memory holding the required vector * in the output space. The number of elements in this vector will equal * the number of outputs for "map". The memory should be freed using * astFree when no longer needed. If the Mapping is not linear, NULL * is returned. * Notes: * - NULL is returned if an error occurs. */ /* Local Constants: */ #define NPO2 50 #define NP (2*NPO2+1) /* Local Variables: */ AstPointSet *pset1; AstPointSet *pset2; double **ptr1; double **ptr2; double *offset; double *pax; double *ret; double *voffset; double dax; double denom; double gap; double sd2; double sd; double sdw; double sw; double wmax; double wmin; int i; int j; int n; int nin; int nout; int ok; /* Initialise */ ret = NULL; /* Check the inherited status and supplied axis size. */ if( !astOK || dim == 0.0 ) return ret; /* Get the number of inputs and outputs for the Mapping. Return if the number of outputs is smaller than the number of inputs. */ nin = astGetNin( map ); nout = astGetNout( map ); if( nout < nin ) return ret; /* Check the supplied position is good on all axes. */ for( j = 0; j < nout; j++ ) { if( w0[ j ] == AST__BAD ) return ret; } /* We use NP points in the fit. If a value for "dim" has been supplied, we use points evenly distributed over one tenth of this size, If not, we use a gap of 1.0 (corresponds to an axis length of 100 pixels). Choose the gap. */ gap = ( dim != AST__BAD ) ? 0.1*dim/NP : 1.0; /* Create PointSets to hold the input and output positions. */ pset1 = astPointSet( NP, nin, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( NP, nout, "", status ); ptr2 = astGetPoints( pset2 ); /* Allocate the returned array. */ ret = astMalloc( sizeof( double )*(size_t) nout ); /* Allocate workspace to hold the constant offsets of the fit. */ offset = astMalloc( sizeof( double )*(size_t) nout ); voffset = astMalloc( sizeof( double )*(size_t) nout ); /* Indicate we have not yet got a usable returned vector. */ ok = 0; /* Check we can use the pointers safely. */ if( astOK ) { /* Set up the input positions: NP evenly spaced points along a line with unit direction vector given by "g", centred at position given by "g0". */ for( j = 0; j < nin; j++ ) { pax = ptr1[ j ]; dax = g[ j ]*gap; for( i = -NPO2; i <= NPO2; i++ ) *(pax++) = g0[ j ] + dax*i; } /* Transform these positions into the output space. */ (void) astTransform( map, pset1, 1, pset2 ); /* Loop over all output axes, finding the component of the returned vector. */ ok = 1; for( j = 0; j < nout; j++ ) { pax = ptr2[ j ]; /* Now loop over all the transformed points to form the other required sums. We also form the sums needed to estimate the variance in the calculated offset. */ sdw = 0.0; sw = 0.0; sd = 0.0; sd2 = 0.0; n = 0; wmax = -DBL_MAX; wmin = DBL_MAX; for( i = -NPO2; i <= NPO2; i++, pax++ ) { if( *pax != AST__BAD ) { /* Increment the required sums. */ sdw += i*(*pax); sw += (*pax); sd += i; sd2 += i*i; n++; if( *pax > wmax ) wmax = *pax; if( *pax < wmin ) wmin = *pax; } } /* If a reasonable number of good points were found, find the component of the returned vector (excluding a scale factor of 1/gap). */ denom = sd2*n - sd*sd; if( n > NP/4 && denom != 0.0 ) { /* Find the constant scale factor to return for this axis. If the axis value is constant, return zero. */ if( wmax > wmin ) { ret[ j ] = (sdw*n - sw*sd)/denom; } else { ret[ j ] = 0.0; } /* Now find the constant offset for this axis. */ offset[ j ] = (sw*sd2 - sdw*sd)/denom; } else { ok = 0; break; } } /* Now check that the fit is good enough. Each axis is checked separately. All axes must be good. */ if( ok ) { for( j = 0; j < nout; j++ ) { /* Store the axis values implied by the linear fit in the now un-needed ptr1[0] array. */ pax = ptr1[ 0 ]; for( i = -NPO2; i <= NPO2; i++, pax++ ) { *pax = i*ret[ j ] + offset[ j ]; } /* Test the fit to see if we beleive that the mapping is linear. If it is, scale the returned value from units of "per gap" to units of "per pixel". Otherwise,indicate that he returned vector is unusable. */ if( FitOK( NP, ptr2[ j ], ptr1[ 0 ], tol[ j ], status ) ) { ret[ j ] /= gap; } else { ok = 0; break; } } } } /* Annul the PointSets. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* Free memory. */ offset = astFree( offset ); voffset = astFree( voffset ); /* If an error has occurred, or if the returned vector is unusable, free any returned memory */ if( !astOK || !ok ) ret = astFree( ret ); /* Return the answer. */ return ret; /* Undefine local constants: */ #undef NP #undef NPO2 } static int FitsEof( AstFitsChan *this, int *status ){ /* *+ * Name: * astFitsEof * Purpose: * See if the FitsChan is at "end-of-file". * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astFitsEof( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * A value of zero is returned if any more cards remain to be read from the * FitsChan. Otherwise a value of 1 is returned. Thus, it is * equivalent to testing the FitsChan for an "end-of-file" condition. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * One if no more cards remain to be read, otherwise zero. * Notes: * - This function attempts to execute even if an error has already * occurred. *- */ /* Check the supplied object. */ if( !this ) return 1; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* If no more cards remain to be read, the current card pointer in the FitsChan will be NULL. Return an appropriate integer value. */ return this->card ? 0 : 1; } static int FitsSof( AstFitsChan *this, int *status ){ /* *+ * Name: * FitsSof * Purpose: * See if the FitsChan is at "start-of-file". * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FitsSof( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * A value of 1 is returned if the current card is the first card in * the FitsChan. Otherwise a value of zero is returned. This function * is much more efficient than "astGetCard(this) <= 1" . * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the current card is the first card. * Notes: * - This function attempts to execute even if an error has already * occurred. * - A non-zero value is returned if the FitsChan is empty. *- */ /* Return if no FitsChan was supplied, or if the FitsChan is empty. */ if ( !this || !this->head ) return 1; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* If the current card is at the head of the linked list, it is the first card. */ return this->card == this->head; } /* *++ * Name: c astGetFits f AST_GETFITS * Purpose: * Get a named keyword value from a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c int astGetFits( AstFitsChan *this, const char *name, type *value ) f RESULT = AST_GETFITS( THIS, NAME, VALUE, STATUS ) * Class Membership: * FitsChan method. * Description: * This is a family of functions which gets a value for a named keyword, * or the value of the current card, from a FitsChan using one of several * different data types. The data type of the returned value is selected * by replacing in the function name by one of the following strings * representing the recognised FITS data types: * * - CF - Complex floating point values. * - CI - Complex integer values. * - F - Floating point values. * - I - Integer values. * - L - Logical (i.e. boolean) values. * - S - String values. * - CN - A "CONTINUE" value, these are treated like string values, but * are encoded without an equals sign. * * The data type of the "value" c parameter f argument * depends on as follows: * c - CF - "double *" (a pointer to a 2 element array to hold the real and c imaginary parts of the complex value). c - CI - "int *" (a pointer to a 2 element array to hold the real and c imaginary parts of the complex value). c - F - "double *". c - I - "int *". c - L - "int *". c - S - "char **" (a pointer to a static "char" array is returned at the c location given by the "value" parameter, Note, the stored string c may change on subsequent invocations of astGetFitsS so a c permanent copy should be taken of the string if necessary). c - CN - Like"S". f - CF - DOUBLE PRECISION(2) (a 2 element array to hold the real and f imaginary parts of the complex value). f - CI - INTEGER(2) (a 2 element array to hold the real and imaginary f parts of the complex value). f - F - DOUBLE PRECISION. f - I - INTEGER f - L - LOGICAL f - S - CHARACTER f - CN - CHARACTER * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c name f NAME = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string f A character string * containing the FITS keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. If c NULL f a single dot '.' * is supplied, the value of the current card is returned. c value f VALUE = type (Returned) c A pointer to a f A * buffer to receive the keyword value. The data type depends on * as described above. The conents of the buffer on entry are left * unchanged if the keyword is not found. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astGetFits() f AST_GETFITS = LOGICAL c A value of zero f .FALSE. * is returned if the keyword was not found in the FitsChan (no error * is reported). Otherwise, a value of c one f .TRUE. * is returned. * Notes: * - If a name is supplied, the card following the current card is * checked first. If this is not the required card, then the rest of the * FitsChan is searched, starting with the first card added to the * FitsChan. Therefore cards should be accessed in the order they are * stored in the FitsChan (if possible) as this will minimise the time * spent searching for cards. * - If the requested card is found, it becomes the current card, * otherwise the current card is left pointing at the "end-of-file". * - If the stored keyword value is not of the requested type, it is * converted into the requested type. * - If the keyword is found in the FitsChan, but has no associated * value, an error is reported. If necessary, the c astTestFits f AST_TESTFITS * function can be used to determine if the keyword has a defined * value in the FitsChan prior to calling this function. * - An error will be reported if the keyword name does not conform * to FITS requirements. c - Zero * - .FALSE. * is returned as the function value if an error has already occurred, * or if this function should fail for any reason. * - The FITS standard says that string keyword values should be * padded with trailing spaces if they are shorter than 8 characters. * For this reason, trailing spaces are removed from the string * returned by c astGetFitsS f AST_GETFITSS * if the original string (including any trailing spaces) contains 8 * or fewer characters. Trailing spaces are not removed from longer * strings. *-- */ /* Define a macro which expands to the implementation of the astGetFits routine for a given data type. */ #define MAKE_FGET(code,ctype,ftype) \ static int GetFits##code( AstFitsChan *this, const char *name, ctype value, int *status ){ \ \ /* Local Variables: */ \ const char *class; /* Object class */ \ const char *method; /* Calling method */ \ char *lcom; /* Supplied keyword comment */ \ char *lname; /* Supplied keyword name */ \ char *lvalue; /* Supplied keyword value */ \ char *string; /* Pointer to returned string value */ \ char *c; /* Pointer to next character */ \ int cl; /* Length of string value */ \ int ret; /* The returned value */ \ \ /* Check the global error status. */ \ if ( !astOK ) return 0; \ \ /* Ensure the source function has been called */ \ ReadFromSource( this, status ); \ \ /* Store the calling method and object class. */ \ method = "astGetFits"#code; \ class = astGetClass( this ); \ \ /* Initialise the returned value. */ \ ret = 0; \ \ /* Extract the keyword name from the supplied string. */ \ if( name ) { \ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); \ } else { \ lname = NULL; \ lvalue = NULL; \ lcom = NULL; \ } \ \ /* Attempt to find a card in the FitsChan refering to this keyword, \ and make it the current card. Only proceed if a card was found. No \ need to do the search if the value of the current card is required. */ \ if( !lname || SearchCard( this, lname, method, class, status ) ){ \ \ /* Convert the stored data value to the requested type, and store it in \ the supplied buffer. */ \ if( !CnvValue( this, ftype, 0, value, method, status ) && astOK ) { \ astError( AST__FTCNV, "%s(%s): Cannot convert FITS keyword " \ "'%s' to %s.", status, method, class, \ CardName( this, status ), type_names[ ftype ] ); \ } \ \ /* If the returned value is a string containing 8 or fewer characters, \ replace trailing spaces with null characters. */ \ if( astOK ) { \ if( ftype == AST__STRING ) { \ string = *( (char **) value ); \ if( string ) { \ cl =strlen( string ); \ if( cl <= 8 ) { \ c = string + cl - 1; \ while( *c == ' ' && c > string ) { \ *c = 0; \ c--; \ } \ } \ } \ } \ \ /* Indicate that a value is available. */ \ ret = 1; \ } \ \ } \ \ /* Context error message. */ \ if( !astOK && lname && *lname ) { \ astError( astStatus, "%s(%s): Cannot get value for FITS keyword " \ "'%s'.", status, method, class, lname ); \ } \ \ /* Release the memory used to hold keyword name, value and comment strings. */ \ lname = (char *) astFree( (void *) lname ); \ lvalue = (char *) astFree( (void *) lvalue ); \ lcom = (char *) astFree( (void *) lcom ); \ \ /* Return the answer. */ \ return ret; \ \ } /* Use the above macro to give defintions for the astGetFits method for each FITS data type. */ MAKE_FGET(CF,double *,AST__COMPLEXF) MAKE_FGET(CI,int *,AST__COMPLEXI) MAKE_FGET(F,double *,AST__FLOAT) MAKE_FGET(I,int *,AST__INT) MAKE_FGET(L,int *,AST__LOGICAL) MAKE_FGET(S,char **,AST__STRING) MAKE_FGET(CN,char **,AST__CONTINUE) #undef MAKE_FGET static int FitsGetCom( AstFitsChan *this, const char *name, char **comment, int *status ){ /* *+ * Name: * astFitsGetCom * Purpose: * Get a keyword comment from a FitsChan. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astFitsGetCom( AstFitsChan *this, const char *name, * char **comment ) * Class Membership: * FitsChan method. * Description: * This function gets the comment associated with the next occurrence of * a named keyword in a FitsChan. * Parameters: * this * Pointer to the FitsChan. * name * A pointer to a * string holding the keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. * comment * A pointer to a location at which to return a pointer to a string * holding the keyword comment. Note, the stored string will change on * subsequent invocations of astFitsGetCom so a permanent copy * should be taken of the string if necessary. * Returned Value: * astFitsGetCom() * A value of zero is returned if the keyword was not found before * the end of the FitsChan was reached (no error is reported). * Otherwise, a value of one is returned. * Notes: * - If a NULL pointer is supplied for "name" then the comment from * the current card is returned. * - The returned value is obtained from the next card refering to * the required keyword, starting the search with the current card. * Any cards occuring before the current card are not seached. If * the entire contents of the FitsChan must be searched, then ensure * the current card is the first card in the FitsChan by clearing the Card * attribute. This effectively "rewinds" the FitsChan. * - The current card is updated to become the card following the one * read by this function. If the card read by this function is the * last one in the FitsChan, then the current card is left pointing at the * "end-of-file". * - An error will be reported if the keyword name does not conform * to FITS requirements. * - A NULL pointer is returned for the comment string if the keyword * has no comment. * - Zero is returned as the function value if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *method; /* Calling method */ const char *class; /* Object class */ char *lcom; /* Supplied keyword comment */ char *lname; /* Supplied keyword name */ char *lvalue; /* Supplied keyword value */ int ret; /* The returned value */ /* Check the global error status. */ if ( !astOK ) return 0; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Initialise the returned value. */ ret = 0; /* Store the method name and object class. */ method = "astFitsGetCom"; class = astGetClass( this ); /* Extract the keyword name from the supplied string (if supplied). */ if( name ){ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); } else { lname = NULL; lcom = NULL; lvalue = NULL; } /* Find the next card in the FitsChan refering to this keyword. This will be the current card if no keyword name was supplied. The matching card is made the current card. Only proceed if a card was found. */ if( FindKeyCard( this, lname, method, class, status ) ){ /* Copy the comment into a static buffer, and return a pointer to it. */ if( CardComm( this, status ) ){ (void) strncpy( fitsgetcom_sval, CardComm( this, status ), AST__FITSCHAN_FITSCARDLEN ); fitsgetcom_sval[ AST__FITSCHAN_FITSCARDLEN ] = 0; if( comment ) *comment = fitsgetcom_sval; } else { if( comment ) *comment = NULL; } /* Move on to the next card. */ MoveCard( this, 1, method, class, status ); /* Indicate that a value is available. */ if( astOK ) ret = 1; } /* Release the memory used to hold keyword name, value and comment strings. */ lname = (char *) astFree( (void *) lname ); lvalue = (char *) astFree( (void *) lvalue ); lcom = (char *) astFree( (void *) lcom ); /* Return the answer. */ return ret; } static int SetFits( AstFitsChan *this, const char *keyname, void *value, int type, const char *comment, int overwrite, int *status ){ /* * Name: * SetFits * Purpose: * Store a keyword value of any type in a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int SetFits( AstFitsChan *this, const char *keyname, void *value, * int type, const char *comment, int overwrite, int *status ) * Class Membership: * FitsChan member function. * Description: * This function stores the supplied value for the supplied keyword * in the supplied FitsChan, assuming it is of the supplied data type. * Parameters: * this * Pointer to the FitsChan. * name * A pointer to a string holding the keyword name. * value * A pointer to a buffer holding the keyword value. For strings, * the buffer should hold the address of a pointer to the character * string. * type * The keyword type. * comment * A pointer to a string holding a comment to associated with the * keyword. If a NULL pointer or a blank string is supplied, then * any comment included in the string supplied for the "name" parameter * is used instead. If "name" contains no comment, then any existing * comment in the card being over-written is retained, or a NULL * pointer is stored if a new card is being inserted. If the data * value being stored for the card is the same as the card being * over-written, then any existing comment is retained. * overwrite * If non-zero, the new card formed from the supplied keyword name, * value and comment string over-writes the current card, and the * current card is incremented to refer to the next card. If zero, the * new card is inserted in front of the current card and the current * card is left unchanged. In either case, if the current card on * entry points to the "end-of-file", the new card is appended to the * end of the list. * status * Pointer to the inherited status variable. * Returned Value: * A value of 0 is returned if the value could not be stored for any * reason. A value of 1 is returned otherwise. * Notes: * - Nothing is stored in the FitsChan and a value of zero is returned * (but no error is reported) if an AST__FLOAT value is supplied equal * to AST__BAD. */ /* Local Variables: */ const char *cval; const char *ecval; double dval; double ecdval[ 2 ]; double edval; int ecival[ 2 ]; int eival; int ival; int ret; /* Check the global status, and the supplied pointer. */ if( !astOK || !value ) return 0; /* Initialise the returned value to indicate that the supplied name was stored. */ ret = 1; /* Check each data type in turn. */ if( type == AST__FLOAT ){ dval = *( (double *) value ); if( dval != AST__BAD ) { /* If the data value has not changed, and the card has a coment, set the comment pointer NULL so that the existing comment will be retained. */ if( overwrite && CnvValue( this, type, 0, &edval, "SetFits", status ) && CardComm( this, status ) ) { if( EQUAL( edval, dval ) ) comment = NULL; } astSetFitsF( this, keyname, dval, comment, overwrite ); } else { ret = 0; } } else if( type == AST__STRING ){ cval = *( (char **) value); if( cval ){ /* If the data value has not changed, retain the original comment. */ if( overwrite && CnvValue( this, type, 0, &ecval, "SetFits", status ) && CardComm( this, status ) ) { if( Similar( ecval, cval, status ) ) comment = NULL; } /* Ignore comments if they are identical to the keyword value. */ if( comment && !strcmp( cval, comment ) ) comment = NULL; astSetFitsS( this, keyname, cval, comment, overwrite ); } else { ret = 0; } } else if( type == AST__CONTINUE ){ cval = *( (char **) value); if( cval ){ astSetFitsCN( this, keyname, cval, comment, overwrite ); } else { ret = 0; } } else if( type == AST__COMMENT ){ astSetFitsCom( this, keyname, comment, overwrite ); } else if( type == AST__INT ){ ival = *( (int *) value ); /* If the data value has not changed, retain the original comment. */ if( overwrite && CnvValue( this, type, 0, &eival, "SetFits", status ) && CardComm( this, status ) ) { if( eival == ival ) comment = NULL; } astSetFitsI( this, keyname, ival, comment, overwrite ); } else if( type == AST__COMPLEXF ){ if( ( (double *) value )[0] != AST__BAD && ( (double *) value )[1] != AST__BAD ) { /* If the data value has not changed, retain the original comment. */ if( overwrite && CnvValue( this, type, 0, ecdval, "SetFits", status ) && CardComm( this, status ) ) { if( EQUAL( ecdval[ 0 ], ( (double *) value )[ 0 ] ) && EQUAL( ecdval[ 1 ], ( (double *) value )[ 1 ] ) ) comment = NULL; } astSetFitsCF( this, keyname, (double *) value, comment, overwrite ); } else { ret = 0; } } else if( type == AST__COMPLEXI ){ /* If the data value has not changed, retain the original comment. */ if( overwrite && CnvValue( this, type, 0, ecival, "SetFits", status ) && CardComm( this, status ) ) { if( ecival[ 0 ] == ( (int *) value )[ 0 ] && ecival[ 1 ] == ( (int *) value )[ 1 ] ) comment = NULL; } astSetFitsCI( this, keyname, (int *) value, comment, overwrite ); } else if( type == AST__LOGICAL ){ ival = ( *( (int *) value ) != 0 ); /* If the data value has not changed, retain the original comment. */ if( overwrite && CnvValue( this, type, 0, &eival, "SetFits", status ) && CardComm( this, status ) ) { if( eival == ival ) comment = NULL; } astSetFitsL( this, keyname, ival, comment, overwrite ); } else if( type == AST__UNDEF ){ if( overwrite && CardType( this, status ) == AST__UNDEF && CardComm( this, status ) ) { comment = NULL; } astSetFitsU( this, keyname, comment, overwrite ); } return ret; } /* *++ * Name: c astSetFits f AST_SETFITS * Purpose: * Store a keyword value in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astSetFits( AstFitsChan *this, const char *name, type value, c const char *comment, int overwrite ) f CALL AST_SETFITS( THIS, NAME, VALUE, COMMENT, OVERWRITE, STATUS ) * Class Membership: * FitsChan method. * Description: c This is a family of functions which store values for named keywords f This is a family of routines which store values for named keywords * within a FitsChan at the current card position. The supplied keyword * value can either over-write an existing keyword value, or can be * inserted as a new header card into the FitsChan. * c The keyword data type is selected by replacing in the function name f The keyword data type is selected by replacing in the routine name * by one of the following strings representing the recognised FITS data * types: * * - CF - Complex floating point values. * - CI - Complex integer values. * - F - Floating point values. * - I - Integer values. * - L - Logical (i.e. boolean) values. * - S - String values. * - CN - A "CONTINUE" value, these are treated like string values, but * are encoded without an equals sign. * * The data type of the "value" parameter depends on as follows: * c - CF - "double *" (a pointer to a 2 element array holding the real and c imaginary parts of the complex value). c - CI - "int *" (a pointer to a 2 element array holding the real and c imaginary parts of the complex value). c - F - "double". c - I - "int". c - L - "int". c - S - "const char *". c - CN - "const char *". * f - CF - DOUBLE PRECISION(2) (a 2 element array holding the real and f imaginary parts of the complex value). f - CI - INTEGER(2) (a 2 element array holding the real and imaginary f parts of the complex value). f - F - DOUBLE PRECISION. f - I - INTEGER f - L - LOGICAL f - S - CHARACTER f - CN - CHARACTER * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c name f NAME = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string f A character string * containing the FITS keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. c value f VALUE = type (Given) * The keyword value to store with the named keyword. The data type * of this parameter depends on as described above. c comment f COMMENT = CHARACTER * ( * ) (Given) c A pointer to a null terminated string f A string * holding a comment to associated with the keyword. c If a NULL pointer or f If * a blank string is supplied, then any comment included in the string * supplied for the c "name" parameter is used instead. If "name" f NAME parameter is used instead. If NAME * contains no comment, then any existing comment in the card being * over-written is retained. Otherwise, no comment is stored with * the card. c overwrite f OVERWRITE = LOGICAL (Given) c If non-zero, f If .TRUE., * the new card formed from the supplied keyword name, value and comment * string over-writes the current card, and the current card is * incremented to refer to the next card (see the "Card" attribute). If c zero, f .FALSE., * the new card is inserted in front of the current card and the current * card is left unchanged. In either case, if the current card on entry * points to the "end-of-file", the new card is appended to the end of * the list. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - The c function astSetFitsU f routine AST_SETFITSU * can be used to indicate that no value is associated with a keyword. * - The c function astSetFitsCM f routine AST_SETFITSCM * can be used to store a pure comment card (i.e. a card with a blank * keyword). * - To assign a new value for an existing keyword within a FitsChan, c first find the card describing the keyword using astFindFits, and c then use one of the astSetFits family to over-write the old value. f first find the card describing the keyword using AST_FINDFITS, and f then use one of the AST_SETFITS family to over-write the old value. * - If, on exit, there are no cards following the card written by c this function, then the current card is left pointing at the f this routine, then the current card is left pointing at the * "end-of-file". * - An error will be reported if the keyword name does not conform * to FITS requirements. *-- */ /* Define a macro which expands to the implementation of the astSetFits routine for a given data type. */ #define MAKE_FSET(code,ctype,ftype,valexp) \ static void SetFits##code( AstFitsChan *this, const char *name, ctype value, const char *comment, int overwrite, int *status ) { \ \ /* Local variables: */ \ const char *class; /* Object class */ \ const char *method; /* Calling method */ \ const char *com; /* Comment to use */ \ char *lcom; /* Supplied keyword comment */ \ char *lname; /* Supplied keyword name */ \ char *lvalue; /* Supplied keyword value */ \ int free_com; /* Should com be freed before returned? */ \ \ /* Check the global error status. */ \ if ( !astOK ) return; \ \ /* Ensure the source function has been called */ \ ReadFromSource( this, status ); \ \ /* Store the object clas and calling method. */ \ class = astGetClass( this ); \ method = "astSetFits"#code; \ \ /* Extract the keyword name from the supplied string. */ \ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); \ \ /* Initialise a pointer to the comment to be stored. If the supplied \ comment is blank, use the comment given with "name". */ \ com = ChrLen( comment, status ) ? comment : lcom; \ \ /* If the comment is still blank, use the existing comment if we are \ over-writing, or a NULL pointer otherwise. */ \ free_com = 0; \ if( !ChrLen( com, status ) ) { \ com = NULL; \ if( overwrite ) { \ if( CardComm( this, status ) ){ \ com = (const char *) astStore( NULL, (void *) CardComm( this, status ), \ strlen( CardComm( this, status ) ) + 1 ); \ free_com = 1; \ } \ } \ } \ \ /* Insert the new card. */ \ InsCard( this, overwrite, lname, ftype, valexp, com, method, class, status ); \ \ /* Release the memory used to hold keyword name, value and comment strings. */ \ lname = (char *) astFree( (void *) lname ); \ lvalue = (char *) astFree( (void *) lvalue ); \ lcom = (char *) astFree( (void *) lcom ); \ \ /* Release the memory holding the stored comment string, so long as it was \ allocated within this function. */ \ if( free_com ) com = (const char *) astFree( (void *) com ); \ \ } /* Use the above macro to give defintions for the astSetFits method for each FITS data type. */ MAKE_FSET(I,int,AST__INT,(void *)&value) MAKE_FSET(F,double,AST__FLOAT,(void *)&value) MAKE_FSET(S,const char *,AST__STRING,(void *)value) MAKE_FSET(CN,const char *,AST__CONTINUE,(void *)value) MAKE_FSET(CF,double *,AST__COMPLEXF,(void *)value) MAKE_FSET(CI,int *,AST__COMPLEXI,(void *)value) MAKE_FSET(L,int,AST__LOGICAL,(void *)&value) #undef MAKE_FSET static void SetFitsU( AstFitsChan *this, const char *name, const char *comment, int overwrite, int *status ) { /* *++ * Name: c astSetFitsU f AST_SETFITSU * Purpose: * Store an undefined keyword value in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astSetFitsU( AstFitsChan *this, const char *name, c const char *comment, int overwrite ) f CALL AST_SETFITSU( THIS, NAME, COMMENT, OVERWRITE, STATUS ) * Description: * This c function f routine * stores an undefined value for a named keyword within * a FitsChan at the current card position. The new undefined value * can either over-write an existing keyword value, or can be inserted * as a new header card into the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c name f NAME = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string f A character string * containing the FITS keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. c comment f COMMENT = CHARACTER * ( * ) (Given) c A pointer to a null terminated string f A string * holding a comment to associated with the keyword. c If a NULL pointer or f If * a blank string is supplied, then any comment included in the string * supplied for the c "name" parameter is used instead. If "name" f NAME parameter is used instead. If NAME * contains no comment, then any existing comment in the card being * over-written is retained. Otherwise, no comment is stored with * the card. c overwrite f OVERWRITE = LOGICAL (Given) c If non-zero, f If .TRUE., * the new card formed from the supplied keyword name and comment * string over-writes the current card, and the current card is * incremented to refer to the next card (see the "Card" attribute). If c zero, f .FALSE., * the new card is inserted in front of the current card and the current * card is left unchanged. In either case, if the current card on entry * points to the "end-of-file", the new card is appended to the end of * the list. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - If, on exit, there are no cards following the card written by * this function, then the current card is left pointing at the * "end-of-file". * - An error will be reported if the keyword name does not conform * to FITS requirements. *-- */ /* Local variables: */ const char *class; /* Object class */ const char *method; /* Calling method */ const char *com; /* Comment to use */ char *lcom; /* Supplied keyword comment */ char *lname; /* Supplied keyword name */ char *lvalue; /* Supplied keyword value */ int free_com; /* Should com be freed before returned? */ /* Check the global error status. */ if ( !astOK ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the object clas and calling method. */ class = astGetClass( this ); method = "astSetFitsU"; /* Extract the keyword name from the supplied string. */ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); /* Initialise a pointer to the comment to be stored. If the supplied comment is blank, use the comment given with "name". */ com = ChrLen( comment, status ) ? comment : lcom; /* If the comment is still blank, use the existing comment if we are over-writing, or a NULL pointer otherwise. */ free_com = 0; if( !ChrLen( com, status ) ) { com = NULL; if( overwrite ) { if( CardComm( this, status ) ){ com = (const char *) astStore( NULL, (void *) CardComm( this, status ), strlen( CardComm( this, status ) ) + 1 ); free_com = 1; } } } /* Insert the new card. */ InsCard( this, overwrite, lname, AST__UNDEF, NULL, com, method, class, status ); /* Release the memory used to hold keyword name, value and comment strings. */ lname = (char *) astFree( (void *) lname ); lvalue = (char *) astFree( (void *) lvalue ); lcom = (char *) astFree( (void *) lcom ); /* Release the memory holding the stored comment string, so long as it was allocated within this function. */ if( free_com ) com = (const char *) astFree( (void *) com ); } static void SetFitsCM( AstFitsChan *this, const char *comment, int overwrite, int *status ) { /* *++ * Name: c astSetFitsCM f AST_SETFITSCM * Purpose: * Store a comment card in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astSetFitsCM( AstFitsChan *this, const char *comment, c int overwrite ) f CALL AST_SETFITSCM( THIS, COMMENT, OVERWRITE, STATUS ) * Description: * This c function f routine * stores a comment card ( i.e. a card with no keyword name or equals * sign) within a FitsChan at the current card position. The new card * can either over-write an existing card, or can be inserted as a new * card into the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c comment f COMMENT = CHARACTER * ( * ) (Given) c A pointer to a null terminated string f A string * holding the text of the comment card. c If a NULL pointer or f If * a blank string is supplied, then a totally blank card is produced. c overwrite f OVERWRITE = LOGICAL (Given) c If non-zero, f If .TRUE., * the new card over-writes the current card, and the current card is * incremented to refer to the next card (see the "Card" attribute). If c zero, f .FALSE., * the new card is inserted in front of the current card and the current * card is left unchanged. In either case, if the current card on entry * points to the "end-of-file", the new card is appended to the end of * the list. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - If, on exit, there are no cards following the card written by * this function, then the current card is left pointing at the * "end-of-file". *-- */ /* Just call astSetFitsCom with a blank keyword name. */ astSetFitsCom( this, "", comment, overwrite ); } static void SetFitsCom( AstFitsChan *this, const char *name, const char *comment, int overwrite, int *status ){ /* *+ * Name: * astSetFitsCom * Purpose: * Store a comment for a keyword in a FitsChan. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * void astSetFitsCom( AstFitsChan *this, const char *name, * const char *comment, int overwrite ) * Class Membership: * FitsChan method. * Description: * This function replaces the comment within an existing card, or * stores a new comment card within a FitsChan. * Parameters: * this * Pointer to the FitsChan. * name * A pointer to a * string holding the keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. * comment * A pointer to a * string holding a comment to associated with the keyword. * If a NULL or * blank string is supplied, any existing comment associated with * the keyword is removed. * overwrite * If non-zero, the new comment replaces the comment in the current * card, and the current card is then incremented to refer to the next * card. If zero, a new comment card is inserted in front of the current * card and the current card is left unchanged. In either case, if the * current card on entry points to the "end-of-file", the new card is * appended to the end of the list. * Notes: * - When replacing an existing comment, any existing keyword value is * retained only if the supplied keyword name is the same as the keyword * name in the current card. If the keyword names are different, then * the new name replaces the old name, and any existing keyword data value * is deleted. The card thus becomes a comment card with the supplied * keyword name and comment, but no data value. * - If, on exit, there are no cards following the card written by * this function, then the current card is left pointing at the * "end-of-file". * - The current card can be set explicitly before calling this function * either by assigning a value to the Card attribute (if the index of the * required card is already known), or using astFindFits (if only the * keyword name is known). * - An error will be reported if the keyword name does not conform * to FITS requirements. *- */ /* Local variables: */ const char *class; /* Pointer to object class string */ const char *method; /* Pointer to calling method string */ const char *cname; /* The existing keyword name */ const char *com; /* The comment to use */ char *lcom; /* Supplied keyword comment */ char *lname; /* Supplied keyword name */ char *lvalue; /* Supplied keyword value */ void *old_data; /* Pointer to the old data value */ void *data; /* Pointer to data value to be stored */ size_t size; /* The size of the data value */ /* Check the global error status. */ if ( !astOK ) return; /* Initialisation */ size = 0; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the calling method and object class. */ method = "astSetFitsCom"; class = astGetClass( this ); /* Extract the keyword name, etc, from the supplied string. */ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); /* If a blank comment has been supplied, use NULL instead. */ com = ChrLen( comment, status )? comment : NULL; /* If we are inserting a new card, or over-writing an old card with a different name, create and store a comment card with the given keyword name and comment, but no data value. */ cname = CardName( this, status ); if( !overwrite || !cname || strcmp( lname, cname ) ){ InsCard( this, overwrite, lname, AST__COMMENT, NULL, com, method, class, status ); /* If we are overwriting an existing keyword comment, use the data type and value from the existing current card. Note, we have to take a copy of the old data value because InsCard over-writes by deleting the old card and then inserting a new one. */ } else { old_data = CardData( this, &size, status ); data = astStore( NULL, old_data, size ); InsCard( this, 1, lname, CardType( this, status ), data, com, method, class, status ); data = astFree( data ); } /* Release the memory used to hold keyword name, value and comment strings. */ lname = (char *) astFree( (void *) lname ); lvalue = (char *) astFree( (void *) lvalue ); lcom = (char *) astFree( (void *) lcom ); } static void FixNew( AstFitsChan *this, int flag, int remove, const char *method, const char *class, int *status ){ /* * * Name: * FixNew * Purpose: * Remove "new" flags from the whole FitsChan, and optionally remove * "new" cards. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FixNew( AstFitsChan *this, int flag, int remove, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan method. * Description: * This function searches the entire FitsChan for cards which are * marked as new using the supplied flag (NEW1 or NEW2). If "remove" * is non-zero, these cards are completely removed from the FitsChan * (not just marked as used). If "remove" is zero, they are retained * and the specified flag is cleared. * Parameters: * this * Pointer to the FitsChan. * flag * The flag to use; NEW1 or NEW2. * remove * Remove flagged cards from the FitsChan? * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This function attempts to execute even if an error has occurred. * - If any cards are removed, the current Card is left at "end-of-file" * on exit. If no cards are removed, the original current card is * retained. *- */ /* Local Variables: */ int *flags; /* Pointer to flags mask for the current card */ int icard; /* Index of current card on entry */ int ndeleted; /* Number of cards deleted by this call */ /* Return if no FitsChan was supplied, or if the FitsChan is empty. */ if ( !this || !this->head ) return; /* Save the current card index, and rewind the FitsChan. */ icard = astGetCard( this ); astClearCard( this ); /* Indicate no cards have yet been deleted. */ ndeleted = 0; /* Loop through the list of FitsCards in the FitsChan until the final card is reached. */ while( astOK && this->card ){ /* Get a pointer to the flags mask for this card. */ flags = CardFlags( this, status ); /* See if the Card has been marked with the requeste new flag. */ if( flags && ( (*flags) & flag ) ) { /* If requested, remove the card. This will automatically move the current card on to the next card. */ if( remove ){ DeleteCard( this, method, class, status ); ndeleted++; /* Otherwise, clear the flag. */ } else { *flags = (*flags) & ~flag; /* Increment the card count and move on to the next card. */ MoveCard( this, 1, method, class, status ); } /* Move on to the next card if this card is not marked with the requested new flag. */ } else { MoveCard( this, 1, method, class, status ); } } /* If no cards were removed, we can safely re-instate the original current card. Otherwise, the current card is left at "end-of-file". */ if( ndeleted == 0 ) astSetCard( this, icard ); /* Return */ return; } static void FixUsed( AstFitsChan *this, int reset, int used, int remove, const char *method, const char *class, int *status ){ /* * * Name: * FixUsed * Purpose: * Remove "provisionally used" flags from the whole FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FixUsed( AstFitsChan *this, int reset, int used, int remove, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan method. * Description: * This function searches the entire FitsChan for cards which are * marked as "provisionally used". The "provisionally used" flag is * cleared for each such card. In addition, if "used" is non-zero then * each such card is flagged as having been "definitely used". If * "remove" is non-zero, then all "provisionally used" cards are deleted * from the FitsChan. * Parameters: * this * Pointer to the FitsChan. * reset * Set all cards so that they are neither provisionally used or * definitely used. In this case neither the "used" nor the * "remove" parameter are accssed. * used * Have the provisionally used cards definitely been used? * remove * Should provisionally used cards be deleted? * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - This function attempts to execute even if an error has occurred. *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ FitsCard *card0; /* Pointer to current FitsCard */ int *flags; /* Pointer to flags mask for the current card */ int old_ignore_used; /* Original value of variable ignore_used */ int old_status; /* Original inherited status value */ int rep; /* Original error reporting flag */ /* Return if no FitsChan was supplied, or if the FitsChan is empty. */ if ( !this || !this->head ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Temporarily clear any bad status value and supress error reporting in this function. */ old_status = astStatus; astClearStatus; rep = astReporting( 0 ); /* Indicate that we should not skip over cards marked as having been read. */ old_ignore_used = ignore_used; ignore_used = 0; /* Save a pointer to the current card, and the reset the current card to be the first card. */ card0 = this->card; astClearCard( this ); /* Loop through the list of FitsCards in the FitsChan until the final card is reached. */ while( this->card ){ /* Get a pointer to the flags mask for this card. */ flags = CardFlags( this, status ); /* Reset both used flags if required. */ if( reset ) { *flags = (*flags) & ~PROVISIONALLY_USED; *flags = (*flags) & ~USED; MoveCard( this, 1, method, class, status ); /* Otherwise perform the actions indicated by parameters "used" and "remove". */ } else { /* See if the Card has been provisionally used. */ if( flags && ( (*flags) & PROVISIONALLY_USED ) ) { /* Clear the provisionally used flag. */ *flags = (*flags) & ~PROVISIONALLY_USED; /* If required, set the definitely used flag. */ if( used ) *flags = (*flags) | USED; /* If required, delete the card. The next card is made current. If we are about to delete the original current card, we need to update the pointer to the card to be made current at the end of this function. If we end up back at the head of the chain, indicate that we have reached the end of file by setting card0 NULL. */ if( remove ) { if( card0 == this->card && card0 ) { card0 = ( (FitsCard *) this->card )->next; if( (void *) card0 == this->head ) card0 = NULL; } DeleteCard( this, method, class, status ); /* Otherwise, just move on to the next card. */ } else { MoveCard( this, 1, method, class, status ); } /* If this card has not bee provisionally used, move on to the next card. */ } else { MoveCard( this, 1, method, class, status ); } } } /* Re-instate the original current card. */ this->card = card0; /* If this card is now flagged as definitely used, move forward to the next un-used card. */ flags = CardFlags( this, status ); if( flags && (*flags & USED ) ) { ignore_used = 1; MoveCard( this, 1, method, class, status ); } /* Re-instate the original flag indicating if cards marked as having been read should be skipped over. */ ignore_used = old_ignore_used; /* Re-instate the original status value and error reporting condition. */ astReporting( rep ); astSetStatus( old_status ); } static void FormatCard( AstFitsChan *this, char *buf, const char *method, int *status ){ /* * * Name: * FormatCard * Purpose: * Formats the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void FormatCard( AstFitsChan *this, char *buf, const char *method, int *status ) * Class Membership: * FitsChan method. * Description: * This function write the current card into the supplied character * buffer as a complete FITS header card. * Parameters: * this * Pointer to the FitsChan. * buf * A character string into which the header card is written. This * should be at least 81 characters long. The returned string is * padded with spaces upto column 80. A terminating null character * is added. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - An error is reported if the requested header card does not conform to * FITS standards. * */ /* Local Variables: */ const char *com; /* Pointer to comment string to use */ int comlen; /* Length of comment string */ int comstart; /* Column in which to start comment */ int i; /* Loop counter for characters */ int len; /* Output string length */ int digits; /* No. of digits to use when formatting floating point values */ int type; /* Card data type */ /* Check the global error status, and check the current card is defined. */ if ( !astOK || astFitsEof( this ) ) return; /* Get a pointer to the comment to use and determine its length. */ com = CardComm( this, status ); comlen = ChrLen( com, status ); /* Copy the keyword name to the start of the output buffer, and store its length. */ len = (int) strlen( strcpy( buf, CardName( this, status ) ) ); /* Pad the name with spaces up to column 8. */ while ( len < FITSNAMLEN ) buf[ len++ ] = ' '; /* If the card contains a keyword value... */ type = CardType( this, status ); if( type != AST__COMMENT ){ /* Get the number of digits to use when formatting floating point values. */ digits = astGetFitsDigits( this ); /* Put an equals sign in column 9 (or a space if the keyword is a CONTINUE card), followed by a space in column 10. */ buf[ len++ ] = ( type == AST__CONTINUE ) ? ' ' : '='; buf[ len++ ] = ' '; /* Format and store the keyword value, starting at column 11 and update the output string length. */ len += EncodeValue( this, buf + len, FITSNAMLEN + 3, digits, method, status ); /* If there is a comment, determine which column it should start in so that it ends in column 80. */ if( com ){ comstart = AST__FITSCHAN_FITSCARDLEN - ( comlen - 2 ) + 1; /* Adjust the starting column to 32 if possible, avoiding over-writing the value, or running off the end of the card unless this is unavoidable. */ if ( comstart > FITSCOMCOL ) comstart = FITSCOMCOL; if ( comstart < len + 2 ) comstart = len + 2; /* Pad the output buffer with spaces up to the start of the comment. */ while ( len < comstart - 1 ) buf[ len++ ] = ' '; /* Then append "/ " to introduce the comment, truncating if the card length forces this. */ for ( i = 0; ( i < 2 ) && ( len < AST__FITSCHAN_FITSCARDLEN ); i++ ) { buf[ len++ ] = "/ "[ i ]; } } } /* Append any comment, truncating it if the card length forces this. */ if ( com ) { for ( i = 0; com[ i ] && ( len < AST__FITSCHAN_FITSCARDLEN ); i++ ) { buf[ len++ ] = com[ i ]; } } /* Pad with spaces up to the end of the card. */ while ( len < AST__FITSCHAN_FITSCARDLEN ) buf[ len++ ] = ' '; /* Terminate it. */ buf[ AST__FITSCHAN_FITSCARDLEN ] = 0; } static int FullForm( const char *list, const char *test, int abbrev, int *status ){ /* * Name: * FullForm * Purpose: * Identify the full form of an option string. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int FullForm( const char *list, const char *test, int abbrev, int *status ) * Class Membership: * FitsChan method. * Description: * This function identifies a supplied test option within a supplied * list of valid options, and returns the index of the option within * the list. The test option may be abbreviated, and case is * insignificant. * Parameters: * list * A list of space separated option strings. * test * A candidate option string. * abbrev * 1 if abbreviations are to be accepted. Zero otherwise. * status * Pointer to the inherited status variable. * Returned Value: * The index of the identified option within the supplied list, starting * at zero. -1 is returned if the option is not recognised, and (if * abbrev is 1 ) -2 if the option is ambiguous (no errors are reported * in these cases). If abbrev is zero, the returned index will be the * index of the first matching string. * * Notes: * - A value of -1 is returned if an error has already occurred, or * if this function should fail for any reason. */ /* Local Variables: */ char *context; /* Context used by strtok_r */ char *llist; /* Pointer to a local copy of the options list */ char *option; /* Pointer to the start of the next option */ int i; /* Current option index */ int len; /* Length of supplied option */ int nmatch; /* Number of matching options */ int ret; /* The returned index */ /* Initialise the answer to indicate that the option has not been identified. */ ret = -1; /* Avoid compiler warnings. */ context = NULL; /* Check global status. */ if( !astOK ) return ret; /* Take a local copy of the supplied options list. This is necessary since "strtok" modified the string by inserting null characters. */ llist = (char *) astStore( NULL, (void *) list, strlen(list) + 1 ); if( astOK ){ /* Save the number of characters in the supplied test option (excluding trailing spaces). */ len = ChrLen( test, status ); /* Compare the supplied test option against each of the known options in turn. Count the number of matches. */ nmatch = 0; #if HAVE_STRTOK_R option = strtok_r( llist, " ", &context ); #else option = strtok( llist, " " ); #endif i = 0; while( option ){ /* If every character in the supplied label matches the corresponding character in the current test label we have a match. Increment the number of matches and save the current item index. If abbreviation is not allowed ensure that the lengths of the strings are equal. */ if( !Ustrncmp( test, option, len, status ) && ( abbrev || len == ChrLen( option, status ) ) ) { nmatch++; ret = i; if( !abbrev ) break; } /* Get a pointer to the next option. */ #if HAVE_STRTOK_R option = strtok_r( NULL, " ", &context ); #else option = strtok( NULL, " " ); #endif i++; } /* Return -1 if no match was found. */ if( !nmatch ){ ret = -1; /* Return -2 if the option was ambiguous. */ } else if( abbrev && nmatch > 1 ){ ret = -2; } /* Free the local copy of the options list. */ llist = (char *) astFree( (void *) llist ); } /* Return the answer. */ return ret; } static const char *GetAllWarnings( AstFitsChan *this, int *status ){ /* *+ * Name: * astGetAllWarnings * Purpose: * Return a list of all condition names. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * const char *GetAllWarnings( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function returns a space separated lits of the condition names * currently recognized by the Warnings attribute. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * A pointer to a static string holding the condition names. * Notes: * - This routine does not check the inherited status. *- */ /* Return the result. */ return ALLWARNINGS; } const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * FitsChan member function (over-rides the protected astGetAttrib * method inherited from the Channel class). * Description: * This function returns a pointer to the value of a specified * attribute for a FitsChan, formatted as a character string. * Parameters: * this * Pointer to the FitsChan. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the FitsChan, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the FitsChan. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure */ const char *result; /* Pointer value to return */ int ival; /* Integer attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Card. */ /* ----- */ if ( !strcmp( attrib, "card" ) ) { ival = astGetCard( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* CardComm. */ /* --------- */ } else if ( !strcmp( attrib, "cardcomm" ) ) { result = astGetCardComm( this ); /* CardName. */ /* --------- */ } else if ( !strcmp( attrib, "cardname" ) ) { result = astGetCardName( this ); /* CardType. */ /* --------- */ } else if ( !strcmp( attrib, "cardtype" ) ) { ival = astGetCardType( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Encoding. */ /* --------- */ } else if ( !strcmp( attrib, "encoding" ) ) { ival = astGetEncoding( this ); if ( astOK ) { if( ival == NATIVE_ENCODING ){ result = NATIVE_STRING; } else if( ival == FITSPC_ENCODING ){ result = FITSPC_STRING; } else if( ival == FITSIRAF_ENCODING ){ result = FITSIRAF_STRING; } else if( ival == FITSAIPS_ENCODING ){ result = FITSAIPS_STRING; } else if( ival == FITSAIPSPP_ENCODING ){ result = FITSAIPSPP_STRING; } else if( ival == FITSCLASS_ENCODING ){ result = FITSCLASS_STRING; } else if( ival == FITSWCS_ENCODING ){ result = FITSWCS_STRING; } else if( ival == DSS_ENCODING ){ result = DSS_STRING; } else { result = UNKNOWN_STRING; } } /* CDMatrix */ /* -------- */ } else if ( !strcmp( attrib, "cdmatrix" ) ) { ival = astGetCDMatrix( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* DefB1950 */ /* -------- */ } else if ( !strcmp( attrib, "defb1950" ) ) { ival = astGetDefB1950( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* TabOK */ /* ----- */ } else if ( !strcmp( attrib, "tabok" ) ) { ival = astGetTabOK( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* CarLin */ /* ------ */ } else if ( !strcmp( attrib, "carlin" ) ) { ival = astGetCarLin( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* PolyTan */ /* ------- */ } else if ( !strcmp( attrib, "polytan" ) ) { ival = astGetPolyTan( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Iwc */ /* --- */ } else if ( !strcmp( attrib, "iwc" ) ) { ival = astGetIwc( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Clean */ /* ----- */ } else if ( !strcmp( attrib, "clean" ) ) { ival = astGetClean( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* FitsDigits. */ /* ----------- */ } else if ( !strcmp( attrib, "fitsdigits" ) ) { ival = astGetFitsDigits( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Ncard. */ /* ------ */ } else if ( !strcmp( attrib, "ncard" ) ) { ival = astGetNcard( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* Nkey. */ /* ----- */ } else if ( !strcmp( attrib, "nkey" ) ) { ival = astGetNkey( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* AllWarnings */ /* ----------- */ } else if ( !strcmp( attrib, "allwarnings" ) ) { result = astGetAllWarnings( this ); /* Warnings. */ /* -------- */ } else if ( !strcmp( attrib, "warnings" ) ) { result = astGetWarnings( this ); /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } static int GetCard( AstFitsChan *this, int *status ){ /* *+ * Name: * astGetCard * Purpose: * Get the value of the Card attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astGetCard( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function returns the value of the Card attribute for the supplied * FitsChan. This is the index of the next card to be read from the * FitsChan. The index of the first card is 1. If there are no more * cards to be read, a value one greater than the number of cards in the * FitsChan is returned. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * The index of the next card to be read. * Notes: * - A value of zero will be returned if the current card is not defined. * - This function attempts to execute even if an error has occurred. *- */ /* Local Variables: */ const char *class; /* Pointer to class string */ const char *method; /* Pointer to method string */ FitsCard *card0; /* Pointer to current FitsCard */ int index; /* Index of next FitsCard */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return if no FitsChan was supplied, or if the FitsChan is empty. */ if ( !this || !this->head ) return 0; /* Store the method and object class. */ method = "astGetCard"; class = astGetClass( this ); /* Save a pointer to the current card, and the reset the current card to be the first card. */ card0 = this->card; astClearCard( this ); /* Count through the list of FitsCards in the FitsChan until the original current card is reached. If the current card is not found (for instance if it has been marked as deleted and we are currently skipping such cards), this->card will be left null (end-of-file). */ index = 1; while( this->card != card0 && astOK && this->card ){ /* Increment the card count and move on to the next card. */ index++; MoveCard( this, 1, method, class, status ); } /* Return the card index. */ return index; } static const char *GetCardComm( AstFitsChan *this, int *status ){ /* *+ * Name: * GetCardComm * Purpose: * Get the value of the CardComm attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * const char *astGetCardComm( AstFitsChan *this) * Class Membership: * FitsChan method. * Description: * This function returns the value of the CardComm attribute for the * supplied FitsChan. This is the comment for the current card. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * A pointer to a static string holding the comment. A zero-length * string is returned if the card has no comment. * Notes: * - A value of NULL will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables */ const char *result = NULL; /* Check inherited status */ if( !astOK ) return result; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Get the comment for the current card. */ result = CardComm( this, status ); /* Return a zero-length string if the card has no comment. */ if( astOK && !result ) result = ""; /* Return the comment. */ return result; } static const char *GetCardName( AstFitsChan *this, int *status ){ /* *+ * Name: * GetCardName * Purpose: * Get the value of the CardName attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * const char *astGetCardName( AstFitsChan *this) * Class Membership: * FitsChan method. * Description: * This function returns the value of the CardName attribute for the * supplied FitsChan. This is the keyword name for the current card. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * A pointer to a static string holding the keyword name. * Notes: * - A value of NULL will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return the keyword name of the current card. */ return CardName( this, status ); } static int GetCardType( AstFitsChan *this, int *status ){ /* *+ * Name: * GetCardType * Purpose: * Get the value of the CardType attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astGetCardType( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function returns the value of teh CardType attribute for the supplied * FitsChan. This is the data type of the keyword value for the current card. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * An integer representing the data type of the current card. * Notes: * - A value of AST__NOTYPE will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return the data type of the current card. */ return CardType( this, status ); } static int GetFull( AstChannel *this_channel, int *status ) { /* * Name: * GetFull * Purpose: * Obtain the value of the Full attribute for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetFull( AstChannel *this, int *status ) * Class Membership: * FitsChan member function (over-rides the protected astGetFull * method inherited from the Channel class). * Description: * This function return the integer value of the Full attribute for * a FitsChan. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The Full attribute value. * Notes: * - This function modifies the default Full value from 0 to -1 for * the benefit of the FitsChan class. This prevents non-essential * information being written by the astWrite method unless it is * requested by explicitlt setting a Full value. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ int result; /* Result value to return */ /* Check the global error status. */ if ( !astOK ) return 0; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* If the Full attribute us set, obtain its value using the parent class method. */ if ( astTestFull( this ) ) { result = (* parent_getfull)( this_channel, status ); /* Otherwise, supply a default value of -1. */ } else { result = -1; } /* Return the result. */ return result; } static FitsCard *GetLink( FitsCard *card, int next, const char *method, const char *class, int *status ){ /* * Name: * GetLink * Purpose: * Get a pointer to the next or previous card in the list. * Type: * Private function. * Synopsis: * #include "fitschan.h" * FitsCard *GetLink( FitsCard *card, int next, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns the a pointer to either the next or previous FitsCard * structure in the circular linked list of such structures stored in a * FitsChan. A check is performed to ensure that the forward and * backward links from the supplied card are consistent and an error * is reported if they are not (so long as no previous error has been * reported). Memory corruption can result in inconsistent links * which can result in infinite loops if an attempt is made to scan the * list. * Parameters: * card * The current card. * next * If non-zero, a pointer to the "next" card is returned. Otherwise * a pointer to the "previous" card is returned. * method * Pointer to string holding the name of the calling method. * class * Pointer to string holding the object class. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the required card, or NULL if an error occurs. * Notes: * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ FitsCard *ret; /* Pointer to the returned card */ /* Check that the "next" link from the previous card points back to the current card, and that the "prev" link from the next card points back to the current card. */ if( card && ( card->prev->next != card || card->next->prev != card ) ){ /* Report an error so long as no previous error has been reported, and return a NULL pointer. */ if( astOK ){ astError( AST__FCRPT, "%s(%s): A corrupted %s object has been " "supplied.", status, method, class, class ); } ret = NULL; /* If the links are good, return a pointer to the required card. */ } else { ret = next ? card->next : card->prev; } /* Return the result. */ return ret; } static int GetNcard( AstFitsChan *this, int *status ){ /* *+ * Name: * astGetNcard * Purpose: * Get the value of the Ncard attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astGetNcard( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function returns the value of the Ncard attribute for the supplied * FitsChan. This is the number of cards currently in the FitsChan. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * The number of cards currently in the FitsChan. * Notes: * - A value of zero will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ const char *class; /* Pointer to class string */ const char *method; /* Pointer to method string */ FitsCard *card0; /* Pointer to current card on entry */ int ncard; /* Number of cards so far */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return zero if an error has already occurred, or no FitsChan was supplied, or the FitsChan is empty. */ if ( !astOK || !this || !this->head ) return 0; /* Store the method and object class. */ method = "astGetNcard"; class = astGetClass( this ); /* Save a pointer to the current card, and then reset the current card to be the first card. */ card0 = this->card; astClearCard( this ); /* Count through the cards in the FitsChan until the end of file is reached. */ ncard = 0; while( astOK && this->card ){ /* Increment the card count and move on to the next card. */ ncard++; MoveCard( this, 1, method, class, status ); } /* Reset the current card to be the original current card. */ this->card = card0; /* Return the result. */ return astOK ? ncard : 0; } static int GetNkey( AstFitsChan *this, int *status ){ /* *+ * Name: * astGetNkey * Purpose: * Get the value of the Nkey attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astGetNkey( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function returns the value of the Nkey attribute for the supplied * FitsChan. This is the number of unique keywords currently in the * FitsChan. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * The number of unique keywords currently in the FitsChan. * Notes: * - A value of zero will be returned if an error has already * occurred, or if this function should fail for any reason. *- */ /* Local Variables: */ AstKeyMap *km; /* KeyMap holding unique keyword names */ FitsCard *card0; /* Pointer to current card on entry */ const char *class; /* Pointer to class string */ const char *method; /* Pointer to method string */ int nkey; /* Returned Nkey value */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return zero if an error has already occurred, or no FitsChan was supplied, or the FitsChan is empty. */ if ( !astOK || !this || !this->head ) return 0; /* Store the method and object class. */ method = "astGetNkey"; class = astGetClass( this ); /* Create an empty KeyMap to hold the unused keyword names */ km = astKeyMap( " ", status ); /* Save a pointer to the current card, and then reset the current card to be the first card. */ card0 = this->card; astClearCard( this ); /* Loop through the cards in the FitsChan until the end of file is reached. */ while( astOK && this->card ){ /* Get the keyword name for the current card and add it to the keymap. */ astMapPut0I( km, CardName( this, status ), 0, NULL ); /* Move on to the next unused card. */ MoveCard( this, 1, method, class, status ); } /* Reset the current card to be the original current card. */ this->card = card0; /* Get the number of keywords. */ nkey = astMapSize( km ); /* Annull the KeyMap . */ km = astAnnul( km ); /* Return the result. */ return astOK ? nkey : 0; } static void GetNextData( AstChannel *this_channel, int skip, char **name, char **val, int *status ) { /* * Name: * GetNextData * Purpose: * Read the next item of data from a data source. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void GetNextData( AstChannel *this, int skip, char **name, char **val ) * Class Membership: * FitsChan member function (over-rides the protected * astGetNextData method inherited from the Channel class). * Description: * This function reads the next item of input data from a data * source associated with a FitsChan and returns the result. It * decodes the data item and returns name/value pairs ready for * use. * Parameters: * this * Pointer to the FitsChan. * skip * A non-zero value indicates that a new Object is to be read, * and that all input data up to the next "Begin" item are to be * skipped in order to locate it. This is useful if the data * source contains AST objects interspersed with other data (but * note that these other data cannot appear inside AST Objects, * only between them). * * A zero value indicates that all input data are significant * and the next item will therefore be read and an attempt made * to interpret it whatever it contains. Any other data * inter-mixed with AST Objects will then result in an error. * name * An address at which to store a pointer to a null-terminated * dynamically allocated string containing the name of the next * item in the input data stream. This name will be in lower * case with no surrounding white space. It is the callers * responsibilty to free the memory holding this string (using * astFree) when it is no longer required. * * A NULL pointer value will be returned (without error) to * indicate when there are no further input data items to be * read. * val * An address at which to store a pointer to a null-terminated * dynamically allocated string containing the value associated * with the next item in the input data stream. No case * conversion is performed on this string and all white space is * potentially significant. It is the callers responsibilty to * free the memory holding this string (using astFree) when it * is no longer required. * * The returned pointer will be NULL if an Object data item is * read (see the "Data Representation" section). * Data Representation: * The returned data items fall into the following categories: * * - Begin: Identified by the name string "begin", this indicates * the start of an Object definition. The associated value string * gives the class name of the Object being defined. * * - IsA: Identified by the name string "isa", this indicates the * end of the data associated with a particular class structure * within the definiton of a larger Object. The associated value * string gives the name of the class whose data have just been * read. * * - End: Identified by the name string "end", this indicates the * end of the data associated with a complete Object * definition. The associated value string gives the class name of * the Object whose definition is being ended. * * - Non-Object: Identified by any other name string plus a * non-NULL "val" pointer, this gives the value of a non-Object * structure component (instance variable). The name identifies * which instance variable it is (within the context of the class * whose data are being read) and the value is encoded as a string. * * - Object: Identified by any other name string plus a NULL "val" * pointer, this identifies the value of an Object structure * component (instance variable). The name identifies which * instance variable it is (within the context of the class whose * data are being read) and the value is given by subsequent data * items (so the next item should be a "Begin" item). * Notes: * - NULL pointer values will be returned if this function is * invoked with the global error status set, or if it should fail * for any reason. */ /* Local Constants: */ #define BUFF_LEN 100 /* Length of formatting buffer */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ char *keyword; /* Pointer to current keyword string */ char *newdata; /* Pointer to stripped string value */ char *upq; /* Pointer to unprequoted string */ char buff[ BUFF_LEN + 1 ]; /* Buffer for formatting values */ const char *class; /* Pointer to object class */ const char *method; /* Pointer to method name */ int cont; /* String ends with an ampersand? */ int done; /* Data item found? */ int freedata; /* Should the data pointer be freed? */ int i; /* Loop counter for keyword characters */ int len; /* Length of current keyword */ int nc; /* Number of characters read by "astSscanf" */ int nn; /* No. of characters after UnPreQuoting */ int type; /* Data type code */ void *data; /* Pointer to current data value */ /* Initialise the returned pointer values. */ *name = NULL; *val = NULL; /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Store the method name and object class. */ method = "astRead"; class = astGetClass( this ); /* Loop to consider successive cards stored in the FitsChan (starting at the "current" card) until a valid data item is read or "end of file" is reached. Also quit the loop if an error occurs. */ done = 0; newdata = NULL; while ( !done && !astFitsEof( this ) && astOK ){ /* Obtain the keyword string, data type code and data value pointer from the current card. */ keyword = CardName( this, status ); type = CardType( this, status ); data = CardData( this, NULL, status ); /* Mark all cards as having been used unless we are skipping over cards which may not be related to AST. */ if( !skip ) MarkCard( this, status ); /* Ignore comment cards. */ if ( type != AST__COMMENT ) { /* Native encoding requires trailing white space to be removed from string values (so that null strings can be distinguished from blank strings). Do this now. */ freedata = 0; if ( ( type == AST__STRING || type == AST__CONTINUE ) && data ){ newdata = (char *) astStore( NULL, data, strlen( (char *) data ) + 1 ); if( newdata ){ newdata[ ChrLen( data, status ) ] = 0; data = (void *) newdata; freedata = 1; } } /* Obtain the keyword length and test the card to identify the type of AST data item (if any) that it represents. */ len = (int) strlen( keyword ); /* "Begin" item. */ /* ------------- */ /* This is identified by a string value and a keyword of the form "BEGASTxx", where "xx" are characters encoding a sequence number. */ if ( ( type == AST__STRING ) && ( nc = 0, ( 0 == astSscanf( keyword, "BEGAST" "%*1[" SEQ_CHARS "]" "%*1[" SEQ_CHARS "]%n", &nc ) ) && ( nc >= len ) ) ) { /* Note we have found a data item. */ done = 1; /* Set the returned name to "begin" and extract the associated class name from the string value. Store both of these in dynamically allocated strings. */ *name = astString( "begin", 5 ); *val = UnPreQuote( (const char *) data, status ); /* Indicate that the current card has been used. */ MarkCard( this, status ); /* The "begin" item will be preceded by a header of COMMENT cards. Mark them as having been used. */ ComBlock( this, -1, method, class, status ); /* "IsA" item. */ /* ----------- */ /* This is identified by a string value and a keyword of the form "ISAxx", where "xx" are characters encoding a sequence number. Don't accept the item if we are skipping over cards looking for a "Begin" item. */ } else if ( !skip && ( type == AST__STRING ) && ( nc = 0, ( 0 == astSscanf( keyword, "ISA" "%*1[" SEQ_CHARS "]" "%*1[" SEQ_CHARS "]%n", &nc ) ) && ( nc >= len ) ) ) { /* Note we have found a data item. */ done = 1; /* Set the returned name to "isa" and extract the associated class name from the string value. Store both of these in dynamically allocated strings. */ *name = astString( "isa", 3 ); *val = UnPreQuote( (const char *) data, status ); /* "End" item. */ /* ----------- */ /* This is identified by a string value and a keyword of the form "ENDASTxx", where "xx" are characters encoding a sequence number. Don't accept the item if we are skipping over cards looking for a "Begin" item. */ } else if ( !skip && ( type == AST__STRING ) && ( nc = 0, ( 0 == astSscanf( keyword, "ENDAST" "%*1[" SEQ_CHARS "]" "%*1[" SEQ_CHARS "]%n", &nc ) ) && ( nc >= len ) ) ) { /* Note we have found a data item. */ done = 1; /* Set the returned name to "end" and extract the associated class name from the string value. Store both of these in dynamically allocated strings. */ *name = astString( "end", 3 ); *val = UnPreQuote( (const char *) data, status ); /* The "end" item eill be followed by a footer of COMMENT cards. Mark these cards as having been used. */ ComBlock( this, 1, method, class, status ); /* Object or data item. */ /* -------------------- */ /* These are identified by a string, int, or double value, and a keyword ending in two characters encoding a sequence number. Don't accept the item if we are skipping over cards looking for a "Begin" item. */ } else if ( !skip && ( ( type == AST__STRING ) || ( type == AST__INT ) || ( type == AST__FLOAT ) ) && ( len > 2 ) && strchr( SEQ_CHARS, keyword[ len - 1 ] ) && strchr( SEQ_CHARS, keyword[ len - 2 ] ) ) { /* Note we have found a data item. */ done = 1; /* Set the returned name by removing the last two characters from the keyword and converting to lower case. Store this in a dynamically allocated string. */ *name = astString( keyword, len - 2 ); for ( i = 0; ( *name )[ i ]; i++ ) { ( *name )[ i ] = tolower( ( *name )[ i ] ); } /* Classify the data type. */ switch ( type ) { /* If the value is a string, test if it is zero-length. If so, this "null" value indicates an Object data item (whose definition follows), so leave the returned value pointer as NULL. Otherwise, we have a string data item, so extract its value and store it in a dynamically allocated string. */ case AST__STRING: if ( *( (char *) data ) ) { /* A long string value may be continued on subsequent CONTINUE cards. See if the current string may be continued. This is the case if the final non-blank character (before UnPreQuoting) is an ampersand. */ cont = ( ((char *) data)[ ChrLen( data, status ) - 1 ] == '&' ); /* If the string does not end with an ampersand, just UnPreQUote it and return a copy. */ if( !cont ) { *val = UnPreQuote( (const char *) data, status ); /* Otherwise, initialise the returned string to hold a copy of the keyword value. */ } else { nc = strlen( (const char *) data ); *val = astStore( NULL, (const char *) data, nc + 1 ); /* Loop round reading any subsequent CONTINUE cards. Leave the loop when the end-of-file is hit, or an error occurs. */ while( cont && MoveCard( this, 1, method, class, status ) && astOK ){ /* See if this is a CONTINUE card. If so, get its data pointer. */ if( CardType( this, status ) == AST__CONTINUE ){ data = CardData( this, NULL, status ); /* See if the CONTINUE card ends with an ampersand (i.e. if there is a possibility of there being any remaining CONTINUE cards). */ cont = ( ( (char *) data)[ ChrLen( data, status ) - 1 ] == '&' ); /* UnPreQUote it. */ upq = UnPreQuote( (const char *) data, status ); if( !astOK ) break; /* Expand the memory for the returned string to hold the new string. */ nn = strlen( upq ); *val = astRealloc( *val, nc + nn ); if( !astOK ) break; /* Copy the new string into the expanded memory, so that the first character of the new string over-writes the trailing ampersand currently in the buffer. */ strcpy( *val + nc - 1, upq ); /* Release the memory holding the UnPreQUoted string . */ upq = astFree( upq ); /* Update the current length of the returned string. */ nc += nn - 1; /* Mark the current card as having been read. */ MarkCard( this, status ); /* Report an error if this is not a CONTINUE card. */ } else { astError( AST__BADIN, "%s(%s): One or more " "FITS \"CONTINUE\" cards are missing " "after the card for keyword \"%s\".", status, method, class, keyword ); } } } } break; /* If the value is an int, format it and store the result in a dynamically allocated string. */ case AST__INT: (void) sprintf( buff, "%d", *( (int *) data ) ); *val = astString( buff, (int) strlen( buff ) ); break; /* If the value is a double, format it and store the result in a dynamically allocated string. */ case AST__FLOAT: (void) sprintf( buff, "%.*g", DBL_DIG, *( (double *) data ) ); CheckZero( buff, *( (double *) data ), 0, status ); *val = astString( buff, (int) strlen( buff ) ); break; } /* Anything else. */ /* -------------- */ /* If the input line didn't match any of the above and the "skip" flag is not set, then report an error.. */ } else if ( !skip ) { astError( AST__BADIN, "%s(%s): Cannot interpret the input data given by " "FITS keyword \"%s\".", status, method, class, keyword ); } /* Free any memory used to hold stripped string data. */ if( freedata ) newdata = (char *) astFree( (void *) newdata ); } /* Increment the current card. */ MoveCard( this, 1, method, class, status ); } /* If an error occurred, ensure that any allocated memory is freed and that NULL pointer values are returned. */ if ( !astOK ) { *name = astFree( *name ); *val = astFree( *val ); } /* Undefine macros local to this function. */ #undef BUFF_LEN } static int GetSkip( AstChannel *this_channel, int *status ) { /* * Name: * GetSkip * Purpose: * Obtain the value of the Skip attribute for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int GetSkip( AstChannel *this, int *status ) * Class Membership: * FitsChan member function (over-rides the protected astGetSkip * method inherited from the Channel class). * Description: * This function return the (boolean) integer value of the Skip * attribute for a FitsChan. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * The Skip attribute value. * Notes: * - This function modifies the default Skip value from 0 to 1 for * the benefit of the FitsChan class. This default value allows the * astRead method to skip over unrelated FITS keywords when * searching for the next Object to read. * - A value of zero will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ int result; /* Result value to return */ /* Check the global error status. */ if ( !astOK ) return 0; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* If the Skip attribute us set, obtain its value using the parent class method. */ if ( astTestSkip( this ) ) { result = (* parent_getskip)( this_channel, status ); /* Otherwise, supply a default value of 1. */ } else { result = 1; } /* Return the result. */ return result; } static int GetValue( AstFitsChan *this, const char *keyname, int type, void *value, int report, int mark, const char *method, const char *class, int *status ){ /* * Name: * GetValue * Purpose: * Obtain a FITS keyword value. * Type: * Private function. * Synopsis: * int GetValue( AstFitsChan *this, const char *keyname, int type, void *value, * int report, int mark, const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function gets a value for the specified keyword from the * supplied FitsChan, and stores it in the supplied buffer. Optionally, * the keyword is marked as having been read into an AST object so that * it is not written out when the FitsChan is deleted. * Parameters: * this * A pointer to the FitsChan containing the keyword values to be * read. * keyname * A pointer to a string holding the keyword name. * type * The FITS data type in which to return the keyword value. If the * stored value is not of the requested type, it is converted if * possible. * value * A pointer to a buffer of suitable size to receive the keyword * value. The supplied value is left unchanged if the keyword is * not found. * report * Should an error be reported if the keyword cannot be found, or * cannot be converted to the requested type? * mark * Should the card be marked as having been used? * method * A string holding the name of the calling method. * class * A string holding the object class. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the keyword does not exist in "this", or cannot be * converted to the requested type. One is returned otherwise. * Notes: * - An error is reported if the keyword value is undefined. * - A value of zero is returned if an error has already occurred, * or if an error occurs within this function. */ /* Local Variables: */ int icard; /* Current card index */ int ret; /* Returned value */ /* Check the status */ if( !astOK ) return 0; /* Save the current card index. */ icard = astGetCard( this ); /* Attempt to find the supplied keyword. */ ret = SearchCard( this, keyname, method, class, status ); /* If the keyword was found, convert the current card's data value and copy it to the supplied buffer. */ if( ret ){ if( CnvValue( this, type, 0, value, method, status ) ) { /* If required, mark it as having been read into an AST object. */ if( mark ) MarkCard( this, status ); /* If the value is undefined, report an error if "report" is non-zero. */ if( type == AST__UNDEF && report && astOK ) { ret = 0; astError( AST__FUNDEF, "%s(%s): FITS keyword \"%s\" has no value.", status, method, class, keyname ); } /* If the value could not be converted to the requested data, type report an error if reporting is enabled. */ } else { ret = 0; if( report && astOK ){ astError( AST__FTCNV, "%s(%s): Cannot convert FITS keyword '%s' to %s.", status, method, class, keyname, type_names[ type ] ); } } /* If the keyword was not found, report an error if "report" is non-zero. */ } else if( report && astOK ){ astError( AST__BDFTS, "%s(%s): Unable to find a value for FITS " "keyword \"%s\".", status, method, class, keyname ); } /* Reinstate the original current card index. */ astSetCard( this, icard ); /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the result. */ return ret; } static int GetValue2( AstFitsChan *this1, AstFitsChan *this2, const char *keyname, int type, void *value, int report, const char *method, const char *class, int *status ){ /* * Name: * GetValue2 * Purpose: * Obtain a FITS keyword value from one of two FitsChans. * Type: * Private function. * Synopsis: * int GetValue2( AstFitsChan *this1, AstFitsChan *this2, const char *keyname, * int type, void *value, int report, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function attempts to get a value for the specified keyword from * the first supplied FitsChan. If this fails (due to the FitsChan not * containing a value for the ketword) then an attempt is made to get * a value for the keyword from the second supplied FitsChan. * Parameters: * this1 * A pointer to the first FitsChan to be used. * this2 * A pointer to the second FitsChan to be used. * keyname * A pointer to a string holding the keyword name. * type * The FITS data type in which to return the keyword value. If the * stored value is not of the requested type, it is converted if * possible. * value * A pointer to a buffer of suitable size to receive the keyword * value. The supplied value is left unchanged if the keyword is * not found. * report * Should an error be reported if the keyword cannot be found, or * cannot be converted to the requested type? * method * A string holding the name of the calling method. * class * A string holding the object class. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the keyword does not exist in either FitsChan, or cannot be * converted to the requested type. One is returned otherwise. * Notes: * - A value of zero is returned if an error has already occurred, * or if an error occurs within this function. * - If the card is found in the first FitsChan, it is not marked as * having been used. If the card is found in the second FitsChan, it is * marked as having been used. */ /* Local Variables: */ int ret; /* Returned value */ /* Check the status */ if( !astOK ) return 0; /* Try the first FitsChan. If this fails try the second. Do not report an error if the keyword is not found in the first FitsChan (this will be done, if required, once the second FitsChan has been searched). */ ret = GetValue( this1, keyname, type, value, 0, 0, method, class, status ); if( ! ret ) { ret = GetValue( this2, keyname, type, value, report, 1, method, class, status ); } /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the result. */ return ret; } static int HasAIPSSpecAxis( AstFitsChan *this, const char *method, const char *class, int *status ){ /* * Name: * HasAIPSSpecAxis * Purpose: * Does the FitsChan contain an AIPS spectral CTYPE keyword? * Type: * Private function. * Synopsis: * int HasAIPSSpecAxis( AstFitsChan *this, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function returns a non-zero value if the FitsCHan contains a * CTYPE value which conforms to the non-standard system used by AIPS. * Parameters: * this * A pointer to the FitsChan to be used. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if an AIPS spectral CTYPE keyword was found. */ /* Local Variables: */ char *assys; /* AIPS standard of rest type */ char *astype; /* AIPS spectral type */ char *cval; /* Pointer to character string */ int j; /* Current axis index */ int jhi; /* Highest axis index with a CTYPE */ int jlo; /* Lowest axis index with a CTYPE */ int ret; /* Returned value */ /* Initialise */ ret = 0; /* Check the status */ if( !astOK ) return ret; /* If the FitsChan contains any CTYPE values, convert the bounds from one-based to zero-based, and loop round them all. */ if( astKeyFields( this, "CTYPE%1d", 1, &jhi, &jlo ) ) { jlo--; jhi--; for( j = jlo; j <= jhi; j++ ) { /* Get the next CTYPE value. If found, see if it is an AIPS spectral CTYPE value. */ if( GetValue( this, FormatKey( "CTYPE", j + 1, -1, ' ', status ), AST__STRING, (void *) &cval, 0, 0, method, class, status ) ){ if( IsAIPSSpectral( cval, &astype, &assys, status ) ) { ret = 1; break; } } } } /* If an error has occurred, return 0. */ if( !astOK ) ret = 0; /* Return the result. */ return ret; } static int HasCard( AstFitsChan *this, const char *name, const char *method, const char *class, int *status ){ /* * Name: * HasCard * Purpose: * Check if the FitsChan contains a specified keyword. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int HasCard( AstFitsChan *this, const char *name, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a non-zero value if the FitsChan contains the given keyword, * and zero otherwise. The current card is unchanged. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a string holding the keyword name. * method * Pointer to string holding name of calling method. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if a card was found refering to the given * keyword. Otherwise zero is returned. */ /* Check the supplied pointers (we can rely on astMapHasKey to check the inherited status). */ if( !name || !this || !this->keywords ) return 0; /* Search the KeyMap holding the keywords currently in the FitsChan, returning non-zero if the keyword was found. A KeyMap is used because it uses a hashing algorithm to find the entries and is therefore a lot quicker than searching through the list of linked FitsCards. */ return astMapHasKey( this->keywords, name ); } void astInitFitsChanVtab_( AstFitsChanVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitFitsChanVtab * Purpose: * Initialise a virtual function table for a FitsChan. * Type: * Protected function. * Synopsis: * #include "fitschan.h" * void astInitFitsChanVtab( AstFitsChanVtab *vtab, const char *name ) * Class Membership: * FitsChan vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the FitsChan class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstChannelVtab *channel; /* Pointer to Channel component of Vtab */ char buf[ 100 ]; /* Buffer large enough to store formatted INT_MAX */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitChannelVtab( (AstChannelVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsAFitsChan) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstChannelVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->PutCards = PutCards; vtab->PutFits = PutFits; vtab->DelFits = DelFits; vtab->GetTables = GetTables; vtab->PutTables = PutTables; vtab->PutTable = PutTable; vtab->TableSource = TableSource; vtab->SetTableSource = SetTableSource; vtab->RemoveTables = RemoveTables; vtab->PurgeWCS = PurgeWCS; vtab->RetainFits = RetainFits; vtab->FindFits = FindFits; vtab->KeyFields = KeyFields; vtab->ReadFits = ReadFits; vtab->ShowFits = ShowFits; vtab->WriteFits = WriteFits; vtab->EmptyFits = EmptyFits; vtab->FitsEof = FitsEof; vtab->GetFitsCF = GetFitsCF; vtab->GetFitsCI = GetFitsCI; vtab->GetFitsF = GetFitsF; vtab->GetFitsI = GetFitsI; vtab->GetFitsL = GetFitsL; vtab->TestFits = TestFits; vtab->GetFitsS = GetFitsS; vtab->GetFitsCN = GetFitsCN; vtab->FitsGetCom = FitsGetCom; vtab->SetFitsCom = SetFitsCom; vtab->SetFitsCF = SetFitsCF; vtab->SetFitsCI = SetFitsCI; vtab->SetFitsF = SetFitsF; vtab->SetFitsI = SetFitsI; vtab->SetFitsL = SetFitsL; vtab->SetFitsU = SetFitsU; vtab->SetFitsS = SetFitsS; vtab->SetFitsCN = SetFitsCN; vtab->SetFitsCM = SetFitsCM; vtab->ClearCard = ClearCard; vtab->TestCard = TestCard; vtab->SetCard = SetCard; vtab->GetCard = GetCard; vtab->ClearFitsDigits = ClearFitsDigits; vtab->TestFitsDigits = TestFitsDigits; vtab->SetFitsDigits = SetFitsDigits; vtab->GetFitsDigits = GetFitsDigits; vtab->ClearDefB1950 = ClearDefB1950; vtab->TestDefB1950 = TestDefB1950; vtab->SetDefB1950 = SetDefB1950; vtab->GetDefB1950 = GetDefB1950; vtab->ClearTabOK = ClearTabOK; vtab->TestTabOK = TestTabOK; vtab->SetTabOK = SetTabOK; vtab->GetTabOK = GetTabOK; vtab->ClearCarLin = ClearCarLin; vtab->TestCarLin = TestCarLin; vtab->SetCarLin = SetCarLin; vtab->GetCarLin = GetCarLin; vtab->ClearPolyTan = ClearPolyTan; vtab->TestPolyTan = TestPolyTan; vtab->SetPolyTan = SetPolyTan; vtab->GetPolyTan = GetPolyTan; vtab->ClearIwc = ClearIwc; vtab->TestIwc = TestIwc; vtab->SetIwc = SetIwc; vtab->GetIwc = GetIwc; vtab->ClearWarnings = ClearWarnings; vtab->TestWarnings = TestWarnings; vtab->SetWarnings = SetWarnings; vtab->GetWarnings = GetWarnings; vtab->GetCardType = GetCardType; vtab->GetCardName = GetCardName; vtab->GetCardComm = GetCardComm; vtab->GetNcard = GetNcard; vtab->GetNkey = GetNkey; vtab->GetAllWarnings = GetAllWarnings; vtab->ClearEncoding = ClearEncoding; vtab->TestEncoding = TestEncoding; vtab->SetEncoding = SetEncoding; vtab->GetEncoding = GetEncoding; vtab->ClearClean = ClearClean; vtab->TestClean = TestClean; vtab->SetClean = SetClean; vtab->GetClean = GetClean; vtab->ClearCDMatrix = ClearCDMatrix; vtab->TestCDMatrix = TestCDMatrix; vtab->SetCDMatrix = SetCDMatrix; vtab->GetCDMatrix = GetCDMatrix; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; channel = (AstChannelVtab *) vtab; parent_getobjsize = object->GetObjSize; object->GetObjSize = GetObjSize; #if defined(THREAD_SAFE) parent_managelock = object->ManageLock; object->ManageLock = ManageLock; #endif parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_write = channel->Write; channel->Write = Write; parent_read = channel->Read; channel->Read = Read; parent_getskip = channel->GetSkip; channel->GetSkip = GetSkip; parent_getfull = channel->GetFull; channel->GetFull = GetFull; channel->WriteBegin = WriteBegin; channel->WriteIsA = WriteIsA; channel->WriteEnd = WriteEnd; channel->WriteInt = WriteInt; channel->WriteDouble = WriteDouble; channel->WriteString = WriteString; channel->WriteObject = WriteObject; channel->GetNextData = GetNextData; parent_setsourcefile = channel->SetSourceFile; channel->SetSourceFile = SetSourceFile; /* Declare the class dump, copy and delete functions.*/ astSetDump( vtab, Dump, "FitsChan", "I/O channels to FITS files" ); astSetCopy( (AstObjectVtab *) vtab, Copy ); astSetDelete( (AstObjectVtab *) vtab, Delete ); /* Max number of characters needed to format an int. */ LOCK_MUTEX4 sprintf( buf, "%d", INT_MAX ); int_dig = strlen( buf ); /* Create a pair of MJD TimeFrames which will be used for converting to and from TDB. */ astBeginPM; if( !tdbframe ) tdbframe = astTimeFrame( "system=MJD,timescale=TDB", status ); if( !timeframe ) timeframe = astTimeFrame( "system=MJD", status ); astEndPM; UNLOCK_MUTEX4 /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static void InsCard( AstFitsChan *this, int overwrite, const char *name, int type, void *data, const char *comment, const char *method, const char *class, int *status ){ /* * Name: * InsCard * Purpose: * Inserts a card into a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void InsCard( AstFitsChan *this, int overwrite, const char *name, * int type, void *data, const char *comment, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Either appends a new card to a FitsChan, or over-writes an existing * card, holding the supplied keyword name, value and comment. * Parameters: * this * Pointer to the FitsChan containing the filters to apply to the * keyword name. If a NULL pointer is supplied, no filtering is applied. * overwrite * If non-zero, the new card over-writes the current card given by * the "Card" attribute, and the current card is incremented so * that it refers to the next card. Otherwise, the new card is * inserted in front of the current card and the current card is * left unchanged. * name * Pointer to a string holding the keyword name of the new card. * type * An integer value representing the data type of the keyword. * data * Pointer to the data associated with the keyword. * comment * Pointer to a null-terminated string holding a comment. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Notes: * - An error is reported if an attempt is made to change the data type * of an existing card. * - If a type of AST__COMMENT is supplied, then any data value (of any * type) associated with an existing card is left unchanged. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ int flags; /* Flags to assign to new card */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* If the current card is to be over-written, delete the current card (the next card in the list, if any, will become the new current card). */ if( overwrite ) DeleteCard( this, method, class, status ); /* If requested, set both NEW flags for the new card. */ flags = ( mark_new ) ? ( NEW1 | NEW2 ): 0; /* Insert the new card into the list, just before the current card. */ NewCard( this, name, type, data, comment, flags, status ); } static int IRAFFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * IRAFFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-IRAF encoding. * Type: * Private function. * Synopsis: * int IRAFFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-IRAF encoding. * * IRAF encoding is like FITS-WCS encoding but with the following * restrictions: * * 1) The celestial projection must not have any projection parameters * which are not set to their default values. The one exception to this * is that SIN projections are acceptable if the associated projection * parameter PV_1 is zero and PV_2 = cot( reference point * latitude). This is encoded using the string "-NCP". The SFL projection * is encoded using the string "-GLS". Note, the original IRAF WCS * system only recognised a small subset of the currently available * projections, but some more recent IRAF-like software recognizes some * of the new projections included in the FITS-WCS encoding. * * 2) The celestial axes must be RA/DEC, galactic or ecliptic. * * 3) LONPOLE and LATPOLE cannot be used. * * 4) Only primary axis descriptions are written out. * * 5) RADECSYS is used in place of RADESYS. * * 6) PC/CDELT keywords are not allowed (CD must be used) * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ char *comm; /* Pointer to comment string */ char *cval; /* Pointer to string keyword value */ char combuf[80]; /* Buffer for FITS card comment */ char lattype[MXCTYPELEN];/* Latitude axis CTYPE */ char lontype[MXCTYPELEN];/* Longitude axis CTYPE */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ double cdelt; /* A CDELT value */ double fd; /* Fraction of a day */ double mjd99; /* MJD at start of 1999 */ double p1, p2; /* Projection parameters */ double val; /* General purpose value */ int axlat; /* Index of latitude FITS WCS axis */ int axlon; /* Index of longitude FITS WCS axis */ int axspec; /* Index of spectral FITS WCS axis */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int naxis; /* No. of axes */ int ok; /* Is FitsSTore OK for IRAF encoding? */ int prj; /* Projection type */ int ret; /* Returned value. */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* First check that the values in the FitsStore conform to the requirements of the IRAF encoding. Assume they do to begin with. */ ok = 1; /* Just do primary axes. */ s = ' '; /* Look for the primary celestial and spectral axes. */ FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status ); /* If both longitude and latitude axes are present and thereis no spectral axis...*/ if( axlon >= 0 && axlat >= 0 ) { /* Get the CTYPE values for both axes. */ cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status ); if( !cval ) return ret; strcpy( lontype, cval ); cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); if( !cval ) return ret; strcpy( lattype, cval ); /* Extract the projection type as specified by the last 4 characters in the CTYPE keyword value. */ prj = astWcsPrjType( lattype + 4 ); /* Check the projection type is OK. Assume not initially. */ ok = 0; /* FITS-IRAF cannot handle the AST-specific TPN projection. */ if( prj == AST__TPN || prj == AST__WCSBAD ) { ok = 0; /* SIN projections are handled later. */ } else if( prj != AST__SIN ){ /* There must be no projection parameters. */ if( GetMaxJM( &(store->pv), ' ', status ) == -1 ) ok = 1; /* Change the new SFL projection code to to the older equivalent GLS */ if( prj == AST__SFL ){ (void) strcpy( lontype + 4, "-GLS" ); (void) strcpy( lattype + 4, "-GLS" ); } /* SIN projections are only acceptable if the associated projection parameters are both zero, or if the first is zero and the second = cot( reference point latitude ) (the latter case is equivalent to the old NCP projection). */ } else { p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status ); p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status ); if( p1 == AST__BAD ) p1 = 0.0; if( p2 == AST__BAD ) p2 = 0.0; val = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { if( p1 == 0.0 ) { if( p2 == 0.0 ) { ok = 1; } else if( fabs( p2 ) >= 1.0E14 && val == 0.0 ){ ok = 1; (void) strcpy( lontype + 4, "-NCP" ); (void) strcpy( lattype + 4, "-NCP" ); } else if( fabs( p2*tan( AST__DD2R*val ) - 1.0 ) < 0.01 ){ ok = 1; (void) strcpy( lontype + 4, "-NCP" ); (void) strcpy( lattype + 4, "-NCP" ); } } } } /* Identify the celestial coordinate system from the first 4 characters of the longitude CTYPE value. Only RA, galactic longitude, and ecliptic longitude can be stored using FITS-IRAF. */ if( strncmp( lontype, "RA--", 4 ) && strncmp( lontype, "GLON", 4 ) && strncmp( lontype, "ELON", 4 ) ) ok = 0; /* If the physical Frame requires a LONPOLE or LATPOLE keyword, it cannot be encoded using FITS-IRAF. */ if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ) != AST__BAD || GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ) != AST__BAD ) ok = 0; /* If there are no celestial axes, the physical Frame can be written out using FITS-IRAF. */ } else { ok = 1; } /* Save the number of axes */ naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1; /* If this is different to the value of NAXIS abort since this encoding does not support WCSAXES keyword. */ if( naxis != store->naxis ) ok = 0; /* Return if the FitsStore does not conform to IRAF encoding. */ if( !ok ) return ret; /* Get and save CRPIX for all pixel axes. These are required, so return if they are not available. */ for( i = 0; i < naxis; i++ ){ val = GetItem( &(store->crpix), 0, i, s, NULL, method, class, status ); if( val == AST__BAD ) return ret; sprintf( combuf, "Reference pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRPIX", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } /* Get and save CRVAL for all intermediate axes. These are required, so return if they are not available. */ for( j = 0; j < naxis; j++ ){ val = GetItem( &(store->crval), j, 0, s, NULL, method, class, status ); if( val == AST__BAD ) return ret; sprintf( combuf, "Value at ref. pixel on axis %d", j + 1 ); SetValue( this, FormatKey( "CRVAL", j + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } /* Get and save CTYPE for all intermediate axes. These are required, so return if they are not available. Use the potentially modified versions saved above for the celestial axes. */ for( i = 0; i < naxis; i++ ){ if( i == axlat ) { cval = lattype; } else if( i == axlon ) { cval = lontype; } else { cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( !cval ) return ret; } if( !strcmp( cval + 4, "-TAB" ) ) return ret; comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING, comm, status ); } /* CD matrix (the product of the CDELT and PC matrices). */ for( i = 0; i < naxis; i++ ){ cdelt = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdelt == AST__BAD ) cdelt = 1.0; for( j = 0; j < naxis; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdelt; if( val != 0.0 ) { SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val, AST__FLOAT, "Transformation matrix element", status ); } } } /* Get and save CUNIT for all intermediate axes. These are NOT required, so do not return if they are not available. */ for( i = 0; i < naxis; i++ ){ cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( cval ) { sprintf( combuf, "Units for axis %d", i + 1 ); SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING, combuf, status ); } } /* Get and save RADECSYS. This is NOT required, so do not return if it is not available. */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, "RADECSYS", &cval, AST__STRING, "Reference frame for RA/DEC values", status ); /* Reference equinox */ val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "EQUINOX", &val, AST__FLOAT, "Epoch of reference equinox", status ); /* Date of observation */ val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD ) { /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING, "Date of observation", status ); } /* If we get here we have succeeded. */ ret = 1; /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ret : 0; } static int IsMapLinear( AstMapping *smap, const double lbnd_in[], const double ubnd_in[], int coord_out, int *status ) { /* * Name: * IsMapLinear * Purpose: * See if a specified Mapping output is linearly related to the * Mapping inputs. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int IsMapLinear( AstMapping *smap, const double lbnd_in[], * const double ubnd_in[], int coord_out, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a flag indicating if the specified output of the supplied * Mapping is a linear function of the Mapping inputs. A set of output * positions are created which are evenly spaced along the specified * output coordinate. The spacing is chosen so that the entire range * of the output coordinate is covered in 20 steps. The other output * coordinates are held fixed at arbitrary values (actually, values * at which the specified output coordinate achieves its minimum value). * This set of output positions is transformed into the corresponding * set of input coordinates using the inverse of the supplied Mapping. * A least squares linear fit is then made which models each input * coordinate as a linear function of the specified output coordinate. * The residual at every point in this fit must be less than some * small fraction of the total range of the corresponding input * coordinate for the Mapping to be considered linear. * Parameters: * smap * Pointer to the Mapping. * lbnd_in * Pointer to an array of double, with one element for each * Mapping input coordinate. This should contain the lower bound * of the input box in each input dimension. * ubnd_in * Pointer to an array of double, with one element for each * Mapping input coordinate. This should contain the upper bound * of the input box in each input dimension. * coord_out * The zero-based index of the Mapping output which is to be checked. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the specified Mapping output is linear. Zero otherwise. */ /* Local Constants: */ #define NP 20 /* Local Variables: */ AstMapping *map; AstPointSet *pset1; AstPointSet *pset2; double **ptr1; double **ptr2; double *p; double *s; double *xl; double c; double d; double delta; double in_lbnd; double in_ubnd; double lbnd_out; double m; double p0; double pv; double sn; double sp; double sps; double ss2; double ss; double sv; double tol; double ubnd_out; int *ins; int boxok; int i; int j; int nin; int nout; int oldrep; int ret; /* Initialise */ ret = 0; /* Check inherited status */ if( !astOK ) return ret; /* Attempt to split off the required output (in case any of the other outputs are associated with Mappings that do not have an inverse). */ astInvert( smap ); ins = astMapSplit( smap, 1, &coord_out, &map ); astInvert( smap ); /* If successful, check that the output is fed by only one input. */ if( ins ) { if( astGetNin( map ) == 1 ) { /* If so, invert the map so that it goes from pixel to wcs, and then modify the supplied arguments so that they refer to the single required axis. */ astInvert( map ); lbnd_in += coord_out; ubnd_in += coord_out; coord_out = 0; /* If the output was fed by more than one input, annul the split mapping and use the supplied nmapping. */ } else { (void) astAnnul( map ); map = astClone( smap ); } ins = astFree( ins ); /* If the supplied Mapping could not be split, use the supplied nmapping. */ } else { map = astClone( smap ); } /* Check the Mapping is defined in both directions. */ if( astGetTranForward( map ) && astGetTranInverse( map ) ) { /* Allocate resources. */ nin = astGetNin( map ); nout = astGetNout( map ); xl = astMalloc( sizeof( double )*(size_t) nin ); pset1 = astPointSet( NP, nin, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( NP, nout, "", status ); ptr2 = astGetPoints( pset2 ); /* Call astMapBox in a new error reporting context. */ boxok = 0; if( astOK ) { /* Temporarily switch off error reporting so that no report is made if astMapBox cannot find a bounding box (which can legitimately happen with some non-linear Mappings). */ oldrep = astReporting( 0 ); /* Find the upper and lower bounds on the specified Mapping output. This also returns the input coords of a point at which the required output has its lowest value. */ astMapBox( map, lbnd_in, ubnd_in, 1, coord_out, &lbnd_out, &ubnd_out, xl, NULL ); /* If the box could not be found, clear the error status and pass on. */ if( !astOK ) { astClearStatus; /* If the box was found OK, flag this and check if the bounds are equal. If so we cannot use them. In this case create new bounds. */ } else { boxok = 1; if( EQUAL( lbnd_out, ubnd_out ) ) { m = 0.5*( lbnd_out + ubnd_out ); if( fabs( m ) > 1.0E-15 ) { lbnd_out = 0.9*m; ubnd_out = 1.1*m; } else { lbnd_out = -1.0; ubnd_out = 1.0; } } } /* Re-instate error reporting. */ astReporting( oldrep ); } /* Check pointers can be used safely and a box was obtained. */ if( astOK && boxok ) { /* Transform the input position returned by astMapBox using the supplied Mapping to get the corresponding output position. Fill all unused elements of the PointSet with AST__BAD. */ for( i = 0; i < nin; i++ ){ p = ptr1[ i ]; *(p++) = xl[ i ]; for( j = 1; j < NP; j++ ) *(p++) = AST__BAD; } (void) astTransform( map, pset1, 1, pset2 ); /* Now create a set of NP points evenly spaced in output coordinates. The first point is at the output position found above. Each subsequent point is incremented by a fixed amount along the specified output coordinate (the values on all other output coordinates is held fixed). */ delta = ( ubnd_out - lbnd_out )/ ( NP - 1 ); for( i = 0; i < nout; i++ ){ p = ptr2[ i ]; if( i == coord_out ) { for( j = 0; j < NP; j++ ) *(p++) = lbnd_out + j*delta; } else { p0 = p[ 0 ]; for( j = 0; j < NP; j++ ) *(p++) = p0; } } /* Transform these output positions into input positions using the inverse Mapping. */ (void) astTransform( map, pset2, 0, pset1 ); /* Do a least squares fit to each input coordinate. Each fit gives the corresponding input coordinate value as a linear function of the specified output coordinate value. Note, linear function should never produce bad values so abort if a bad value is found. */ ret = 1; s = ptr2[ coord_out ]; for( i = 0; i < nin; i++ ) { p = ptr1[ i ]; /* Form the required sums. Also find the largest and smallest input coordinate value achieved. */ sp = 0.0; ss = 0.0; sps = 0.0; sn = 0.0; ss2 = 0.0; in_lbnd = DBL_MAX; in_ubnd = DBL_MIN; for( j = 0; j < NP; j++ ) { sv = s[ j ]; pv = p[ j ]; if( pv != AST__BAD && sv != AST__BAD ) { sp += pv; ss += sv; sps += pv*sv; sn += 1.0; ss2 += sv*sv; if( pv < in_lbnd ) in_lbnd = pv; if( pv > in_ubnd ) in_ubnd = pv; } else { sn = 0.0; break; } } /* Ignore input axes which are independant of the output axis. */ if( !EQUAL( in_lbnd, in_ubnd ) ) { /* Calculate the constants "input coord = m*output coord + c" */ d = ss*ss - sn*ss2; if( sn > 0.0 && d != 0.0 ) { m = ( sp*ss - sps*sn )/d; c = ( sps*ss - sp*ss2 )/d; /* Subtract off the fit value form the "p" values to get the residuals of the fit. */ for( j = 0; j < NP; j++ ) p[ j ] -= m*s[ j ] + c; /* We now do a least squares fit to the residuals. This second fit is done because the first least squares fit sometimes leaves the residuals with a distinct non-zero gradient. We do not need to worry about bad values here since we have checked above that there are no bad values. Also we do not need to recalculate sums which only depend on the "s" values since they have not changed. */ sp = 0.0; sps = 0.0; for( j = 0; j < NP; j++ ) { pv = p[ j ]; sp += pv; sps += pv*s[ j ]; } /* Find the constants in "input residual = m*output coord + c" equation. */ m = ( sp*ss - sps*sn )/d; c = ( sps*ss - sp*ss2 )/d; /* Subtract off the fit value form the "p residuals" values to get the residual redisuals of the fit. */ for( j = 0; j < NP; j++ ) p[ j ] -= m*s[ j ] + c; /* The requirement for a linear relationship is that the absolute residual between the input coord produced by the above linear fit and the input coord produced by the actual Mapping should be less than some small fraction of the total range of input coord value, at every point. Test this. */ tol = 1.0E-7*( in_ubnd - in_lbnd ); for( j = 0; j < NP; j++ ) { if( fabs( p[ j ] ) > tol ) { ret = 0; break; } } } else { ret = 0; } } if( !ret ) break; } } /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); xl = astFree( xl ); } map = astAnnul( map ); /* Return the answer. */ return ret; } static AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit, AstFrame *wcsfrm, double *dim, int iax, int iwcs, AstFitsTable **table, int *icolmain, int *icolindex, int *interp, int *status ){ /* * Name: * IsMapTab1D * Purpose: * See if a specified Mapping output is related to a single Mapping input * via a FITS -TAB algorithm. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit, * AstFrame *wcsfrm, double *dim, int iax, * int iwcs, AstFitsTable **table, int *icolmain, * int *icolindex, int *interp, int *status ) * Class Membership: * FitsChan member function. * Description: * A specified axis of the supplied Mapping is tested to see if it * can be represented by the -TAB alogirithm described in FITS-WCS * paper III. If the test is passed, a Mapping is returned from the * specified WCS axis to the corresponding psi axis. A FitsTable is * also created holding the information to be stored in the * corresponding FITS binary table. * * Note, when creating a -TAB header, AST uses grid coords for the psi * axis. See FITS-WCS paper III section 6.1.2 for a definition of the * psi axes. * Parameters: * map * Pointer to the Mapping from pixel coords to WCS coords. * scale * A scale factor by which to multiply the axis values stored in the * returned FitsTable. Note, the returned Mapping is unaffected by * this scaling factor. * unit * Pointer to the unit string to store with the coords column. If * NULL, the unit string is extracted form the supplied WCS Frame. * wcsfrm * Pointer to a Frame describing WCS coords. * dim * An array holding the array dimensions in pixels. AST__BAD should * be supplied for any unknown dimensions. * iax * The zero-based index of the Mapping output which is to be checked. * iwcs * The zero-based index of the corresponding FITS WCS axis. * table * Pointer to a location holding a pointer to the FitsTable describing * the -TAB look-up table. If "*table" is NULL on entry, a new * FitsTable will be created and returned, otherwise the supplied * FitsTable is used. * icolmain * The one-based index of the column within "*table" that holds the * main data array. * icolindex * The one-based index of the column within "*table" that holds the * index vector. Returned equal to -1 if no index is added to the * table (i.e. if the index is a unt index). * interp * The interpolation method (0=linear, other=nearest neighbour). * status * Pointer to the inherited status variable. * Returned Value: * If the specified "map" output can be described using the -TAB * algorithm of FITS-WCS paper III, then a 1-input/1-output Mapping * from the specified WCS axis to the corresponding psi axis (which is * assumed to be equal to grid coords) is returned. NULL is returned * otherwise, of if an error occurs. */ /* Local Variables: */ AstCmpMap *cm; /* CmpMap pointer */ AstMapping **map_list; /* Mapping array pointer */ AstMapping *postmap; /* Total Mapping after LutMap */ AstMapping *premap; /* Total Mapping before LutMap */ AstMapping *ret; /* Returned WCS axis Mapping */ AstMapping *tmap; /* Temporary Mapping */ AstPermMap *pm; /* PermMap pointer */ char cellname[ 20 ]; /* Buffer for cell name */ char colname[ 20 ]; /* Buffer for column name */ double *lut; /* Pointer to table of Y values */ double *work1; /* Pointer to work array */ double *work2; /* Pointer to work array */ double inc; /* X increment between table entries */ double start; /* X value at first table entry */ double v[ 2 ]; /* Y values at start and end of interval */ double x[ 2 ]; /* X values at start and end of interval */ int *ins; /* Array of "map" input indices */ int *invert_list; /* Invert array pointer */ int *outs; /* Array of "map" output indices */ int dims[ 2 ]; /* Dimensions of the tab coords array */ int iin; /* Index of Mapping input */ int ilut; /* Index of the LutMap within the mappings list */ int imap; /* Index of current Mapping in list */ int iout; /* Index of Mapping output */ int jout; /* Index of Mapping output */ int nin; /* Number of Mapping inputs */ int nlut; /* Number of elements in "lut" array */ int nmap; /* Number of Mappings in the list */ int nout; /* Number of Mapping outputs */ int ok; /* Were columns added to the table? */ int old_invert; /* Original value for Mapping's Invert flag */ int outperm; /* Index of input that feeds the single output */ /* Initialise */ ret = NULL; *icolmain = -1; *icolindex = -1; *interp = 0; /* Check inherited status */ if( !astOK ) return ret; /* Ensure we have aunit string. */ if( !unit ) unit = astGetUnit( wcsfrm, iax ); /* Check that the requested mapping output is fed by only one mapping input, identify that input, and extract the input->output mapping from the total mapping. Since astMapSplit splits off a specified input, we need to invert the Mapping first so we can split off a specified output. */ astInvert( map ); ins = astMapSplit( map, 1, &iax, &ret ); astInvert( map ); /* If the Mapping could not be split, try a different approach in which each input is checked in turn to see if it feeds the specified output. */ if( !ins ) { /* Loop round each input of "map". */ nin = astGetNin( map ); for( iin = 0; iin < nin && !ins; iin++ ) { /* Attempt to find a group of outputs (of "map") that are fed by just this one input. */ outs = astMapSplit( map, 1, &iin, &ret ); /* If successful, "ret" will be a Mapping with one input corresponding to input "iin" of "map, and one or more outputs. We loop round these outputs to see if any of them correspond to output "iax" of "map". */ if( outs ) { nout = astGetNout( ret ); for( iout = 0; iout < nout; iout++ ) { if( outs[ iout ] == iax ) break; } /* Did input "iin" feed the output "iax" (and possibly other outputs)? */ if( iout < nout ) { /* The "ret" Mapping is now a 1-input (pixel) N-output (WCS) Mapping in which output "iout" corresponds to output "iax" of Mapping. To be compatible with the previous approach, we want "ret" to be a 1-input (WCS) to 1-output (pixel) Mapping in which the input corresponds to output "iax" of Mapping. To get "ret" into this form, we first append a PermMap to "ret" that selects a single output ("iout"), and then invert the whole CmpMap. */ for( jout = 0; jout < nout; jout++ ) { outs[ jout ] = -1; } outs[ iout ] = 0; outperm = iout; pm = astPermMap( nout, outs, 1, &outperm, NULL, "", status ); cm = astCmpMap( ret, pm, 1, " ", status ); (void) astAnnul( ret ); pm = astAnnul( pm ); ret = (AstMapping *) cm; astInvert( ret ); /* The earlier approach leves ins[ 0 ] holding the index of the input to "map" that feeds output iax. Ensure we have this too. */ ins = outs; ins[ 0 ] = iin; /* Free resources if the current input did not feed the required output. */ } else { outs = astFree( outs ); ret = astAnnul( ret ); } } } } /* If the Mapping still could not be split, try again on a copy of the Mapping in which all PermMaps provide an alternative implementation of the astMapSplit method. */ if( !ins ) { astInvert( map ); tmap = astCopy( map ); ChangePermSplit( tmap, status ); ins = astMapSplit( tmap, 1, &iax, &ret ); tmap = astAnnul( tmap ); astInvert( map ); } /* Assume the Mapping cannot be represented by -TAB */ ok = 0; /* Check a Mapping was returned by astMapSplit. If so, it will be the mapping from the requested output of "map" (the WCS axis) to the corresponding input(s) (grid axes). Check only one "map" input feeds the requested output. */ if( ins && ret && astGetNout( ret ) == 1 ) { /* Invert the Mapping so that the input is grid coord and the output is WCS coord. */ astInvert( ret ); /* We now search the "ret" mapping for a non-inverted LutMap, splitting ret up into three serial components: 1) the mappings before the LutMap, 2) the LutMap itself, and 3) the mappings following the LutMap. First, decompose the mapping into a list of series mappings. */ map_list = NULL; invert_list = NULL; nmap = 0; astMapList( ret, 1, astGetInvert( ret ), &nmap, &map_list, &invert_list ); /* Search the list for a non-inverted LutMap. */ ilut = -1; for( imap = 0; imap < nmap; imap++ ) { if( astIsALutMap( map_list[ imap ] ) && !(invert_list[ imap ]) ) { ilut = imap; break; } } /* If a LutMap was found, combine all Mappings before the LutMap into a single Mapping. Remember to set the Mapping Invert flags temporarily to the values used within the CmpMap. */ if( ilut >= 0 ) { premap = (AstMapping *) astUnitMap( 1, " ", status ); for( imap = 0; imap < ilut; imap++ ) { old_invert = astGetInvert( map_list[ imap ] ); astSetInvert( map_list[ imap ], invert_list[ imap ] ); tmap = (AstMapping *) astCmpMap( premap, map_list[ imap ], 1, " ", status ); astSetInvert( map_list[ imap ], old_invert ); (void) astAnnul( premap ); premap = tmap; } /* Also combine all Mappings after the LutMap into a single Mapping, setting the Mapping Invert flags temporarily to the values used within the CmpMap. */ postmap = (AstMapping *) astUnitMap( 1, " ", status ); for( imap = ilut + 1; imap < nmap; imap++ ) { old_invert = astGetInvert( map_list[ imap ] ); astSetInvert( map_list[ imap ], invert_list[ imap ] ); tmap = (AstMapping *) astCmpMap( postmap, map_list[ imap ], 1, " ", status ); astSetInvert( map_list[ imap ], old_invert ); (void) astAnnul( postmap ); postmap = tmap; } /* Get the table of values, and other attributes, from the LutMap. */ lut = astGetLutMapInfo( map_list[ ilut ], &start, &inc, &nlut ); *interp = astGetLutInterp( map_list[ ilut ] ); /* If required, create a FitsTable to hold the returned table info. */ if( ! *table ) *table = astFitsTable( NULL, "", status ); ok = 1; /* Define the properties of the column in the FitsTable that holds the main coordinate array. Points on a WCS axis are described by a single value (wavelength, frequency, or whatever), but the coords array has to be 2-dimensional, with an initial degenerate axis, as required by FITS-WCS paper III. */ dims[ 0 ] = 1; dims[ 1 ] = nlut; sprintf( colname, "COORDS%d", iwcs + 1 ); astAddColumn( *table, colname, AST__DOUBLETYPE, 2, dims, unit ); /* Get the one-based index of the column just added to the table. */ *icolmain = astGetNcolumn( *table ); /* Get workspace. */ work1 = astMalloc( nlut*sizeof( double ) ); if( astOK ) { /* Transform the LutMap table values using the post-lutmap mapping to get the list of WCS values in AST units. */ astTran1( postmap, nlut, lut, 1, work1 ); /* Convert them to FITS units (e.g. celestial axis values should be converted from radians to degrees). */ for( ilut = 0; ilut < nlut; ilut++ ) work1[ ilut ] *= scale; /* Store them in row 1, column COORDS, in the FitsTable. */ sprintf( cellname, "COORDS%d(1)", iwcs + 1 ); astMapPut1D( *table, cellname, nlut, work1, NULL ); /* Create an array holding the LutMap input value at the centre of each table entry. Re-use the "lut" array since we no longer need it. */ for( ilut = 0; ilut < nlut; ilut++ ) { lut[ ilut ] = start + ilut*inc; } /* Transform this array using the inverted pre-lutmap mapping to get the list of grid coord. */ astTran1( premap, nlut, lut, 0, work1 ); /* Test this list to see if they form a unit index (i.e. index(i) == i+1 ). (not the "+1" is due to the fact that "i" is zero based). */ for( ilut = 0; ilut < nlut; ilut++ ) { if( fabs( work1[ ilut ] - ilut - 1.0 ) > 1.0E-6 ) break; } /* if it is not a unit index, we add the index to the table. */ if( ilut < nlut ) { /* Define the properties of the column in the FitsTable that holds the indexing vector. */ sprintf( colname, "INDEX%d", iwcs + 1 ); astAddColumn( *table, colname, AST__DOUBLETYPE, 1, &nlut, " " ); /* Get the one-based index of the column just added to the table. */ *icolindex = astGetNcolumn( *table ); /* Store the values in the column. */ sprintf( cellname, "INDEX%d(1)", iwcs + 1 ); astMapPut1D( *table, cellname, nlut, work1, NULL ); } } /* Free resources. */ work1 = astFree( work1 ); lut = astFree( lut ); premap = astAnnul( premap ); postmap = astAnnul( postmap ); /* If no LutMap was found in the Mapping, then we can create a FitsTable by sampling the full WCS Mapping at selected input (i.e. grid) positions. But we can only do this if we know the number of pixels along the WCS axis. */ } else if( dim[ ins[ 0 ] ] != AST__BAD ) { /* Create two works array each holding a single value. The first holds the grid coords at which the samples are taken. The second holds the WCS coords at the sampled positions. These arrays are expanded as required within function AdaptLut. */ work1 = astMalloc( sizeof( double ) ); work2 = astMalloc( sizeof( double ) ); if( astOK ) { /* Get the WCS values at the centres of the first and last pixel on the WCS axis. */ x[ 0 ] = 1.0; x[ 1 ] = dim[ ins[ 0 ] ]; astTran1( ret, 2, x, 1, v ); /* Put the lower limit into the work arrays. */ work1[ 0 ] = x[ 0 ]; work2[ 0 ] = v[ 0 ]; nlut = 1; /* Expand the arrays by sampling the WCS axis adaptively so that more samples occur where the WCS value is changing most rapidly. We require the maximum error introduced by the table to be 0.25 pixels. */ AdaptLut( ret, 3, 0.25, x[ 0 ], x[ 1 ], v[ 0 ], v[ 1 ], &work1, &work2, &nlut, status ); /* Create a FitsTable to hold the returned table info. */ if( ! *table ) *table = astFitsTable( NULL, "", status ); ok = 1; /* Define the properties of the column in the FitsTable that holds the main coordinate array. */ sprintf( colname, "COORDS%d", iwcs + 1 ); dims[ 0 ] = 1; dims[ 1 ] = nlut; astAddColumn( *table, colname, AST__DOUBLETYPE, 2, dims, unit ); *icolmain = astGetNcolumn( *table ); /* Convert the axis values to FITS units (e.g. celestial axis values should be converted from radians to degrees). */ for( ilut = 0; ilut < nlut; ilut++ ) work2[ ilut ] *= scale; /* Store the scaled axis values in row 1 of the column. */ sprintf( cellname, "COORDS%d(1)", iwcs + 1 ); astMapPut1D( *table, cellname, nlut, work2, NULL ); /* Test the index vector to see if they form a unit index (i.e. index(i) == i+1 ). If not the "+1" is due to the fact that "i" is zero based). If not, store them as the index vector in the FitsTable. */ for( ilut = 0; ilut < nlut; ilut++ ) { if( fabs( work1[ ilut ] - ilut - 1.0 ) > 1.0E-6 ) break; } /* If the index vector is not a unit index, define the properties of the column in the FitsTable that holds the indexing vector. Then store values in row 1 of the column. */ if( ilut < nlut ) { sprintf( colname, "INDEX%d", iwcs + 1 ); astAddColumn( *table, colname, AST__DOUBLETYPE, 1, &nlut, " " ); *icolindex = astGetNcolumn( *table ); sprintf( cellname, "INDEX%d(1)", iwcs + 1 ); astMapPut1D( *table, cellname, nlut, work1, NULL ); } } /* Free resources */ work1 = astFree( work1 ); work2 = astFree( work2 ); } /* If columns were added to the table, invert the returned Mapping again so that the input is wcs coord and the output is grid coord. Otherwise, annul the returned Mapping. */ if( ok ) { astInvert( ret ); } else { ret = astAnnul( ret ); } /* Loop to annul all the Mapping pointers in the list. */ for ( imap = 0; imap < nmap; imap++ ) map_list[ imap ] = astAnnul( map_list[ imap ] ); /* Free the dynamic arrays. */ map_list = astFree( map_list ); invert_list = astFree( invert_list ); } /* Free resources. */ ins = astFree( ins ); /* If an error occurred, free the returned Mapping. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result. */ return ret; } static AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit, AstFrame *wcsfrm, double *dim, int iax1, int iax2, int iwcs1, int iwcs2, AstFitsTable **table, int *icolmain1, int *icolmain2, int *icolindex1, int *icolindex2, int *max1, int *max2, int *interp1, int *interp2, int *status ){ /* * Name: * IsMapTab2D * Purpose: * See if a specified pair of Mapping outputs are related to a pair of * Mapping inputs via a FITS -TAB algorithm. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit, * AstFrame *wcsfrm, double *dim, int iax1, * int iax2, int iwcs1, int iwcs2, * AstFitsTable **table, int *icolmain1, * int *icolmain2, int *icolindex1, * int *icolindex2, int *max1, int *max2, * int *interp1, int *interp2, int *status ) * Class Membership: * FitsChan member function. * Description: * A specified pair of outputs axes of the supplied Mapping are tested * to see if they can be represented by the -TAB alogirithm described in * FITS-WCS paper III. If the test is passed, a Mapping is returned from * the specified WCS axes to the corresponding psi axes. A FitsTable is * also created holding the information to be stored in the corresponding * FITS binary table. Note, when creating a header, AST assumes a unit * transformaton between psi axes and grid axes (psi axes are defined * in FITS-WCS paper III section 6.1.2). * Parameters: * map * Pointer to the Mapping from pixel coords to WCS coords. * scale * A scale factor by which to multiply the axis values stored in the * returned FitsTable. Note, the returned Mapping is unaffected by * this scaling factor. * unit * A unit string for the axis values. If supplied, the same * string is stored for both axes. If NULL, the unit strings are * extracted from the relavent axes of the supplied WCS Frame. * wcsfrm * Pointer to a Frame describing WCS coords. * dim * An array holding the array dimensions in pixels. AST__BAD should * be supplied for any unknown dimensions. * iax1 * The zero-based index of the first Mapping output which is to be * checked. * iax2 * The zero-based index of the second Mapping output which is to be * checked. * iwcs1 * The zero-based index of the FITS WCS axis corresponding to "iax1". * iwcs2 * The zero-based index of the FITS WCS axis corresponding to "iax2". * table * Pointer to a location holding a pointer to the FitsTable describing * the -TAB look-up table. If "*table" is NULL on entry, a new * FitsTable will be created and returned, otherwise the supplied * FitsTable is used. * icolmain1 * The one-based index of the column within "*table" that holds the * main coord array for the first Mapping output. * icolmain2 * The one-based index of the column within "*table" that holds the * main coord array for the second Mapping output. * icolindex1 * The one-based index of the column within "*table" that holds the * index vector for the first Mapping output. Returned equal to -1 * if no index is added to the table (e.g. because the index is a * unit index). * icolindex2 * The one-based index of the column within "*table" that holds the * index vector for the second Mapping output. Returned equal to -1 * if no index is added to the table (e.g. because the index is a * unit index). * max1 * The one-based index of the dimension describing the first Mapping * output within the main coord array specified by "icolmain1". * max2 * The one-based index of the dimension describing the second Mapping * output within the main coord array specified by "icolmain1". * interp1 * The interpolation method (0=linear, other=nearest neighbour) for * the first mapping output. * interp2 * The interpolation method (0=linear, other=nearest neighbour) for * the second mapping output. * status * Pointer to the inherited status variable. * Returned Value: * If the specified "map" outputs can be described using the -TAB * algorithm of FITS-WCS paper III, then a 2-input/2-output Mapping * from the specified WCS axes to the corresponding psi axes (i.e. * grid axes) is returned. NULL is returned otherwise, of if an error * occurs. */ /* Local Variables: */ AstMapping *ret1; /* WCS->IWC Mapping for first output */ AstMapping *ret2; /* WCS->IWC Mapping for second output */ AstMapping *ret; /* Returned WCS axis Mapping */ AstMapping *tmap; AstPermMap *pm; int *pix_axes; /* Zero-based indicies of corresponding pixel axes */ int wcs_axes[ 2 ]; /* Zero-based indicies of selected WCS axes */ int inperm[ 1 ]; int outperm[ 2 ]; /* Initialise */ ret = NULL; /* Check inherited status */ if( !astOK ) return ret; /* First see if the two required Mapping outputs are separable, in which case they can be described by two 1D tables. */ ret1 = IsMapTab1D( map, scale, unit, wcsfrm, dim, iax1, iwcs1, table, icolmain1, icolindex1, interp1, status ); ret2 = IsMapTab1D( map, scale, unit, wcsfrm, dim, iax2, iwcs2, table, icolmain2, icolindex2, interp2, status ); /* If both outputs are seperable... */ if( ret1 && ret2 ) { /* Both axes are stored as the first dimension in the corresponding main coords array. */ *max1 = 1; *max2 = 1; /* Get a Mapping from the required pair of WCS axes to the corresponding pair of grid axes. First try to split the supplied grid->wcs mapping. */ wcs_axes[ 0 ] = iax1; wcs_axes[ 1 ] = iax2; astInvert( map ); pix_axes = astMapSplit( map, 2, wcs_axes, &ret ); astInvert( map ); if( pix_axes ) { pix_axes = astFree( pix_axes ); if( astGetNout( ret ) > 2 ) { ret = astAnnul( ret ); /* If the two output WCS axes are fed by the same grid axis, we need to add another pixel axis to form the pair. */ } else if( astGetNout( ret ) == 1 ) { inperm[ 0 ] = 0; outperm[ 0 ] = 0; outperm[ 1 ] = 0; pm = astPermMap( 1, inperm, 2, outperm, NULL, " ", status ); tmap = (AstMapping *) astCmpMap( ret, pm, 1, " ", status ); ret = astAnnul( ret ); pm = astAnnul( pm ); ret = tmap; } } /* If this was unsuccessful, combine the Mappings returned by IsMapTab1D. We only do this if the above astMapSplit call failed, since the IsMapTab1D mappings may well not be independent of each other, and we may end up sticking together in parallel two mappings that are basically the same except for ending with PermMapa that select different axes. Is is hard then to simplify such a parallel CmpMap back into the simpler form that uses only one of the two identical mappings, without a PermMap. */ if( !ret ) { ret = (AstMapping *) astCmpMap( ret1, ret2, 0, " ", status ); } /* Free resources. */ ret1 = astAnnul( ret1 ); ret2 = astAnnul( ret2 ); /* If only one output is separable, remove the corresponding columns from the returned table. */ } else if( ret1 ) { ret1 = astAnnul( ret1 ); astRemoveColumn( *table, astColumnName( *table, *icolmain1 ) ); if( icolindex1 >= 0 ) astRemoveColumn( *table, astColumnName( *table, *icolindex1 ) ); } else if( ret2 ) { ret2 = astAnnul( ret2 ); astRemoveColumn( *table, astColumnName( *table, *icolmain2 ) ); if( icolindex1 >= 0 ) astRemoveColumn( *table, astColumnName( *table, *icolindex2 ) ); } /* If the required Mapping outputs were not separable, create a single 2D coords array describing both outputs. */ if( !ret ) { /* TO BE DONE... Until then non-separable Mappings will result in a failure to create a -TAB header. No point in doing this until AST has an N-dimensional LutMap class (otherwise AST could never read the resulting FITS header). */ } /* If an error occurred, free the returned Mapping. */ if( !astOK ) ret = astAnnul( ret ); /* Return the result. */ return ret; } static int IsAIPSSpectral( const char *ctype, char **wctype, char **wspecsys, int *status ){ /* * Name: * IsAIPSSpectral * Purpose: * See if a given CTYPE value describes a FITS-AIPS spectral axis. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int IsAIPSSpectral( const char *ctype, char **wctype, char **wspecsys, int *status ) * Class Membership: * FitsChan member function. * Description: * The given CTYPE value is checked to see if it conforms to the * requirements of a spectral axis CTYPE value as specified by * FITS-AIPS encoding. If so, the equivalent FITS-WCS CTYPE and * SPECSYS values are returned. * Parameters: * ctype * Pointer to a null terminated string holding the CTYPE value to * check. * wctype * The address of a location at which to return a pointer to a * static string holding the corresponding FITS-WCS CTYPE value. A * NULL pointer is returned if the supplied CTYPE string is not an * AIPS spectral CTYPE value. * wspecsys * The address of a location at which to return a pointer to a * static string holding the corresponding FITS-WCS SPECSYS value. A * NULL pointer is returned if the supplied CTYPE string is not an * AIPS spectral CTYPE value. * status * Pointer to the inherited status variable. * Retuned Value: * Non-zero fi the supplied CTYPE was an AIPS spectral CTYPE value. * Note: * - These translations are also used by the FITS-CLASS encoding. */ /* Local Variables: */ int ret; /* Initialise */ ret = 0; *wctype = NULL; *wspecsys = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* If the length of the string is not 8, then it is not an AIPS spectral axis. */ if( strlen( ctype ) == 8 ) { /* Translate AIPS spectral CTYPE values to FITS-WCS paper III equivalents. These are of the form AAAA-BBB, where "AAAA" can be "FREQ", "VELO" (=VRAD!) or "FELO" (=VOPT-F2W), and BBB can be "LSR", "LSD", "HEL" (=*Bary*centric!) or "GEO". */ if( !strncmp( ctype, "FREQ", 4 ) ){ *wctype = "FREQ "; } else if( !strncmp( ctype, "VELO", 4 ) ){ *wctype = "VRAD "; } else if( !strncmp( ctype, "FELO", 4 ) ){ *wctype = "VOPT-F2W"; } else if( !strncmp( ctype, "WAVELENG", 8 ) ){ *wctype = "WAVE "; } if( !strcmp( ctype + 4, "-LSR" ) ){ *wspecsys = "LSRK"; } else if( !strcmp( ctype + 4, "LSRK" ) ){ *wspecsys = "LSRK"; } else if( !strcmp( ctype + 4, "-LSRK" ) ){ *wspecsys = "LSRK"; } else if( !strcmp( ctype + 4, "-LSD" ) ){ *wspecsys = "LSRD"; } else if( !strcmp( ctype + 4, "-HEL" ) ){ *wspecsys = "BARYCENT"; } else if( !strcmp( ctype + 4, "-EAR" ) || !strcmp( ctype + 4, "-GEO" ) ){ *wspecsys = "GEOCENTR"; } else if( !strcmp( ctype + 4, "-OBS" ) || !strcmp( ctype + 4, "-TOP" ) ){ *wspecsys = "TOPOCENT"; } if( *wctype && *wspecsys ) { ret = 1; } else { *wctype = NULL; *wspecsys = NULL; } } /* Return the result. */ return ret; } static int IsSkyOff( AstFrameSet *fset, int iframe, int *status ){ /* * Name: * IsSkyOff * Purpose: * See if a given Frame contains an offset SkyFrame. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int IsSkyOff( AstFrameSet *fset, int iframe, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns a flag indicating if the specified Frame within the * supplied FrameSet is, or contains, a SkyFrame that represents * offset coordinates. This is the case if the Frame is a SkyFrame * and its SkyRefIs attribute is "Pole" or "Origin", or is a CmpFrame * containing such a SkyFrame. * Parameters: * fset * The FrameSet. * iframe * Index of the Frame to check within "fset" * status * Pointer to the inherited status variable. * Retuned Value: * +1 if the Frame is an offset SkyFrame. Zero otherwise. * Notes: * - Zero is returned if an error has already occurred. */ /* Local Variables: */ AstFrame *frm; const char *skyrefis; int oldrep; int result; /* Initialise. */ result = 0; /* Check the inherited status. */ if( !astOK ) return result; /* Get a pointer to the required Frame in the FrameSet */ frm = astGetFrame( fset, iframe ); /* Since the current Frame may not contain a SkyFrame, we temporarily switch off error reporting. */ oldrep = astReporting( 0 ); /* Get the SkyRefIs attribute value. */ skyrefis = astGetC( frm, "SkyRefIs" ); /* If it is "Pole" or "Origin", return 1. */ if( skyrefis && ( !Ustrcmp( skyrefis, "POLE", status ) || !Ustrcmp( skyrefis, "ORIGIN", status ) ) ) result = 1; /* Cancel any error and switch error reporting back on again. */ astClearStatus; astReporting( oldrep ); /* Annul the Frame pointer. */ frm = astAnnul( frm ); /* Return the result. */ return result; } static const char *IsSpectral( const char *ctype, char stype[5], char algcode[5], int *status ) { /* * Name: * IsSpectral * Purpose: * See if a given FITS-WCS CTYPE value describes a spectral axis. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *IsSpectral( const char *ctype, char stype[5], char algcode[5], int *status ) * Class Membership: * FitsChan member function. * Description: * The given CTYPE value is checked to see if it conforms to the * requirements of a spectral axis CTYPE value as specified by * FITS-WCS paper 3. If so, the spectral system and algorithm codes * are extracted from it and returned, together with the default units * for the spectral system. * Parameters: * ctype * Pointer to a null terminated string holding the CTYPE value to * check. * stype * An array in which to return the null-terminated spectral system type * (e.g. "FREQ", "VELO", "WAVE", etc). A null string is returned if * the CTYPE value does not describe a spectral axis. * algcode * An array in which to return the null-terminated algorithm code * (e.g. "-LOG", "", "-F2W", etc). A null string is returned if the * spectral axis is linear. A null string is returned if the CTYPE * value does not describe a spectral axis. * status * Pointer to the inherited status variable. * Retuned Value: * A point to a static string holding the default units associated * with the spectral system specified by the supplied CTYPE value. * NULL is returned if the CTYPE value does not describe a spectral * axis. * Notes: * - The axis is considered to be a spectral axis if the first 4 * characters form one of the spectral system codes listed in FITS-WCS * paper 3. The algorithm code is not checked, except to ensure that * it begins with a minus sign, or is blank. * - A NULL pointer is returned if an error has already occurred. */ /* Local Variables: */ astDECLARE_GLOBALS int ctype_len; /* Initialise */ stype[ 0 ] = 0; algcode[ 0 ] = 0; /* Check the inherited status. */ if( !astOK ) return NULL; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* Initialise more stuff */ isspectral_ret = NULL; /* If the length of the string is less than 4, then it is not a spectral axis. */ ctype_len = strlen( ctype ); if( ctype_len >= 4 ) { /* Copy the first 4 characters (the coordinate system described by the axis) into a null-terminated buffer. */ strncpy( stype, ctype, 4 ); stype[ 4 ] = 0; stype[ astChrLen( stype ) ] = 0; /* Copy any remaining characters (the algorithm code) into a null-terminated buffer. Only copy a maximum of 4 characters. */ if( ctype_len > 4 ) { if( ctype_len <= 8 ) { strcpy( algcode, ctype + 4 ); } else { strncpy( algcode, ctype + 4, 4 ); algcode[ 4 ] = 0; } algcode[ astChrLen( algcode ) ] = 0; } else { algcode[ 0 ] = 0; } /* See if the first 4 characters of the CTYPE value form one of the legal spectral coordinate type codes listed in FITS-WCS Paper III. Also note the default units associated with the system. */ if( !strcmp( stype, "FREQ" ) ) { isspectral_ret = "Hz"; } else if( !strcmp( stype, "ENER" ) ) { isspectral_ret = "J"; } else if( !strcmp( stype, "WAVN" ) ) { isspectral_ret = "/m"; } else if( !strcmp( stype, "VRAD" ) ) { isspectral_ret = "m/s"; } else if( !strcmp( stype, "WAVE" ) ) { isspectral_ret = "m"; } else if( !strcmp( stype, "VOPT" ) ) { isspectral_ret = "m/s"; } else if( !strcmp( stype, "ZOPT" ) ) { isspectral_ret = ""; } else if( !strcmp( stype, "AWAV" ) ) { isspectral_ret = "m"; } else if( !strcmp( stype, "VELO" ) ) { isspectral_ret = "m/s"; } else if( !strcmp( stype, "BETA" ) ) { isspectral_ret = ""; } /* Also check that the remaining part of CTYPE (the algorithm code) begins with a minus sign or is blank. */ if( algcode[ 0 ] != '-' && strlen( algcode ) > 0 ) isspectral_ret = NULL; } /* Return null strings if the axis is not a spectral axis. */ if( ! isspectral_ret ) { stype[ 0 ] = 0; algcode[ 0 ] = 0; } /* Return the result. */ return isspectral_ret; } static AstMapping *LinearWcs( FitsStore *store, int i, char s, const char *method, const char *class, int *status ) { /* * Name: * LinearWcs * Purpose: * Create a Mapping describing a FITS-WCS linear algorithm * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *LinearWcs( FitsStore *store, int i, char s, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function uses the contents of the supplied FitsStore to create * a Mapping which goes from Intermediate World Coordinate (known as "w" * in the context of FITS-WCS paper III) to a linearly related axis. * * The returned Mapping is a ShiftMap which simply adds on the value of * CRVALi. * Parameters: * store * Pointer to the FitsStore structure holding the values to use for * the WCS keywords. * i * The zero-based index of the spectral axis within the FITS header * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a Mapping, or NULL if an error occurs. */ /* Local Variables: */ AstMapping *ret; double crv; /* Check the global status. */ ret = NULL; if( !astOK ) return ret; /* Get the CRVAL value for the specified axis. */ crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( crv == AST__BAD ) crv = 0.0; /* Create a 1D ShiftMap which adds this value onto the IWCS value. */ if( crv != 0.0 ) { ret = (AstMapping *) astShiftMap( 1, &crv, "", status ); } else { ret = (AstMapping *) astUnitMap( 1, "", status ); } return ret; } static AstMapping *LogAxis( AstMapping *map, int iax, int nwcs, double *lbnd_p, double *ubnd_p, double crval, int *status ){ /* * Name: * LogAxes * Purpose: * Test a Frame axis to see if it logarithmically spaced in pixel coords. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *LogAxis( AstMapping *map, int iax, int nwcs, double *lbnd_p, * double *ubnd_p, double crval ) * Class Membership: * FitsChan member function. * Description: * A specified axis of the supplied Mappinhg is tested to see if it * corresponds to the form * * S = Sr.exp( w/Sr ) * * where "w" is one of the Mapping inputs, "S" is the specified * Mapping output, and "Sr" is the supplied value of "crval". This * is the form for a FITS log axis as defined in FITS-WCS paper III. * * If the above test is passed, a Mapping is returned from "S" to "w" * (the inverseof the above expression). * Parameters: * map * Pointer to the Mapping. This will usually be a Mapping from * pixel coords to WCS coords. * iax * The index of the output of "map" which correspoinds to "S". * nwcs * The number of outputs from "map". * lbnd_p * Pointer to an array of double, with one element for each * Mapping input coordinate. This should contain the lower bound * of the input pixel box in each input dimension. * ubnd_p * Pointer to an array of double, with one element for each * Mapping input coordinate. This should contain the upper bound * of the input pixel box in each input dimension. * crval * The reference value ("Sr") to use. Must not be zero. * Returned Value: * If the specified axis is logarithmically spaced, a Mapping with * "nwcs" inputs and "nwcs" outputs is returned. This Mapping transforms * its "iax"th input using the transformation: * * w = Sr.Log( S/Sr ) * * (where "S" is the Mapping is the "iax"th input and "w" is the * "iax"th output). Other inputs are copied to the corresponding * output without change. NULL is returned if the specified axis is * not logarithmically spaced. */ /* Local Variables: */ AstMapping *result; /* Returned Mapping */ AstMapping *tmap0; /* A temporary Mapping */ AstMapping *tmap1; /* A temporary Mapping */ AstMapping *tmap2; /* A temporary Mapping */ AstMapping *tmap3; /* A temporary Mapping */ AstMapping *tmap4; /* A temporary Mapping */ const char *fexps[ 1 ]; /* Forward MathMap expressions */ const char *iexps[ 1 ]; /* Inverse MathMap expressions */ /* Initialise */ result = NULL; /* Check the inherited status and crval value. */ if( !astOK || crval == 0.0 ) return result; /* If the "log" algorithm is appropriate, the supplied axis (s) is related to pixel coordinate (p) by s = Sr.EXP( a*p - b ). If this is the case, then the log of s will be linearly related to pixel coordinates. To test this, we create a CmpMap which produces log(s). */ fexps[ 0 ] = "logs=log(s)"; iexps[ 0 ] = "s=exp(logs)"; tmap1 = (AstMapping *) astMathMap( 1, 1, 1, fexps, 1, iexps, "simpfi=1,simpif=1", status ); tmap2 = AddUnitMaps( tmap1, iax, nwcs, status ); tmap0 = (AstMapping *) astCmpMap( map, tmap2, 1, "", status ); tmap2 = astAnnul( tmap2 ); /* See if this Mapping is linear. */ if( IsMapLinear( tmap0, lbnd_p, ubnd_p, iax, status ) ) { /* Create the Mapping which defines the IWC axis. This is the Mapping from WCS to IWCS - "W = Sr.log( S/Sr )". Other axes are left unchanged by the Mapping. The IWC axis has the same axis index as the WCS axis. */ tmap2 = (AstMapping *) astZoomMap( 1, 1.0/crval, "", status ); tmap3 = (AstMapping *) astCmpMap( tmap2, tmap1, 1, "", status ); tmap2 = astAnnul( tmap2 ); tmap2 = (AstMapping *) astZoomMap( 1, crval, "", status ); tmap4 = (AstMapping *) astCmpMap( tmap3, tmap2, 1, "", status ); tmap3 = astAnnul( tmap3 ); tmap2 = astAnnul( tmap2 ); result = AddUnitMaps( tmap4, iax, nwcs, status ); tmap4 = astAnnul( tmap4 ); } /* Free resources. */ tmap0 = astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); /* Return the result. */ return result; } static AstMapping *LogWcs( FitsStore *store, int i, char s, const char *method, const char *class, int *status ) { /* * Name: * LogWcs * Purpose: * Create a Mapping describing a FITS-WCS logarithmic algorithm * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *LogWcs( FitsStore *store, int i, char s, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function uses the contents of the supplied FitsStore to create * a Mapping which goes from Intermediate World Coordinate (known as "w" * in the context of FITS-WCS paper III) to a logarthmic version of w * called "S" given by: * * S = Sr.exp( w/Sr ) * * where Sr is the value of S corresponding to w=0. * Parameters: * store * Pointer to the FitsStore structure holding the values to use for * the WCS keywords. * i * The zero-based index of the axis within the FITS header * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a Mapping, or NULL if an error occurs. */ /* Local Variables: */ AstMapping *ret; char forexp[ 12 + DBL_DIG*2 ]; char invexp[ 12 + DBL_DIG*2 ]; const char *fexps[ 1 ]; const char *iexps[ 1 ]; double crv; /* Check the global status. */ ret = NULL; if( !astOK ) return ret; /* Get the CRVAL value for the specified axis. Use a default of zero. */ crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( crv == AST__BAD ) crv = 0.0; /* Create the MathMap, if possible. */ if( crv != 0.0 ) { sprintf( forexp, "s=%.*g*exp(w/%.*g)", DBL_DIG, crv, DBL_DIG, crv ); sprintf( invexp, "w=%.*g*log(s/%.*g)", DBL_DIG, crv, DBL_DIG, crv ); fexps[ 0 ] = forexp; iexps[ 0 ] = invexp; ret = (AstMapping *) astMathMap( 1, 1, 1, fexps, 1, iexps, "simpfi=1,simpif=1", status ); } /* Return the result */ return ret; } static int LooksLikeClass( AstFitsChan *this, const char *method, const char *class, int *status ){ /* * Name: * LooksLikeClass * Purpose: * Does the FitsChan seem to use FITS-CLASS encoding? * Type: * Private function. * Synopsis: * #include "fitschan.h" * int LooksLikeClass( AstFitsChan *this, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns non-zero if the supplied FitsChan probably uses FITS-CLASS * encoding. This is the case if it contains a DELTAV keyword and a * keyword of the form VELO-xxx", where xxx is one of the accepted * standards of rest, or "VLSR". * Parameters: * this * Pointer to the FitsChan. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the encoding in use lookslike FITS-CLASS. */ /* Local Variables... */ int ret; /* Returned value */ /* Initialise */ ret = 0; /* Check the global status. */ if( !astOK ) return ret; /* See if there is a "DELTAV" card, and a "VELO-xxx" or "VLSR" card. */ if( astKeyFields( this, "DELTAV", 0, NULL, NULL ) && ( astKeyFields( this, "VLSR", 0, NULL, NULL ) || astKeyFields( this, "VELO-OBS", 0, NULL, NULL ) || astKeyFields( this, "VELO-HEL", 0, NULL, NULL ) || astKeyFields( this, "VELO-EAR", 0, NULL, NULL ) || astKeyFields( this, "VELO-LSR", 0, NULL, NULL ) ) ) { ret = 1; } /* Return the result. */ return ret; } static void MakeBanner( const char *prefix, const char *middle, const char *suffix, char banner[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int *status ) { /* * Name: * MakeBanner * Purpose: * Create a string containing a banner comment. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void MakeBanner( const char *prefix, const char *middle, * const char *suffix, * char banner[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int *status ) * Class Membership: * FitsChan member function. * Description: * This function creates a string which can be written as a FITS * comment card to produce a banner heading (or tail) for an AST * Object when it is written to a FitsChan. The banner will occupy * the maximum permitted width for text in a FITS comment card. * Parameters: * prefix * A pointer to a constant null-terminated string containing the * first part of the text to appear in the banner. * middle * A pointer to a constant null-terminated string containing the * second part of the text to appear in the banner. * suffix * A pointer to a constant null-terminated string containing the * third part of the text to appear in the banner. * banner * A character array to receive the null-terminated result string. * status * Pointer to the inherited status variable. * Notes: * - The text to appear in the banner is constructed by * concatenating the three input strings supplied. */ /* Local Variables: */ char token[] = "AST"; /* Identifying token */ int i; /* Loop counter for input characters */ int len; /* Number of output characters */ int ltok; /* Length of token string */ int mxlen; /* Maximum permitted output characters */ int start; /* Column number where text starts */ /* Check the global error status. */ if ( !astOK ) return; /* Calculate the maximum number of characters that the output banner can hold and the length of the token string. */ mxlen = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN; ltok = (int) strlen( token ); /* Calculate the column in which to start the text, so that it is centred in the banner (with 4 non-text characters on each side). */ start = ltok + 2 + ( mxlen - ltok - 1 - (int) ( strlen( prefix ) + strlen( middle ) + strlen( suffix ) ) - 1 - ltok ) / 2; if ( start < ltok + 2 ) start = ltok + 2; /* Start building the banner with the token string. */ len = 0; for ( i = 0; token[ i ] && ( len < mxlen ); i++ ) { banner[ len++ ] = token[ i ]; } /* Then pad with spaces up to the start of the text. */ while ( len < start - 1 ) banner[ len++ ] = ' '; /* Insert the prefix data, truncating it if it is too long. */ for ( i = 0; prefix[ i ] && ( len < mxlen - ltok - 1 ); i++ ) { banner[ len++ ] = prefix[ i ]; } /* Insert the middle data, truncating it if it is too long. */ for ( i = 0; middle[ i ] && ( len < mxlen - ltok - 1 ); i++ ) { banner[ len++ ] = middle[ i ]; } /* Insert the suffix data, truncating it if it is too long. */ for ( i = 0; suffix[ i ] && ( len < mxlen - ltok - 1 ); i++ ) { banner[ len++ ] = suffix[ i ]; } /* Pad the end of the text with spaces. */ while ( len < mxlen - ltok ) banner[ len++ ] = ' '; /* Finish the banner with the token string. */ for ( i = 0; token[ i ] && ( len < mxlen ); i++ ) { banner[ len++ ] = token[ i ]; } /* Terminate the output string. */ banner[ len ] = '\0'; } static AstMapping *MakeColumnMap( AstFitsTable *table, const char *col, int isindex, int interp, const char *method, const char *class, int *status ){ /* * Name: * MakeColumnMap * Purpose: * Create a Mapping describing a look-up table supplied in a cell of a * FITS binary table. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *MakeColumnMap( AstFitsTable *table, const char *col, * int isindex, int interp, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a Mapping representing the array of values * stored in row 1 of a named column of a supplied FitsTable. The * array of values is treated as a look-up table following the prescription * of FITS-WCS paper III (the "-TAB" algorithm). If the array has (N+1) * dimensions (where N is one or more), the returned Mapping has N * inputs and N outputs. The inputs correspond to FITS GRID coords * within the array. FITS-WCS paper III requires that the first dimension * in the array has a length of "N" and contains the N output values * at each input values. * Parameters: * table * Pointer to the Fitstable. * col * A string holding the name of the column to use. * isindex * Non-zero if the column hold an index array, zero if it holds a * coordinate array. * interp * The value to use for the Interp attribute of the LutMap. A value * of zero tells the LutMap class to use linear interpolation. Other * values tell the LutMap class to use nearest neighbour interpolation. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping, or NULL if an error occurs. */ /* Local Variables: */ AstMapping *result; char *key; double *lut; int *dims; int ndim; int nel; /* Initialise */ result = NULL; /* Check the inherited status */ if( !astOK ) return result; /* Get the number of dimensions spanned by the value in the named column. */ ndim = astGetColumnNdim( table, col ); /* First deal with index vectors. */ if( isindex ) { /* FITS-WCS paper II mandates that index arrays must be 1-dimensional. */ if( ndim != 1 && astOK ) { astError( AST__BADTAB, "%s(%s): Column '%s' has %d dimensions but it " "holds an index vector and should therefore be 1-dimensional.", status, method, class, col, ndim ); } /* Get the length of the index vector. */ nel = astGetColumnLength( table, col ); /* Allocate memory to hold the array values, and to hold the cell key. */ lut = astMalloc( nel*sizeof( double ) ); key = astMalloc( strlen( col ) + 5 ); if( astOK ) { /* Create the key for the table cell holding the required array. FITS-WCS paper III mandates that tables always occur in the first row of the table (and that the table only has one row). Ignore trailing spaces in the column name. */ sprintf( key, "%.*s(1)", (int) astChrLen( col ), col ); /* Copy the array values into the above memory. */ if( astMapGet1D( table, key, nel, &nel, lut ) ) { /* Create a 1D LutMap. FITS-WCS paper III (sec 6.1.2) mandates that the input corresponds to FITS grid coord (i.e. 1.0 at the centre of the first entry). Ensure the LutMap uses linear interpolation. */ result = (AstMapping *) astLutMap( nel, lut, 1.0, 1.0, "LutInterp=%d", status, interp ); /* Report an error if the table cell was empty. */ } else if( astOK ) { astError( AST__BADTAB, "%s(%s): Row 1 of the binary table " "contains no value for column '%s'.", status, method, class, col ); } } /* Free memory. */ lut = astFree( lut ); key = astFree( key ); /* Now deal with coordinate arrays. */ } else { /* Get the shape of the array. */ dims = astMalloc( sizeof( int )*ndim ); astColumnShape( table, col, ndim, &ndim, dims ); /* For coordinate arrays, check the length of the first axis is "ndim-1", as required by FITS-WCS paper III. */ if( astOK && dims[ 0 ] != ndim - 1 && !isindex ) { astError( AST__BADTAB, "%s(%s): The first dimension of the coordinate " "array has length %d (should be %d since the array has %d " "dimensions).", status, method, class, dims[ 0 ], ndim - 1, ndim ); } /* We can currently only handle 1D look-up tables. These are stored in notionally two-dimensional arrays in which the first dimension is degenarate (i.e. spans only a single element). */ if( ndim > 2 ) { if( astOK ) astError( AST__INTER, "%s(%s): AST can currently only " "handle 1-dimensional coordinate look-up tables " "(the supplied table has %d dimensions).", status, method, class, ndim - 1 ); /* Handle 1-dimensional look-up tables. */ } else if( astOK ){ /* Allocate memory to hold the array values, and to hold the cell key. */ lut = astMalloc( dims[ 1 ]*sizeof( double ) ); key = astMalloc( strlen( col ) + 5 ); if( astOK ) { /* Create the key for the table cell holding the required array. FITS-WCS paper III mandates that tables always occur in the first row of the table (and that the table only has one row). Ignore trailing spaces in the column name. */ sprintf( key, "%.*s(1)", (int) astChrLen( col ), col ); /* Copy the array values into the above memory. */ if( astMapGet1D( table, key, dims[ 1 ], dims, lut ) ) { /* Create a 1D LutMap. FITS-WCS paper III (sec 6.1.2) mandates that the input corresponds to FITS grid coord (i.e. 1.0 at the centre of the first entry). Ensure the LutMap uses linear interpolation. */ result = (AstMapping *) astLutMap( dims[ 1 ], lut, 1.0, 1.0, "LutInterp=%d", status, interp ); /* Report an error if the table cell was empty. */ } else if( astOK ) { astError( AST__BADTAB, "%s(%s): Row 1 of the binary table " "contains no value for column '%s'.", status, method, class, col ); } } /* Free memory. */ lut = astFree( lut ); key = astFree( key ); } dims = astFree( dims ); } /* Issue a context message and annul the returned Mapping if an error has occurred. */ if( !astOK ) { astError( astStatus, "%s(%s): Cannot read a look-up table for a " "tabular WCS axis from column '%s' of a FITS binary table.", status, method, class, col ); result = astAnnul( result ); } /* Return the result. */ return result; } static AstFrameSet *MakeFitsFrameSet( AstFitsChan *this, AstFrameSet *fset, int ipix, int iwcs, int encoding, const char *method, const char *class, int *status ) { /* * Name: * MakeFitsFrameSet * Purpose: * Create a FrameSet which conforms to the requirements of the FITS-WCS * papers. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstFrameSet *MakeFitsFrameSet( AstFitsChan *this, AstFrameSet *fset, * int ipix, int iwcs, int encoding, * const char *method, const char *class, * int *status ) * Class Membership: * FitsChan member function. * Description: * This function constructs a new FrameSet holding the pixel and WCS * Frames from the supplied FrameSet, but optionally extends the WCS * Frame to include any extra axes needed to conform to the FITS model. * Currently, this function does the following: * * - if the WCS Frame contains a spectral axis with a defined celestial * reference position (SpecFrame attributes RefRA and RefDec), then * it ensures that the WCS Frame also contains a pair of celestial * axes (such axes are added if they do not already exist within the * supplied WCS Frame). The pixel->WCS Mapping is adjusted accordingly. * * - if the WCS Frame contains a spectral axis and a pair of celestial * axes, then the SpecFrame attributes RefRA and RefDec are set to the * reference position defined by the celestial axes. The pixel->WCS * Mapping is adjusted accordingly. * * - NULL is returned if the WCS Frame contains more than one spectral * axis. * * - NULL is returned if the WCS Frame contains more than one pair of * celestial axes. * Parameters: * this * The FitsChan. * fset * The FrameSet to check. * ipix * The index of the FITS pixel Frame within "fset". * iwcs * The index of the WCS Frame within "fset". * encoding * The encoding in use. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A new FrameSet which confoms to the requirements of the FITS-WCS * papers. The base Frame in this FrameSet will be the FITS pixel * Frame, and the current Frame will be the WCS Frame. NULL is * returned if an error has already occurred, or if the FrameSet cannot * be produced for any reason. */ /* Local Variables: */ AstFitsChan *fc; /* Pointer to temporary FitsChan */ AstFrame *pframe; /* Pointer to the primary Frame */ AstFrame *pixfrm; /* Pointer to the FITS pixel Frame */ AstFrame *tfrm0; /* Pointer to a temporary Frame */ AstFrame *tfrm; /* Pointer to a temporary Frame */ AstFrame *wcsfrm; /* Pointer to the FITS WCS Frame */ AstFrameSet *ret; /* The returned FrameSet */ AstFrameSet *tfs; /* Pointer to a temporary FrameSet */ AstMapping *map1; /* Pointer to pre-WcsMap Mapping */ AstMapping *map3; /* Pointer to post-WcsMap Mapping */ AstMapping *map; /* Pointer to the pixel->wcs Mapping */ AstMapping *tmap0; /* Pointer to a temporary Mapping */ AstMapping *tmap1; /* Pointer to a temporary Mapping */ AstMapping *tmap2; /* Pointer to a temporary Mapping */ AstMapping *tmap; /* Pointer to a temporary Mapping */ AstSpecFrame *skyfrm; /* Pointer to the SkyFrame within WCS Frame */ AstSpecFrame *specfrm; /* Pointer to the SpecFrame within WCS Frame */ AstWcsMap *map2; /* Pointer to WcsMap */ char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* A FITS header card */ char equinox_attr[ 13 ];/* Name of Equinox attribute for sky axes */ char system_attr[ 12 ]; /* Name of System attribute for sky axes */ const char *eqn; /* Pointer to original sky Equinox value */ const char *skysys; /* Pointer to original sky System value */ double con; /* Constant axis value */ double reflat; /* Celestial latitude at reference point */ double reflon; /* Celestial longitude at reference point */ int *perm; /* Pointer to axis permutation array */ int iax; /* Axis inex */ int icurr; /* Index of original current Frame in returned FrameSet */ int ilat; /* Celestial latitude index within WCS Frame */ int ilon; /* Celestial longitude index within WCS Frame */ int npix; /* Number of pixel axes */ int nwcs; /* Number of WCS axes */ int ok; /* Is the supplied FrameSet usable? */ int paxis; /* Axis index within the primary Frame */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Get copies of the pixel Frame, the WCS Frame and the Mapping. */ tfrm = astGetFrame( fset, ipix ); pixfrm = astCopy( tfrm ); tfrm = astAnnul( tfrm ); tfrm = astGetFrame( fset, iwcs ); wcsfrm = astCopy( tfrm ); tfrm = astAnnul( tfrm ); tmap = astGetMapping( fset, ipix, iwcs ); map = astCopy( tmap ); tmap = astAnnul( tmap ); /* Store the number of pixel and WCS axes. */ npix = astGetNaxes( pixfrm ); nwcs = astGetNaxes( wcsfrm ); /* Search the WCS Frame for SkyFrames and SpecFrames. */ specfrm = NULL; skyfrm = NULL; ok = 1; ilat = -1; ilon = -1; for( iax = 0; iax < nwcs; iax++ ) { /* Obtain a pointer to the primary Frame containing the current WCS axis. */ astPrimaryFrame( wcsfrm, iax, &pframe, &paxis ); /* If the current axis is a SpecFrame, save a pointer to it. If we have already found a SpecFrame, abort. */ if( astIsASpecFrame( pframe ) ) { if( specfrm ) { ok = 0; break; } specfrm = astClone( pframe ); /* If the current axis is a SkyFrame, save a pointer to it, and its WCS index. If we have already found a different SkyFrame, abort. */ } else if( astIsASkyFrame( pframe ) ) { if( skyfrm ) { if( pframe != (AstFrame *) skyfrm ) { ok = 0; break; } } else { skyfrm = astClone( pframe ); } if( paxis == 0 ) { ilon = iax; } else { ilat = iax; } } /* Free resources. */ pframe = astAnnul( pframe ); } /* If the supplied FrameSet is usable... */ if( ok ) { /* If we did not find a SpecFrame, return a FrameSet made from the base and current Frames in the supplied FrameSet. */ if( !specfrm ) { ret = astFrameSet( pixfrm, "", status ); astAddFrame( ret, AST__BASE, map, wcsfrm ); /* If we have a SpecFrame, proceed. */ } else { /* Check that both the RefRA and RefDec attributes of the SpecFrame are set. If not, return a FrameSet made from the base and current Frames in the supplied FrameSet.*/ if( !astTestRefRA( specfrm ) || !astTestRefDec( specfrm ) ) { ret = astFrameSet( pixfrm, "", status ); astAddFrame( ret, AST__BASE, map, wcsfrm ); /* If we have a celestial reference position for the spectral axis, ensure it is described correctly by a pair of celestial axes. */ } else { /* If the WCS Frame does not contain any celestial axes, we add some now. */ if( !skyfrm ) { /* The easiest way to create the required mapping from pixel to celestial to create a simple FITS header and read it in via a FitsChan to create a FrameSet. */ fc = astFitsChan( NULL, NULL, "", status ); astPutFits( fc, "CRPIX1 = 0", 0 ); astPutFits( fc, "CRPIX2 = 0", 0 ); astPutFits( fc, "CDELT1 = 0.0003", 0 ); astPutFits( fc, "CDELT2 = 0.0003", 0 ); astPutFits( fc, "CTYPE1 = 'RA---TAN'", 0 ); astPutFits( fc, "CTYPE2 = 'DEC--TAN'", 0 ); astPutFits( fc, "RADESYS = 'FK5'", 0 ); astPutFits( fc, "EQUINOX = 2000.0", 0 ); sprintf( card, "CRVAL1 = %.*g", DBL_DIG, AST__DR2D*astGetRefRA( specfrm ) ); astPutFits( fc, card, 0 ); sprintf( card, "CRVAL2 = %.*g", DBL_DIG, AST__DR2D*astGetRefDec( specfrm ) ); astPutFits( fc, card, 0 ); sprintf( card, "MJD-OBS = %.*g", DBL_DIG, TDBConv( astGetEpoch( specfrm ), AST__UTC, 1, "astWrite", "FitsChan", status ) ); astPutFits( fc, card, 0 ); astClearCard( fc ); tfs = astRead( fc ); if( tfs ) { /* Create the new pixel->wcs Mapping. First get the 2-input,2-output Mapping between pixel and sky coords from the above FrameSet. Then add this Mapping in parallel with the original pixel->wcs Mapping. */ tmap0 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); tmap1 = (AstMapping *) astCmpMap( map, tmap0, 0, "", status ); tmap0 = astAnnul( tmap0 ); /* We now have a (npix+2)-input,(nwcs+2)-output Mapping. We now add a PermMap in series with this which feeds the constant value 0.0 (the CRPIX value in the above set of FITS headers) into the 2 pixel axes corresponding to RA and Dec. This PermMap has npix-inputs and (npix+2) outputs. The total Mapping then has npix inputs and (nwcs+2) outputs. */ perm = astMalloc( sizeof( int )*(size_t) ( npix + 2 ) ); if( astOK ) { for( iax = 0; iax < npix; iax++ ) perm[ iax ] = iax; perm[ npix ] = -1; perm[ npix + 1 ] = -1; con = 0.0; tmap0 = (AstMapping *) astPermMap( npix, perm, npix + 2, perm, &con, "", status ); tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, "", status ); tmap0 = astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); /* We now create the new WCS Frame with the extra RA and Dec axes. This is just a CmpFrame made up of the original WCS Frame and the new SkyFrame. */ tfrm = astGetFrame( tfs, AST__CURRENT ); tfrm0 = (AstFrame *) astCmpFrame( wcsfrm, tfrm, "", status ); tfrm = astAnnul( tfrm ); /* Construct the returned FrameSet. */ ret = astFrameSet( pixfrm, "", status ); astAddFrame( ret, AST__BASE, tmap2, tfrm0 ); tmap2 = astAnnul( tmap2 ); tfrm0 = astAnnul( tfrm0 ); /* Free remaining resources. */ perm = astFree( perm ); } tfs = astAnnul( tfs ); } fc = astAnnul( fc ); /* If the WCS Frame does contain celestial axes we make sure that the SpecFrame uses the same reference point. */ } else { /* The returned FrameSet has no extra Frames (although some attributes may be changed) so just create a new FrameSet equaivalent to the supplied FrameSet. */ tfs = astFrameSet( pixfrm, "", status ); astAddFrame( tfs, AST__BASE, map, wcsfrm ); /* The RefRA and RefDec attributes of the SpecFrame must be set in FK5 J2000. Therefore we need to know the celestial reference point in FK5 J2000. Modify the SkyFrame within the FrameSet to represent FK5 J2000, noting the original sky system and equinox first so that they can be re-instated (if set) later on. */ sprintf( system_attr, "System(%d)", ilon + 1 ); if( astTest( tfs, system_attr ) ) { skysys = astGetC( tfs, system_attr ); } else { skysys = NULL; } astSetC( tfs, system_attr, "FK5" ); sprintf( equinox_attr, "Equinox(%d)", ilon + 1 ); if( astTest( tfs, equinox_attr ) ) { eqn = astGetC( tfs, equinox_attr ); } else { eqn = NULL; } astSetC( tfs, equinox_attr, "J2000" ); /* The reference point for the celestial axes is defined by the WcsMap contained within the Mapping. Split the mapping up into a list of serial component mappings, and locate the first WcsMap in this list. The first Mapping returned by this call is the result of compounding all the Mappings up to (but not including) the WcsMap, the second returned Mapping is the (inverted) WcsMap, and the third returned Mapping is anything following the WcsMap. Only proceed if one and only one WcsMap is found. */ tmap0 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); if( SplitMap( tmap0, astGetInvert( tmap0 ), ilon, ilat, &map1, &map2, &map3, status ) ){ /* The reference point in the celestial coordinate system is found by transforming the fiducial point in native spherical co-ordinates into absolute physical coordinates using map3. */ if( GetFiducialWCS( map2, map3, ilon, ilat, &reflon, &reflat, status ) ){ /* Use reflon and reflat (which represent FK5 J2000 RA and Dec) to set the values of the SpecFrame RefRA and RefDec attributes. Format the values first so that we can use the FrameSet astSetC method, and so maintain the FrameSet integrity. */ astSetC( tfs, "RefRA", astFormat( wcsfrm, ilon, reflon ) ); astSetC( tfs, "RefDec", astFormat( wcsfrm, ilat, reflat ) ); /* If succesfull, return a pointer to the FrameSet. */ if( astOK ) ret = astClone( tfs ); } /* Release resources. */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); /* If no WcsMap was found, the celestial axes have no reference point and so we can retain the original spectral reference point, so just return the temporary FrameSet. */ } else if( astOK ) { ret = astClone( tfs ); } tmap0 = astAnnul( tmap0 ); /* Re-instate the original sky system and equinox. */ if( skysys ) astSetC( tfs, system_attr, skysys ); if( eqn ) astSetC( tfs, equinox_attr, eqn ); /* Release resources. */ tfs = astAnnul( tfs ); } } } } /* Add a new current Frame into the FrameSet which increases the chances of the requested encoding being usable. The index of the original current Frame is returned, or AST__NOFRAME if no new Frame was added. */ icurr = AddEncodingFrame( this, ret, encoding, method, class, status ); /* If a new Frame was added, remove the original current Frame. */ if( icurr != AST__NOFRAME ) astRemoveFrame( ret, icurr ); /* Free resources. */ if( specfrm ) specfrm = astAnnul( specfrm ); if( skyfrm ) skyfrm = astAnnul( skyfrm ); pixfrm = astAnnul( pixfrm ); wcsfrm = astAnnul( wcsfrm ); map = astAnnul( map ); /* Return NULL if an error has occurred. */ if( !astOK && ret ) ret = astAnnul( ret ); /* Return the result. */ return ret; } static void MakeIndentedComment( int indent, char token, const char *comment, const char *data, char string[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int *status ) { /* * Name: * MakeIndentedComment * Purpose: * Create a comment string containing an indentation bar. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void MakeIndentedComment( int indent, char token, * const char *comment, const char *data, * char string[ AST__FITSCHAN_FITSCARDLEN - * FITSNAMLEN + 1 ], int *status ) * Class Membership: * FitsChan member function. * Description: * This function creates a string that may be used as text in a * FITS comment card. The string contains a textual comment * preceded by a bar (a line of characters) whose length can be * used to indicate a level of indentation (in the absence of any * way of indenting FITS keywords). * Parameters: * indent * The level of indentation, in characters. * token * The character used to form the indentation bar. * comment * A pointer to a constant null-terminated string containing the text * of the comment to be included. * data * A pointer to a constant null-terminated string containing any * textual data to be appended to the comment. * string * A character array to receive the output string. * status * Pointer to the inherited status variable. * Notes: * - The comment text that appears in the output string is formed by * concatenating the "comment" and "data" strings. */ /* Local Variables: */ int i; /* Loop counter for input characters */ int len; /* Number of output characters */ int mxlen; /* Maximum length of output string */ /* Check the global error status. */ if ( !astOK ) return; /* Calculate the maximum number of characters that the output string can accommodate. */ mxlen = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN; /* Start the string with "indent" copies of the token character, but without exceeding the output string length. */ len = 0; while ( ( len < indent ) && ( len < mxlen ) ) string[ len++ ] = token; /* Pad with spaces up to the start of the comment, if necessary. */ while ( len < ( FITSCOMCOL - FITSNAMLEN - 1 ) ) { string[ len++ ] = ' '; } /* Add "/ " to introduce the comment (strictly not necessary as the whole card will be a comment, but it matches the other non-comment cards). Truncate if necessary. */ for ( i = 0; ( i < 2 ) && ( len < mxlen ); i++ ) { string[ len++ ] = "/ "[ i ]; } /* Append the comment string, truncating it if it is too long. */ for ( i = 0; comment[ i ] && ( len < mxlen ); i++ ) { string[ len++ ] = comment[ i ]; } /* Append the data string, again truncating if too long. */ for ( i = 0; data[ i ] && ( len < mxlen ); i++ ) { string[ len++ ] = data[ i ]; } /* Terminate the output string. */ string[ len ] = '\0'; } static void MakeIntoComment( AstFitsChan *this, const char *method, const char *class, int *status ){ /* * Name: * MakeIntoComment * Purpose: * Convert a card into a FITS COMMENT card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void MakeIntoComment( AstFitsChan *this, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function formats the card stored just prior to the current card, * and re-stores it as a COMMENT card. It is used (when writing an Object * to a FitsChan) to output values that are not "set" and which are * therefore provided for information only, and should not be read back. * the COMMENT card has the effect of "commenting out" the value. * Parameters: * this * Pointer to the FitsChan. * method * Calling method. * class * Object class. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Character buffer for FITS card data */ /* Check the global error status. */ if ( !astOK ) return; /* Move the current card backwards by one card. */ MoveCard( this, -1, method, class, status ); /* Format the new current card. */ FormatCard( this, card, method, status ); /* Write the resulting string to the FitsChan as the contents of a COMMENT card, overwriting the existing card. The current card is incremented by this call so that it refers to the same card as on entry. */ astSetFitsCom( this, "COMMENT", card, 1 ); } static int MakeIntWorld( AstMapping *cmap, AstFrame *fr, int *wperm, char s, FitsStore *store, double *dim, const char *method, const char *class, int *status ){ /* * Name: * MakeIntWorld * Purpose: * Create FITS header values which map grid into intermediate world * coords. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int MakeIntWorld( AstMapping *cmap, AstFrame *fr, int *wperm, char s, * FitsStore *store, double *dim, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function adds values to the supplied FitsStore which describe * the transformation from grid (pixel) coords to intermediate world * coords. The values added to the FitsStore correspond to the CRPIXj, * PCi_j, CDELTi and WCSAXES keywords, and are determined by examining the * suppliedMapping, which must be linear with an optional shift of * origin (otherwise a value of zero is returned). * * Much of the complication in the algorithm arises from the need to * support cases where the supplied Mapping has more outputs than * inputs. In these case we add some "degenerate" axes to the grid * coord system, choosing their unit vectors to be orthogonal to all * the other grid axes. It is assumed that degenerate axes will never * be used to find a position other than at the axis value of 1.0. * * NOTE, appropriate values for CRVAL keywords should have been stored * in the FitsStore before calling this function (since this function may * modify them). * Parameters: * cmap * A pointer to a Mapping which transforms grid coordinates into * intermediate world coordinates. The number of outputs must be * greater than or equal to the number of inputs. * fr * Pointer to the final WCS coordinate Frame. * wperm * Pointer to an array of integers with one element for each axis of * the "fr" Frame. Each element holds the zero-based index of the * FITS-WCS axis (i.e. the value of "i" in the keyword names "CTYPEi", * "CDi_j", etc) which describes the Frame axis. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * store * A pointer to the FitsStore into which the calculated CRPIX and * CDi_j values are to be put. * dim * An array holding the image dimensions in pixels. AST__BAD can be * supplied for any unknwon dimensions. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if the CRPIX and CDi_j values are * succesfully calculated. Zero is returned otherwise. * Notes: * - Zero is returned if an error occurs. */ /* Local Variables: */ AstFrame *pfrm; AstFrame *sfrm; AstMapping *map; AstPointSet *psetw; AstPointSet *psetg; double **fullmat; double **partmat; double **ptrg; double **ptrw; double *c; double *cdelt; double *cdmat; double *colvec; double *d; double *g; double *g0; double *m; double *mat; double *tol; double *w0; double *y; double cd; double crp; double crv; double cv; double det; double err; double k; double mxcv; double skydiag1; double skydiag0; double val; int *iw; int *lin; int *pperm; int *skycol; int i; int ii; int j; int jax; int jj; int nin; int nout; int nwcs; int paxis; int ret; int sing; int skycol0; int skycol1; /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Simplify the supplied Mapping to reduce rounding errors when transforming points. */ map = astSimplify( cmap ); /* Get the number of inputs and outputs for the Mapping. Return if the number of outputs is smaller than the number of inputs. */ nin = astGetNin( map ); nout = astGetNout( map ); if( nout < nin ) return ret; /* Note the number of final World Coordinate axes (not necessarily the same as "nout", since some intermediate axes may be discarded by a later PermMap. */ nwcs = astGetNaxes( fr ); /* Allocate work space. */ g = astMalloc( sizeof(double)*(size_t) nin ); g0 = astMalloc( sizeof(double)*(size_t) nin ); w0 = astMalloc( sizeof(double)*(size_t) nout ); tol = astMalloc( sizeof(double)*(size_t) nout ); partmat = astMalloc( sizeof(double *)*(size_t) nout ); lin = astMalloc( sizeof(int)*(size_t) nout ); pperm = astMalloc( sizeof(int)*(size_t) nout ); skycol = astMalloc( sizeof(int)*(size_t) nout ); cdmat = astMalloc( sizeof(double)*(size_t) (nout*nout) ); cdelt = astMalloc( sizeof(double)*(size_t) nout ); /* For safety, initialise all other pointers. */ if( partmat ) for( j = 0; j < nout; j++ ) partmat[ j ] = NULL; fullmat = NULL; /* Create a PointSet to hold an input (grid) position for each axis, plus an extra one. Create two other PointSets to hold corresponding output (IWC) coordinates. */ psetg = astPointSet( nin + 1, nin, "", status ); ptrg = astGetPoints( psetg ); psetw = astPointSet( nin + 1, nout, "", status ); ptrw = astGetPoints( psetw ); /* Check the pointers can be used safely. */ if( astOK ) { /* Assume success. */ ret = 1; /* The next section finds a 'root' grid position for which the corresponding IWC coordinates are all good. It also finds these IWC coordinates, together with the IWC coordinates of "nin" points which are a unit distance away from the root grid position along each grid axis. It also finds an estimate of the rounding error in each Mapping output. ================================================================= */ ret = FindBasisVectors( map, nin, nout, dim, psetg, psetw, status ); /* Save the grid root position in "g0". */ for( j = 0; j < nin; j++ ) g0[ j ] = ptrg[ j ][ 0 ]; /* Save the transformed root position in "w0". This is the grid root position represented as a vector within the Intermediate World Coordinate system. */ for( j = 0; j < nout; j++ ) { w0[ j ] = ptrw[ j ][ 0 ]; /* Find the tolerance for positions on the j'th IWC axis. This is one hundredth of the largest change in the j'th IWC axis value caused by moving out 1 pixel along any grid axis. */ tol[ j ] = 0.0; for( i = 0; i < nin; i++ ) { err = fabs( ptrw[ j ][ i + 1 ] - w0[ j ] ); if( err > tol[ j ] ) tol[ j ] = err; } tol[ j ] *= 0.01; /* If the tolerance is zero (e.g. as is produced for degenerate axes), then use a tolerance equal to a very small fraction of hte degenerate axis value. If the axis value is zero use a fixed small value. */ if( tol[ j ] == 0.0 ) tol[ j ] = w0[ j ]*DBL_EPSILON*1.0E5; if( tol[ j ] == 0.0 ) tol[ j ] = sqrt( DBL_MIN ); } /* The next section finds the CD matrix. ===================================== */ /* Initialise the CD matrix elements to "all missing". */ for( i = 0; i < nout*nout; i++ ) cdmat[ i ] = AST__BAD; /* The elements of column "j" of the CD matrix form a vector (in Intermediate World Coords) which corresponds to a unit vector along grid axis "j". We now find these vectors for all the grid axes represented by the inputs to the supplied Mapping. */ for( i = 0; i < nin && ret; i++ ) { /* Form a unit vector along the current input axis. */ for( ii = 0; ii < nin; ii++ ) g[ ii ] = 0.0; g[ i ] = 1.0; /* Fit a straight line (within IWC) to the current input axis of the Mapping. The IWC vector corresponding to a unit vector along the current input axis is returned if the Mapping is linear. A NULL pointer is returned if the Mapping is not linear. */ partmat[ i ] = FitLine( map, g, g0, w0, dim[ i ], tol, status ); /* If unsuccesful, indicate failure and break out of the loop. */ if( !partmat[ i ] ) { ret = 0; break; } } /* If the number of outputs for "map" is larger than the number of inputs, then we will still be missing some column vectors for the CDi_j matrix (which has to be square). We invent these such that the they are orthogonal to all the other column vectors. Only do this if the Mapping is linear. */ if( ret ) { fullmat = OrthVectorSet( nout, nin, partmat, status ); if( !fullmat ) ret = 0; } /* Check everything is OK. */ if( ret ) { /* Check that the full matrix is invertable, and if not, see if there is any way to make it invertable. */ MakeInvertable( fullmat, nout, dim, status ); /* Set up an array holding index of the Mapping output corresponding to each IWC axis (the inverse of "wperm"). Also look for matching pairs of celestial WCS axes. For the first such pair, note the corresponding column indices and the diagonal element of the matrix which gives the scaling for the axis (taking account of the permutation of WCS axes). Also note if the Mapping from intermediate world coords to final world coords is linear for each axis (this is assumed to be the case if the axis is part of a simple Frame). */ sfrm = NULL; skydiag0 = AST__BAD; skydiag1 = AST__BAD; skycol0 = -1; skycol1 = -1; for( i = 0; i < nout; i++ ) { pperm[ wperm[ i ] ] = i; astPrimaryFrame( fr, i, &pfrm, &paxis ); if( astIsASkyFrame( pfrm ) ) { skycol[ wperm[ i ] ] = paxis + 1; lin[ i ] = 0; if( !sfrm ) { sfrm = astClone( pfrm ); skycol0 = wperm[ i ]; skydiag0 = fullmat[ skycol0 ][ i ]; } else if( sfrm == pfrm ) { skycol1 = wperm[ i ]; skydiag1 = fullmat[ skycol1 ][ i ]; } } else { skycol[ wperm[ i ] ] = 0; lin[ i ] = !strcmp( astGetClass( pfrm ), "Frame" ); } pfrm = astAnnul( pfrm ); } if( sfrm ) sfrm = astAnnul( sfrm ); /* We now have the complete CDi_j matrix. Now to find the CRPIX values. These are the grid coords of the reference point (which corresponds to the origin of Intermediate World Coords). The "w0" array currently holds the position of the root position, as a position within IWC, and the "g0" array holds the corresponding position in grid coordinates. We also have IWC vectors which correspond to unit vectors on each grid axis. The CRPIX values are defined by the matrix equation w0 = fullmat*( g0 - crpix ) The "g0" array only contains "nin" values. If nout>nin, then the missing g0 values will be assumed to be zero when we come to find the CRPIX values below. We use palDmat to solve this system of simultaneous equations to get crpix. The "y" array initially holds "w0" but is over-written to hold "g0 - crpix". */ mat = astMalloc( sizeof( double )*(size_t)( nout*nout ) ); y = astMalloc( sizeof( double )*(size_t) nout ); iw = astMalloc( sizeof( int )*(size_t) nout ); if( astOK ) { m = mat; for( i = 0; i < nout; i++ ) { for( j = 0; j < nout; j++ ) *(m++) = fullmat[ j ][ i ]; y[ i ] = w0[ i ]; } palDmat( nout, mat, y, &det, &sing, iw ); } mat = astFree( mat ); iw = astFree( iw ); /* Loop round all axes, storing the column vector pointer. */ for( j = 0; j < nout; j++ ) { colvec = fullmat[ j ]; /* Get the CRPIX values from the "y" vector created above by palDmat. First deal with axes for which there are Mapping inputs. */ if( j < nin ) { crp = g0[ j ] - y[ j ]; /* If this is a grid axis which has been created to represent a "missing" input to the mapping, we need to add on 1.0 to the crpix value found above. This is because the "w0" vector corresponds to a value of zero on any missing axes, but the FITS grid value for any missing axes is 1.0. */ } else { crp = 1.0 - y[ j ]; } /* Store the CD and CRPIX values for axes which correspond to inputs of "map". The CD matrix elements are stored in an array and are converted later to the corresponding PC and CDELT values. */ if( j < nin || crp == 0.0 ) { for( i = 0; i < nout; i++ ) { cdmat[ wperm[ i ]*nout+j ] = colvec[ i ] ; } SetItem( &(store->crpix), 0, j, s, crp, status ); /* The length of the unit vector along any "degenerate" axes was fixed arbitrarily at 1.0 by the call to OrthVectorSet. We can probably choose a more appropriate vector length. The choice shouldn't make any difference to the transformation, but an appropriate value will look more natural to human readers. */ } else { /* First, try to arrange for longitude/latitude axis pairs to have the same scale. Do we have a matching pair of celestial axes? */ k = AST__BAD; if( skydiag0 != AST__BAD && skydiag1 != AST__BAD ) { /* Is the current column the one which corresponds to the first celestial axis, and does the other sky column correspond to a Mapping input? */ if( skycol0 == j && skycol1 < nin ) { /* If so, scale this column so that its diagonal element is the negative of the diagonal element of the other axis. This is on the assumption that the scales on the two axes should be equal, and that longitude increases east whilst latitude increases north, and that the CD matrix does not introduce an axis permutation. */ if( skydiag0 != 0.0 ) k = -skydiag1/skydiag0; /* Now see if the current column the one which corresponds to the second celestial axis. Do the same as above. */ } else if( skycol1 == j && skycol0 < nin ) { if( skydiag1 != 0.0 ) k = -skydiag0/skydiag1; /* If neither of the above conditions was met, assume a diagonal element value of 1.0 degrees for latitude axes, and -1.0 degrees for longitude axes. */ } } /* If this failed, the next choice is to arrange for diagonally opposite elements to be equal and opposite in value. Look for the element of the column which has the largest diagonally opposite element, and choose a scaling factor which makes this column element equal to the negative value of its diagonally opposite element. Be careful to take axis permutations into account when finding the value of the diagonal element. */ if( k == AST__BAD ) { mxcv = 0.0; ii = pperm[ j ]; for( i = 0; i < nout; i++ ) { jj = wperm[ i ]; if( jj < nin ) { cv = fullmat[ jj ][ ii ]; if( !EQUAL( colvec[ i ], 0.0 ) && fabs( cv ) > mxcv ) { mxcv = fabs( cv ); k = -cv/colvec[ i ]; } } } } /* If still no scaling factor is available, use a scaling factor which produces a diagonal element of 1.0 degree if the corresponding row is a sky latitude axis, -1.0 degree of sky longitude axes, and 1.0 for other axes. */ if( k == AST__BAD && colvec[ pperm[ j ] ] != 0.0 ) { if( skycol[ j ] ) { k = AST__DD2R/colvec[ pperm[ j ] ]; if( skycol[ j ] == 1 ) k = -k; } else { k = 1.0/colvec[ pperm[ j ] ]; } } /* If we still do not have a scaling, use 1.0 (no scaling). */ if( k == AST__BAD ) k = 1.0; /* Now scale and store the column elements. */ for( i = 0; i < nout; i++ ) { cdmat[ wperm[ i ]*nout+j ] = k*colvec[ i ]; } /* Find the corresponding modified CRPIX value and store it. */ crp = 1.0 + ( crp - 1.0 )/k; SetItem( &(store->crpix), 0, j, s, crp, status ); } /* Free resources */ if( pfrm ) pfrm = astAnnul( pfrm ); } /* Any "degenerate" axes added in the above process for which the intermediate->world mapping is linear, and which depend only on one pixel axis, can be adjusted so that the reference point is at grid coord 1.0. */ for( i = 0; i < nout; i++ ) { if( lin[ i ] ) { /* Check only one pixel axis contributes to this intermediate world axis and find which one it is. */ jax = -1; for( j = 0; j < nout; j++ ) { if( !EQUAL( fullmat[ j ][ i ], 0.0 ) ) { if( jax == -1 ) { jax = j; } else { jax = -1; break; } } } /* We only adjust values for "degenerate" axes. */ if( jax >= nin ) { /* Check that this pixel axis only contributes to the single world axis currently being considered. */ for( ii = 0; ii < nout; ii++ ) { if( ii != i ) { if( !EQUAL( fullmat[ jax ][ ii ], 0.0 ) ) { jax = -1; break; } } } if( jax != -1 ) { /* Get the original CRVAL, CRPIX and CD values. Check they are defined.*/ crv = GetItem( &(store->crval), wperm[ i ], 0, s, NULL, method, class, status ); cd = cdmat[ wperm[ i ]*nout + jax ]; crp = GetItem( &(store->crpix), 0, jax, s, NULL, method, class, status ); if( crv != AST__BAD && crp != AST__BAD && cd != AST__BAD ) { /* Modify the CRPIX to be 1.0 and modify the CRVAL value accordingly. */ SetItem( &(store->crpix), 0, jax, s, 1.0, status ); SetItem( &(store->crval), wperm[ i ], 0, s, cd*( 1.0 - crp ) + crv, status ); } } } } } /* Finally, if there are fewer input axes than output axes, put a value for the WCSAXES keyword into the store. */ if( nin < nwcs ) SetItem( &(store->wcsaxes), 0, 0, s, nwcs, status ); /* Release resources. */ y = astFree( y ); } /* Produce and store PC and CDELT values from the above CD matrix */ SplitMat( nout, cdmat, cdelt, status ); c = cdmat; d = cdelt; for( i = 0; i < nout; i++ ){ for( j = 0; j < nout; j++ ){ val = *(c++); if( i == j ){ if( EQUAL( val, 1.0 ) ) val = AST__BAD; } else { if( EQUAL( val, 0.0 ) ) val = AST__BAD; } if( val != AST__BAD ) SetItem( &(store->pc), i, j, s, val, status ); } SetItem( &(store->cdelt), i, 0, s, *(d++), status ); } } /* Annul pointsets. */ psetg = astAnnul( psetg ); psetw = astAnnul( psetw ); /* Free other resources*/ map = astAnnul( map ); if( fullmat ) for( j = 0; j < nout; j++ ) fullmat[ j ] = astFree( fullmat[ j ] ); if( partmat ) for( j = 0; j < nout; j++ ) partmat[ j ] = astFree( partmat[ j ] ); fullmat = astFree( fullmat ); partmat = astFree( partmat ); cdmat = astFree( cdmat ); cdelt = astFree( cdelt ); g = astFree( g ); g0 = astFree( g0 ); w0 = astFree( w0 ); tol = astFree( tol ); lin = astFree( lin ); skycol = astFree( skycol ); pperm = astFree( pperm ); /* If an error has occurred, return zero. */ if( !astOK ) ret = 0; /* Return the answer. */ return ret; } static void MakeInvertable( double **fullmat, int n, double *dim, int *status ){ /* * Name: * MakeInvertable * Purpose: * Modify a supplied square CD matrix if possible to make it invertable. * Type: * Private function. * Synopsis: * void MakeInvertable( double **fullmat, int n, double *dim, int *status ) * Class Membership: * FitsChan * Description: * A search is made for matrix inputs that have no effect on any * matrix outputs. if any such matrix inputs are associated with * degenerate pixel axes (i.e. pixel axes that span only a single * pixel), then the matrix input should always have the value zero and * so the corresponding diagonal element of the matrix can be set to * 1.0 without changing and of the outputs. * Parameters: * fullmat * A pointer to an array with "n" elements corresponding to the n * inputs of the matrix, each element being a pointer to an array * with "n" elements corresponding to the n outputs of the matrix. * n * The number of inputs and outputs for the square matrix. * dim * Pointer to an array of "n" input (i.e. pixel) axis dimensions. * Individual elements will be AST__BAD if dimensions are not known. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int i; /* Input index */ int j; /* Output index */ int unused; /* Does the current input have no effect on any output? */ /* Check inherited status */ if( !astOK ) return; /* Look for any inputs that have no effect on any of the outputs. If such an input is associated with a degenerate grid axis (i.e. a grid axis with a dimension of 1.0), then the input value will always be zero and so the corresponding diagonal element of the matrix can eb set to 1.0 without affecting the output value (which will always be zero since zero times anything is zero). Loop over all inputs. */ for( i = 0; i < n; i++ ) { /* Assume this input has no effect on any output. */ unused = 1; /* Loop over all outputs. */ for( j = 0; j < n; j++ ) { /* If the corresponding matrix term is non-zero, the the input will have an effect on the output, so set the unused flag false and break out of the output loop. */ if( fullmat[ i ][ j ] != 0.0 ) { unused = 0; break; } } /* If the input is unused, and it is associated with a degenerate pixel axis, we can set the corresponding diagonal element of the matrix to 1.0. */ if( unused && dim[ i ] == 1.0 ) fullmat[ i ][ i ] = 1.0; } } #if defined(THREAD_SAFE) static int ManageLock( AstObject *this_object, int mode, int extra, AstObject **fail, int *status ) { /* * Name: * ManageLock * Purpose: * Manage the thread lock on an Object. * Type: * Private function. * Synopsis: * #include "object.h" * AstObject *ManageLock( AstObject *this, int mode, int extra, * AstObject **fail, int *status ) * Class Membership: * FitsChan member function (over-rides the astManageLock protected * method inherited from the parent class). * Description: * This function manages the thread lock on the supplied Object. The * lock can be locked, unlocked or checked by this function as * deteremined by parameter "mode". See astLock for details of the way * these locks are used. * Parameters: * this * Pointer to the Object. * mode * An integer flag indicating what the function should do: * * AST__LOCK: Lock the Object for exclusive use by the calling * thread. The "extra" value indicates what should be done if the * Object is already locked (wait or report an error - see astLock). * * AST__UNLOCK: Unlock the Object for use by other threads. * * AST__CHECKLOCK: Check that the object is locked for use by the * calling thread (report an error if not). * extra * Extra mode-specific information. * fail * If a non-zero function value is returned, a pointer to the * Object that caused the failure is returned at "*fail". This may * be "this" or it may be an Object contained within "this". Note, * the Object's reference count is not incremented, and so the * returned pointer should not be annulled. A NULL pointer is * returned if this function returns a value of zero. * status * Pointer to the inherited status variable. * Returned Value: * A local status value: * 0 - Success * 1 - Could not lock or unlock the object because it was already * locked by another thread. * 2 - Failed to lock a POSIX mutex * 3 - Failed to unlock a POSIX mutex * 4 - Bad "mode" value supplied. * Notes: * - This function attempts to execute even if an error has already * occurred. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to FitsChan structure */ int result; /* Returned status value */ /* Initialise */ result = 0; /* Check the supplied pointer is not NUL. */ if( ! this_object ) return result; /* Obtain a pointers to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Invoke the ManageLock method inherited from the parent class. */ if( !result ) result = (*parent_managelock)( this_object, mode, extra, fail, status ); /* Invoke the astManageLock method on any Objects contained within the supplied Object. */ if( !result ) result = astManageLock( this->keyseq, mode, extra, fail ); if( !result ) result = astManageLock( this->keywords, mode, extra, fail ); return result; } #endif static int Match( const char *test, const char *temp, int maxfld, int *fields, int *nfld, const char *method, const char *class, int *status ){ /* * Name: * Match * Purpose: * Sees if a test keyword name matches a template. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Match( const char *test, const char *temp, int maxfld, int *fields, * int *nfld, const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * All characters in the template other than "%" (and the field width * and type specifiers which follow a "%") must be matched by an * identical character (ignoring case) in the test string. If a "%" occurs * in the template, then the next character in the template should be a * single digit specifying a field width. If it is zero, then the test * string may contain zero or more matching characters. Otherwise, * the test string must contain exactly the specified number of matching * characters (i.e. 1 to 9). The field width digit may be omitted, in * which case the test string must contain one or more matching * characters. The next character in the template specifies the type of * matching characters and must be one of "d", "c" or "f". Decimal digits * are matched by "d", all upper (but not lower) case alphabetical * characters are matched by "c", and all characters which are legal within * a FITS keyword (i.e. upper case letters, digits, underscores and * hyphens) are matched by "f". * Parameters: * test * Pointer to a null terminated string holding the keyword name to * be tested. * temp * Pointer to a null terminated string holding the template. * maxfld * The maximum number of integer field values which should be * returned in "fields". * fields * A pointer to an array of at least "maxfld" integers. This is * returned holding the values of any integer fields specified * in the template. The values are extracted from the test string, * and stored in the order they appear in the template string. * nfld * Pointer to a location at which is returned the total number of * integer fields in the test string. This may be more than the * number returned in "fields" if "maxfld" is smaller than "*nfld". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the test string does not match the template * string, and one is returned if it does. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ char type; /* Field type specifier */ const char *a; /* Pointer to next test character */ const char *b; /* Pointer to next template character */ int extend; /* Can the width of the first field be extended? */ int i; /* Field index */ int match; /* Does "test" match "temp"? */ int nfret; /* No. of fields returned */ int tmp; /* Field value */ /* Check global status. */ if( !astOK ) return 0; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(NULL); /* On the first entry to this function, indicate that no integer fields have yet been returned, and save a pointer to the start of the template string. */ if( !match_nentry ) { *nfld = 0; match_template = temp; } /* Increment the number of entries into this function. */ match_nentry++; /* Initialise pointers to the start of each string. */ a = test; b = temp; /* Initialise the returned flag to indicate that the two strings do not match. */ match = 0; /* Check that the initial part of the test string can match the first field in the template. */ if( MatchFront( a, b, &type, &extend, &match_na, &match_nb, method, class, match_template, status ) ){ /* If it does, increment the pointers to skip over the characters used up in the comparison. */ a += match_na; b += match_nb; /* If the ends of both strings have been reached, they match. */ if( *a == 0 && *b == 0 ){ match = 1; /* Otherwise, if the end of the template has been reached but there are still characters to be read from the test string, we could still have a match if all the remaining test characters match an extandable field. */ } else if( *b == 0 && *a != 0 && extend ){ /* Loop until all the matching characters have been read from the end of the test string. */ while( *a != 0 && MatchChar( *a, type, method, class, match_template, status ) ) a++; /* If we reached the end of the test string, we have a match. */ if( *a == 0 ) match = 1; /* Otherwise, we need to carry on checking the remaining fields. */ } else { /* Call this function recursively to see if the remainder of the strings match. */ if( Match( a, b, maxfld, fields, nfld, method, class, status ) ){ match = 1; /* If the remainder of the strings do not match, we may be able to make them match by using up some extra test characters on the first field. This can only be done if the first field has an unspecified field width, and if the next test character if of a type which matches the first field in the template. */ } else if( extend ){ /* Loop until all the suitable characters have been read from the test string. Break out of the loop early if we find a field width which results in the whole string matching. */ while( MatchChar( *a, type, method, class, match_template, status ) ){ a++; if( Match( a, b, maxfld, fields, nfld, method, class, status ) ){ match = 1; break; } } } } } /* If the strings match and the leading field is an integer, decode the field and store it in the supplied array (if there is room). */ if( match && type == 'd' && a > test ){ if( *nfld < maxfld ){ sprintf( match_fmt, "%%%dd", (int) ( a - test ) ); astSscanf( test, match_fmt, fields + *nfld ); } (*nfld)++; } /* Decrement the number of entries into this function. */ match_nentry--; /* If we are leaving this function for the last time, reverse the order of the returned integer fields so that they are returned in the same order that they occur in the template. */ if( !match_nentry ){ nfret = ( *nfld < maxfld ) ? (*nfld) : maxfld; match_pa = fields; match_pb = fields + nfret - 1; for( i = 0; i < nfret/2; i++ ){ tmp = *match_pa; *(match_pa++) = *match_pb; *(match_pb--) = tmp; } } /* Return the result. */ return match; } static int MatchChar( char test, char type, const char *method, const char *class, const char *template, int *status ){ /* * Name: * MatchChar * Purpose: * See if a given character is of a specified type. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int MatchChar( char test, char type, const char *method, * const char *class, const char *template, int *status ) * Class Membership: * FitsChan member function. * Description: * This function checks that the supplied test character belongs * to the set of characters specified by the parameter "type". * Parameters: * test * The character to test. * type * The character specifying the set of acceptable characters. This * should be one of the field type characters accepted by function * Match (e.g. "d", "c" or "f"). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * template * Pointer to the start of the whole template string, for use in error * messages. * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if the test character does not belongs to the * specified character set, and one is returned if it does. * Notes: * - An error is reported if the type specifier is not legal. * - Zero is returned if an error has already occurred, or if ths * function fails for any reason. */ /* Local Variables: */ int ret; /* Returned flag */ /* Check global status. */ ret = 0; if( !astOK ) return ret; /* Check for "d" specifiers (digits). */ if( type == 'd' ){ ret = isdigit( (int) test ); /* Check for "c" specifiers (upper case letters). */ } else if( type == 'c' ){ ret = isupper( (int) test ); /* Check for "s" specifiers (any legal FITS keyword character). */ } else if( type == 'f' ){ ret = isFits( (int) test ); /* Report an error for any other specifier. */ } else if( astOK ){ ret = 0; astError( AST__BDFMT, "%s(%s): Illegal field type or width " "specifier '%c' found in filter template '%s'.", status, method, class, type, template ); } /* Return the answer. */ return ret; } static int MatchFront( const char *test, const char *temp, char *type, int *extend, int *ntest, int *ntemp, const char *method, const char *class, const char *template, int *status ){ /* * Name: * MatchFront * Purpose: * Sees if the start of a test string matches the start of a template. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int MatchFront( const char *test, const char *temp, char *type, * int *extend, int *ntest, int *ntemp, * const char *method, const char *class, * const char *template ) * Class Membership: * FitsChan member function. * Description: * This function looks for a match between the first field in the * template string and the string at the start of the test string, * using the syntax described in function Match. * Parameters: * test * Pointer to a null terminated string holding the keyword name to * be tested. * temp * Pointer to a null terminated string holding the template. * type * Pointer to a location at which to return a character specifying the * sort of field that was matched. This will be one of the legal field * types accepted by Match (e.g. "d", "c" or "f"), or null (zero) if * the first field in the template string was a literal character (i.e. * did not start with a "%"). * extend * Pointer to a location at which to return a flag which will be non-zero * if the further test characters could be matched by the first field in * the template. This will be the case if the template field only * specifies a minimum number of matching characters (i.e. if the field * width can be extended). For instance, "%d" can be extended, but "%1d" * cannot. * ntest * Pointer to a location at which to return the number of characters * matched in the test string. This will be the minimum number allowed * by the template field. * ntemp * Pointer to a location at which to return the number of characters * read from the template string (i.e. the number of characters in the * field specification). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * template * Pointer to the start of the whole template string, for use in error * messages. * Returned Value: * Zero is returned if the test string starts with fewer than the * minimum number of characters matching the template string, and one * is returned if it does. * Notes: * - Zero is returned if an error has already occurred, or if this * function fails for any reason. */ /* Local Variables: */ const char *a; /* Pointer to next test character */ const char *b; /* Pointer to next template character */ int i; /* Character index */ int match; /* Does "test" match "temp"? */ /* Check global status. */ if( !astOK ) return 0; /* Initialise pointers to the start of each string. */ a = test; b = temp; /* Initialise the returned value to indicate that the strings match. */ match = 1; /* If the current character in the template is not a % sign, it must match the current character in the test string (except for case). */ if( *b != '%' ){ if( toupper( (int) *b ) != toupper( (int) *a ) ) { match = 0; /* If the characters match, return all the required information. */ } else { *type = 0; *extend = 0; *ntest = 1; *ntemp = 1; } /* If the current character of the template is a %, we need to match a field. */ } else { *ntemp = 3; /* The next character in the template string determines the field width. Get the lowest number of characters which must match in the test string, and set a flag indicating if this lowest limit can be extended. */ b++; if( *b == '0' ){ *ntest = 0; *extend = 1; } else if( *b == '1' ){ *ntest = 1; *extend = 0; } else if( *b == '2' ){ *ntest = 2; *extend = 0; } else if( *b == '3' ){ *ntest = 3; *extend = 0; } else if( *b == '4' ){ *ntest = 4; *extend = 0; } else if( *b == '5' ){ *ntest = 5; *extend = 0; } else if( *b == '6' ){ *ntest = 6; *extend = 0; } else if( *b == '7' ){ *ntest = 7; *extend = 0; } else if( *b == '8' ){ *ntest = 8; *extend = 0; } else if( *b == '9' ){ *ntest = 9; *extend = 0; /* If no field width was given, one or more test characters are matched. Step back a character so that the current character will be re-used as the type specifier. */ } else { *ntest = 1; *extend = 1; b--; (*ntemp)--; } /* The next template character gives the type of character which should be matched. */ b++; *type = *b; /* Report an error if the template string ended within the field specifier. */ if( !*b ){ match = 0; astError( AST__BDFMT, "%s(%s): Incomplete field specifier found " "at end of filter template '%s'.", status, method, class, template ); /* Otherwise, check that the test string starts with the minimum allowed number of characters matching the specified type. */ } else { for( i = 0; i < *ntest; i++ ){ if( !MatchChar( *a, *type, method, class, template, status ) ){ match = 0; break; } a++; } } } /* Return the answer. */ return match; } static void MarkCard( AstFitsChan *this, int *status ){ /* * Name: * MarkCard * Purpose: * Mark the current card as having been read into an AST object. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void MarkCard( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * The current card is marked as having been "provisionally used" in * the construction of an AST object. If the Object is constructed * succesfully, such cards are marked as having been definitely used, * and they are then considered to have been removed from the FitsChan. * Parameters: * this * Pointer to the FitsChan containing the list of cards. * status * Pointer to the inherited status variable. * Notes: * - The card remains the current card even though it is now marked * as having been read. */ int flags; /* Return if the global error status has been set, or the current card is not defined. */ if( !astOK || !this->card ) return; /* Set the PROVISIONALLY_USED flag in the current card, but only if the PROTECTED flag is not set. */ flags = ( (FitsCard *) this->card )->flags; if( !( flags & PROTECTED ) ) { ( (FitsCard *) this->card )->flags = flags | PROVISIONALLY_USED; } } static int MoveCard( AstFitsChan *this, int move, const char *method, const char *class, int *status ){ /* * Name: * MoveCard * Purpose: * Move the current card a given number of cards forward or backwards. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int MoveCard( AstFitsChan *this, int move, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The current card is increment by the given number of cards, ignoring * cards which have been read into an AST object if the ignore_used flag * is set non-zero. * Parameters: * this * Pointer to the FitsChan containing the list of cards. * move * The number of cards by which to move the current card. Positive * values move towards the end-of-file. Negative values move * towards the start of the file (i.e. the list head). * method * Pointer to string holding name of calling method. * class * Pointer to string holding object class. * status * Pointer to the inherited status variable. * Returned Value: * The number of cards actually moved. This may not always be equal to * the requested number (for instance, if the end or start of the * FitsChan is encountered first). * Notes: * - If the end-of-file is reached before the required number of * cards have been skipped, the current card is set NULL, to indicate * an end-of-file condition. * - If the start of the file is reached before the required number of * cards have been skipped, the current card is left pointing to the * first usable card. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ FitsCard *card; /* The current card */ FitsCard *card0; /* The previous non-deleted card */ int moved; /* The number of cards moved by so far */ /* Return if the supplied object is NULL or the FitsChan is empty, or zero movement is requested. */ if( !this || !this->head || !move ) return 0; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Get a pointer to the current card. */ card = (FitsCard *) this->card; /* Initialise the number of cards moved so far. */ moved = 0; /* First deal with positive movements (towards the end-of-file). */ if( move > 0 ){ /* Loop round moving on to the next card until the correct number of moves have been made, or the end-of-file is reached. */ while( moved < move && card ){ /* Get a pointer to the next card in the list, reporting an error if the links are inconsistent. */ card = GetLink( card, NEXT, method, class, status ); /* If we have moved past the last card and are now pointing back at the list head, then indicate that we are at end-of-file by setting the card pointer NULL. */ if( (void *) card == this->head ){ card = NULL; /* Otherwise, increment the number of cards moved. We ignore cards which have been read into an AST object if the external "ignore_used" flag is set. */ } else if( card ){ if( !CARDUSED(card) ) moved++; } } /* Now deal with negative movements (towards the list head), so long as we are not currently at the list head. */ } else if( (void *) card != this->head ){ /* If we are currently at end-of-file, replace the NULL pointer for the current card with a pointer to the list head. The first step backwards will make the last card the current card. */ if( !card ) card = (FitsCard *) this->head; /* Loop round until the correct number of cards have been moved. */ while( moved < -move && card ){ /* If cards which have been read into an AST object are to be included in the count of moved cards, get a pointer to the previous card in the list, reporting an error if the links are inconsistent. */ if( !ignore_used ){ card = GetLink( card, PREVIOUS, method, class, status ); /* If cards which have been read into an AST object are to be ignored... */ } else { /* We need to find the previous card which has not been read into an AST object. We do not search beyond the start of the list. */ card0 = GetLink( card, PREVIOUS, method, class, status ); while( card0 && CARDUSED(card0) && (void *) card0 != this->head ){ card0 = GetLink( card0, PREVIOUS, method, class, status ); } /* If no such card was found we leave the card where it is. */ if( card0 && ( card0->flags & USED ) ) { break; /* Otherwise, move back to card found above. */ } else { card = card0; } } /* Increment the number of cards moved. */ moved++; /* If the current card is the list head, break out of the loop. */ if( (void *) card == this->head ) break; } } /* Store the new current card. */ this->card = (void *) card; /* Return the answer. */ return moved; } static double NearestPix( AstMapping *map, double val, int axis, int *status ){ /* * Name: * NearestPix * Purpose: * Find an axis value which corresponds to an integer pixel value. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double NearestPix( AstMapping *map, double val, int axis, int *status ) * Class Membership: * FitsChan member function. * Description: * The supplied axis value is transformed using the inverse of the * supplied Mapping (other axes are given the value AST__BAD). The * resulting axis values are rounded to the nearest whole number, and * then transformed back using the supplied Mapping in the forward * direction. If the nominated axis value is good, it is returned as * the function value, otherwise the supplied value is returned unchanged. * Parameters: * map * A Mapping (usually the input coordinates will correspond to * pixel coordinates). * val * A value for one of the outputs of the "map" Mapping. * axis * The index of the Mapping output to which "val" refers. * status * Pointer to the inherited status variable. * Retuned Value: * The modified output axis value. */ /* Local Variables: */ AstMapping *tmap; /* Mapping to be used */ AstPointSet *pset1; /* Pixel coords PointSet */ AstPointSet *pset2; /* WCS coords PointSet */ double **ptr1; /* Pointer to data in pset1 */ double **ptr2; /* Pointer to data in pset2 */ double result; /* Returned value */ int *ins; /* Array holding input axis indicies */ int i; /* Loop count */ int nin; /* Number of Mapping inputs */ int nout; /* Number of Mapping outputs */ /* Initialise. */ result = val; /* Check inherited status, and that the supplied value is good. */ if( !astOK || result == AST__BAD ) return result; /* If the supplied Mapping has no inverse, trying splitting off the transformation for the required axis, which may have an inverse. If succesful, use the 1-in,1-out Mapping returned by astMapSPlit instead of the supplied Mapping, and adjust the axis index accordingly. */ if( !astGetTranInverse( map ) ) { astInvert( map ); ins = astMapSplit( map, 1, &axis, &tmap ); if( tmap ) { astInvert( tmap ); axis = 0; } else { tmap = astClone( map ); } ins = astFree( ins ); astInvert( map ); } else { tmap = astClone( map ); } /* If the Mapping still has no inverse, return the supplied value unchanged. */ if( astGetTranInverse( tmap ) ) { /* Get the number of input and output coordinates. */ nin = astGetNin( tmap ); nout = astGetNout( tmap ); /* Create PointSets to hold a single input position and the corresponding output position. */ pset1 = astPointSet( 1, nin, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( 1, nout, "", status ); ptr2 = astGetPoints( pset2 ); if( astOK ) { /* Assign AST__BAD values to all output axes, except for the specified axis, which is given the supplied axis value. */ for( i = 0; i < nout; i++ ) ptr2[ i ][ 0 ] = AST__BAD; ptr2[ axis ][ 0 ] = val; /* Transform this output position into an input position. */ (void) astTransform( tmap, pset2, 0, pset1 ); /* Round all good axis values in the resulting input position to the nearest integer. */ for( i = 0; i < nin; i++ ) { if( ptr1[ i ][ 0 ] != AST__BAD ) { ptr1[ i ][ 0 ] = (int) ( ptr1[ i ][ 0 ] + 0.5 ); } } /* Transform this input position back into output coords. */ (void) astTransform( tmap, pset1, 1, pset2 ); /* If the resulting axis value is good, return it. */ if( ptr2[ axis ] [ 0 ] != AST__BAD ) result = ptr2[ axis ] [ 0 ]; } /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); } tmap = astAnnul( tmap ); /* Return the result. */ return result; } static void NewCard( AstFitsChan *this, const char *name, int type, const void *data, const char *comment, int flags, int *status ){ /* * Name: * NewCard * Purpose: * Insert a new card in front of the current card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void NewCard( AstFitsChan *this, const char *name, int type, * const void *data, const char *comment, int flags, * int *status ) * Class Membership: * FitsChan member function. * Description: * The supplied keyword name, data type and value, and comment are * stored in a new FitsCard structure, and this structure is * inserted into the circular linked list stored in the supplied * FitsChan. It is inserted in front of the current card. * Parameters: * this * Pointer to the FitsChan containing the list of cards. * name * Pointer to a string holding the keyword name of the new card. * type * An integer value representing the data type of the keyword. * data * Pointer to the data associated with the keyword. * comment * Pointer to a null-terminated string holding a comment. * flags * The flags to assign to the card. * status * Pointer to the inherited status variable. * Notes: * - The new card is inserted into the list in front of the current card, * so that the "next" link from the new card points to the current card. * If the FitsChan is currently at end-of-file (indicated by a NULL * pointer being stored for the current card), then the card is appended * to the end of the list. The pointer to the current card is left * unchanged. * - Keyword names are converted to upper case before being stored. * - Any trailing white space in a string value is saved as supplied. * - Logical values are converted to zero or one before being stored. * - The "comment" and/or "data" pointers may be supplied as NULL. */ /* Local Variables: */ FitsCard *new; /* Pointer to the new card */ FitsCard *prev; /* Pointer to the previous card in the list */ char *b; /* Pointer to next stored character */ const char *a; /* Pointer to next supplied character */ int lval; /* Logical data value restricted to 0 or 1 */ int nc; /* No. of characters to store */ /* Check the global status. */ if( !astOK ) return; /* Get memory to hold the new FitsCard structure. */ new = (FitsCard *) astMalloc( sizeof( FitsCard ) ); /* Check the pointer can be used. */ if( astOK ){ /* Copy the keyword name, converting to upper case. */ a = name; b = new->name; while( *a ) *(b++) = (char) toupper( (int) *(a++) ); *b = 0; /* Ensure that a KeyMap exists to hold the keywords currently in the FitsChan. */ if( !this->keywords ) this->keywords = astKeyMap( "", status ); /* Add the keyword name to the KeyMap. The value associated with the KeyMap entry is not used and is set arbitrarily to zero. */ astMapPut0I( this->keywords, new->name, 0, NULL ); /* Copy the data type. */ new->type = type; /* Copy any data (ignore any data supplied for an UNDEF value). */ if( data && type != AST__UNDEF ){ /* Logical values are converted to zero or one before being stored. */ if( type == AST__LOGICAL ){ lval = *( (int *) data ) ? 1 : 0; new->size = sizeof( int ); new->data = astStore( NULL, (void *) &lval, sizeof( int ) ); /* String values... */ } else if( type == AST__STRING || type == AST__CONTINUE ){ /* Find the number of characters excluding the trailing null character. */ nc = strlen( data ); /* Store the string, reserving room for a terminating null. */ new->size = (size_t)( nc + 1 ); new->data = astStore( NULL, (void *) data, (size_t)( nc + 1 ) ); /* Terminate it. */ ( (char *) new->data)[ nc ] = 0; /* Other types are stored as supplied. */ } else if( type == AST__INT ){ new->size = sizeof( int ); new->data = astStore( NULL, (void *) data, sizeof( int ) ); } else if( type == AST__FLOAT ){ new->size = sizeof( double ); new->data = astStore( NULL, (void *) data, sizeof( double ) ); } else if( type == AST__COMPLEXF ){ if( *( (double *) data ) != AST__BAD ) { new->size = 2*sizeof( double ); new->data = astStore( NULL, (void *) data, 2*sizeof( double ) ); } else { nc = strlen( BAD_STRING ); new->size = (size_t)( nc + 1 ); new->data = astStore( NULL, BAD_STRING, (size_t)( nc + 1 ) ); ( (char *) new->data)[ nc ] = 0; } } else if( type == AST__COMPLEXI ){ new->size = 2*sizeof( int ); new->data = astStore( NULL, (void *) data, 2*sizeof( int ) ); } else { new->size = 0; new->data = NULL; } } else { new->size = 0; new->data = NULL; } /* Find the first non-blank character in the comment, and find the used length of the remaining string. We retain leading and trailing white space if the card is a COMMENT card. */ if( comment ){ a = comment; if( type != AST__COMMENT ) { while( isspace( *a ) ) a++; nc = ChrLen( a, status ); } else { nc = strlen( a ); } } else { nc = 0; } /* Copy any comment, excluding leading and trailing white space unless this is a COMMENT card */ if( nc > 0 ){ new->comment = astStore( NULL, (void *) a, (size_t)( nc + 1 ) ); ( (char *) new->comment)[ nc ] = 0; } else { new->comment = NULL; } /* Set the supplied flag values. */ new->flags = flags; /* Insert the copied card into the list, in front of the current card. If the current card is the list head, make the new card the list head. */ if( this->card ){ prev = ( ( FitsCard *) this->card )->prev; ( ( FitsCard *) this->card )->prev = new; new->prev = prev; prev->next = new; new->next = (FitsCard *) this->card; if( this->card == this->head ) this->head = (void *) new; /* If the FitsChan is at end-of-file, append the new card to the end of the list (i.e. insert it just before the list head). */ } else { if( this->head ){ prev = ( (FitsCard *) this->head )->prev; ( (FitsCard *) this->head )->prev = new; new->prev = prev; prev->next = new; new->next = (FitsCard *) this->head; /* If there are no cards in the list, start a new list. */ } else { new->prev = new; new->next = new; this->head = (void *) new; this->card = NULL; } } } /* Return. */ return; } static AstMapping *NonLinSpecWcs( AstFitsChan *this, char *algcode, FitsStore *store, int i, char s, AstSpecFrame *specfrm, const char *method, const char *class, int *status ) { /* * Name: * NonLinSpecWcs * Purpose: * Create a Mapping describing a FITS-WCS non-linear spectral algorithm * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *NonLinSpecWcs( AstFitsChan *this, char *algcode, * FitsStore *store, int i, char s, * AstSpecFrame *specfrm, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function uses the contents of the supplied FitsStore to create * a Mapping which goes from Intermediate World Coordinate (known as "w" * in the context of FITS-WCS paper III) to the spectral system * described by the supplied SpecFrame. * * The returned Mapping implements the non-linear "X2P" algorithms * described in FITS-WCS paper III. The axis is linearly sampled in * system "X" but expressed in some other system (specified by the * supplied SpecFrame). * Parameters: * this * Pointer to the FitsChan. * algcode * Pointer to a string holding the non-linear "-X2P" code for the * required algorithm. This includes aleading "-" character. * store * Pointer to the FitsStore structure holding the values to use for * the WCS keywords. * i * The zero-based index of the spectral axis within the FITS header * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * specfrm * Pointer to the SpecFrame. This specified the "S" system - the * system in which the CRVAL kewyords (etc) are specified. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a Mapping, or NULL if an error occurs. */ /* Local Variables: */ AstFrameSet *fs; AstMapping *map1; AstMapping *ret; AstSpecFrame *xfrm; AstMapping *map2; char buf[ 100 ]; char pc; double crv; double ds; double in_a; double in_b; double out_a; double out_b; int ok; int s_sys; /* Check the global status. */ ret = NULL; if( !astOK ) return ret; /* Identify the spectral "X" system within the "X2P" algorithm code, and create a SpecFrame describing the X system ("X" is the system in which the axis is linearly sampled). This is done by copying the supplied SpecFrame and then setting its System attribute. Copying the supplied SpecFrame ensures that all the other attributes (RestFreq, etc.) are set correctly. */ ok = 1; xfrm = astCopy( specfrm ); if( algcode[ 1 ] == 'F' ) { astSetSystem( xfrm, AST__FREQ ); astSetUnit( xfrm, 0, "Hz" ); } else if( algcode[ 1 ] == 'W' ) { astSetSystem( xfrm, AST__WAVELEN ); astSetUnit( xfrm, 0, "m" ); } else if( algcode[ 1 ] == 'V' ) { astSetSystem( xfrm, AST__VREL ); astSetUnit( xfrm, 0, "m/s" ); } else if( algcode[ 1 ] == 'A' ) { astSetSystem( xfrm, AST__AIRWAVE ); astSetUnit( xfrm, 0, "m" ); } else { ok = 0; } /* If the X system was identified, find a Mapping from the "S" (specfrm) system to the X system. */ map1 = NULL; if( ok ) { ok = 0; fs = astConvert( specfrm, xfrm, "" ); if( fs ) { map1 = astGetMapping( fs, AST__BASE, AST__CURRENT ); fs = astAnnul( fs ); ok = 1; } /* Issue a warning if the "P" system is not the correct one for the given "S" system. We can however continue, sine AST interprets illegal "P" systems correctly. */ pc = 0; s_sys = astGetSystem( specfrm ); if( s_sys == AST__FREQ || s_sys == AST__ENERGY || s_sys == AST__WAVENUM || s_sys == AST__VRADIO ) { pc = 'F'; } else if( s_sys == AST__WAVELEN || s_sys == AST__VOPTICAL || s_sys == AST__REDSHIFT ){ pc = 'W'; } else if( s_sys == AST__AIRWAVE ) { pc = 'A'; } else if( s_sys == AST__BETA || s_sys == AST__VREL ) { pc = 'V'; } else if( astOK ) { pc = algcode[ 3 ]; astError( AST__INTER, "%s: Function NonLinSpecWcs does not yet " "support spectral axes of type %s (internal AST " "programming error).", status, method, astGetC( specfrm, "System" ) ); } if( algcode[ 3 ] != pc ) { sprintf( buf, "The spectral CTYPE value %s%s is not legal - " "using %s%.3s%c instead.", astGetC( specfrm, "System" ), algcode, astGetC( specfrm, "System" ), algcode, pc ); Warn( this, "badctype", buf, method, class, status ); } } /* If succesfull, use this Mapping to find the reference value (CRVAL) in the "X" system. */ if( ok ) { /* Get the CRVAL value for the spectral axis (this will be in the S system). */ crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( crv == AST__BAD ) crv = 0.0; /* Convert it to the X system. */ astTran1( map1, 1, &crv, 1, &crv ); /* Invert this Mapping so that it forward transformation goes from X to S. */ astInvert( map1 ); /* Find the rate of change of S with respect to X (dS/dX) at the reference point (x = crv). */ ds = astRate( map1, &crv, 0, 0 ); if( ds != AST__BAD && ds != 0.0 ) { /* FITS-WCS paper III says that dS/dw must be 1.0 at the reference point. Therefore dX/dw = dX/dS at the reference point. Also, since the spectral axis is linear in X, dX/dw must be constant. Therefore the Mapping from IWC to X is a WinMap which scales the IWC axis ("w") by dX/dw and adds on the X value at the reference point. */ if( crv != 0.0 ) { in_a = 0.0; out_a = crv; in_b = crv*ds; out_b = 2.0*crv; map2 = (AstMapping *) astWinMap( 1, &in_a, &in_b, &out_a, &out_b, "", status ); } else { map2 = (AstMapping *) astZoomMap( 1, 1.0/ds, "", status ); } /* The Mapping to be returned is the concatenation of the above Mapping (from w to X) with the Mapping from X to S. */ ret = (AstMapping *) astCmpMap( map2, map1, 1, "", status ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); } } xfrm = astAnnul( xfrm ); /* Return the result */ return ret; } static double *OrthVector( int n, int m, double **in, int *status ){ /* * Name: * OrthVector * Purpose: * Find a unit vector which is orthogonal to a set of supplied vectors. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double *OrthVector( int n, int m, double **in, int *status ) * Class Membership: * FitsChan member function. * Description: * A set of M vectors is supplied, each vector being N-dimensional. * It is assumed that M < N and that the supplied vectors span M * axes within the N dimensional space. An N-dimensional unit vector is * returned which is orthogonal to all the supplied vectors. * * The required vector is orthogonal to all the supplied vectors. * Therefore the dot product of the required vector with each of the * supplied vectors must be zero. This gives us M equations of the * form: * * a1*r1 + a2*r2 + a3*r3 + .... + aN*rN = 0.0 * b1*r1 + b2*r2 + b3*r3 + .... + bN*rN = 0.0 * ... * * where (a1,a2,..,aN), (b1,b2,..,bN), ... are the supplied vectors * and (r1,r2,...,rN) is the required vector. Since M is less * than N the system of linear simultaneous equations is under * specified and we need to assign arbitrary values to some of the * components of the required vector in order to allow the equations * to be solved. We arbitrarily assume that 1 element of the required * vector has value 1.0 and (N-M-1) have value zero. The selection of * *which* elements to set constant is based on the magnitudes of the * columns of coefficients (a1,b1...), (a2,b2,...), etc. The M components * of the required vector which are *not* set constant are the ones which * have coefficient columns with the *largest* magnitude. This choice is * made in order to minimise the risk of the remaining matrix of * coefficients being singular (for instance, if a component of the * required vector has a coefficient of zero in every supplied vector * then the column magnitude will be zero and that component will be * set to 1.0). After choosing the M largest columns, the largest * remaining column is assigned a value of 1.0 in the required vector, * and all other columns are assigned the value zero in the required * vector. This means that the above equations becomes: * * a1*r1 + a2*r2 + a3*r3 + .... + aM*rM = -aM+1 * b1*r1 + b2*r2 + b3*r3 + .... + bM*rM = -bM+1 * ... * * Where the indices are now not direct indices into the supplied and * returned vectors, but indices into an array of indices which have * been sorted into column magnitude order. This is now a set of MxM * simultaneous linear equations which we can solve using palDmat: * * MAT.R = V * * where MAT is the the matrix of columns (coefficients) on the left * hand side of the above set of simultaneous equations, R is the * required vector (just the components which have *not* been set * constant), and V is a constant vector equal to the column of values * on the right hand side in the above set of simultaneous equations. * The palDmat function solves this equation to obtain R. * Parameters: * n * The number of dimensions * m * The number of supplied vectors. * in * A pointer to an array with "m" elements, each element being a * pointer to an array with "n" elements. Each of these "n" element * array holds one of the supplied vectors. * status * Pointer to the inherited status variable. * Returned Value: * The pointer to some newly allocated memory holding the returned N * dimensional unit vector. The memory should be freed using astFree when * no longer needed. * Notes: * - NULL is returned if an error occurs. * - NULL is returned (without error) if the required vector cannot * be found (.e.g becuase the supplied M vectors span less than M axes). */ /* Local Variables: */ double *colmag; double *d; double *e; double *mat; double *mel; double *ret; double *rhs; double det; double sl; int *colperm; int *iw; int done; int i; int ih; int ii; int il; int j; int sing; /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Return if any of the M supplied vectors are NULL. */ for( i = 0; i < m; i++ ) { if( !in[ i ] ) return ret; } /* Allocate rquired memory. */ ret = astMalloc( sizeof( double )*(size_t) n ); rhs = astMalloc( sizeof( double )*(size_t) m ); mat = astMalloc( sizeof( double )*(size_t) m*m ); iw = astMalloc( sizeof( int )*(size_t) m ); colmag = astMalloc( sizeof( double )*(size_t) n ); colperm = astMalloc( sizeof( int )*(size_t) n ); /* Check memory can be used safely. */ if( astOK ) { /* Find the magnitude of each column of coefficients in the full set of simultaneous linear equations (before setting any components of the required vector constant). Also initialise the column permutation array to indicate that the columns are in their original order. The outer loop loops through the columns and the inner loop loops through rows (i.e. equations). */ for( i = 0; i < n; i++ ) { colperm[ i ] = i; colmag[ i ] = 0.0; for( j = 0; j < m; j++ ) { colmag[ i ] += in[ j ][ i ]*in[ j ][ i ]; } } /* Now re-arrange the column indices within the permutation array so that they are in order of decreasing ciolumn magnitude (i.e. colperm[0] will be left holding the index of the column with the largest magnitude). A simple bubble sort is used. */ ii = 1; done = 0; while( !done ) { done = 1; for( i = ii; i < n; i++ ) { ih = colperm[ i ]; il = colperm[ i - 1 ]; if( colmag[ ih ] > colmag[ il ] ) { colperm[ i ] = il; colperm[ i - 1 ] = ih; done = 0; } } ii++; } /* The first M elements in "colperm" now hold the indices of the columns which are to be used within the MAT matrix, the next element of "colperm" hold the index of the column which is to be included in the V vector (other elements hold the indices of the columns which are being ignored because they will be mutiplied by a value of zero - the assumed value of the corresponding components of the returned vector). We now copy the these values into arrays which can be passed to palDmat. First, initialise a pointer used to step through the mat array. */ mel = mat; /* Loop through all the supplied vectors. Get a pointer to the first element of the vector. */ for( i = 0; i < m; i++ ) { d = in[ i ]; /* Copy the required M elements of this supplied vector into the work array which will be passed to palDmat. */ for( j = 0; j < m; j++ ) *(mel++) = d[ colperm[ j ] ]; /* Put the next right-hand side value into the "rhs" array. */ rhs[ i ] = -d[ colperm[ m ] ]; } /* Use palDmat to find the first M elements of the returned array. These are stored in "rhs", over-writing the original right-hand side values. */ palDmat( m, mat, rhs, &det, &sing, iw ); /* If the supplied vectors span fewer than M axes, the above call will fail. In this case, annul the returned vector. */ if( sing != 0 ) { ret = astFree( ret ); /* If succesful, copy the M elements of the solution vector into the required M elements of the returned vector. Also find the squared length of the vector. */ } else { sl = 0.0; e = rhs; for( j = 0; j < m; j++ ) { sl += (*e)*(*e); ret[ colperm[ j ] ] = *(e++); } /* Put 1.0 into the next element of the returned vector. */ sl += 1.0; ret[ colperm[ m ] ] = 1.0; /* Fill up the rest of the returned vector with zeros. */ for( j = m + 1; j < n; j++ ) ret[ colperm[ j ] ] = 0.0; /* Normalise the returned vector so that it is a unit vector.Also ensure that any zeros are "+0.0" insteasd of "-0.0". */ e = ret; sl = sqrt( sl ); for( j = 0; j < n; e++,j++ ) { *e /= sl; if( *e == 0.0 ) *e = 0.0; } } } /* Free workspace. */ rhs = astFree( rhs ); mat = astFree( mat ); iw = astFree( iw ); colmag = astFree( colmag ); colperm = astFree( colperm ); /* Free the returned vector if an error has occurred. */ if( !astOK ) ret = astFree( ret ); /* Return the answer. */ return ret; } static double **OrthVectorSet( int n, int m, double **in, int *status ){ /* * Name: * OrthVectorSet * Purpose: * Find a set of mutually orthogonal vectors. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double **OrthVectorSet( int n, int m, double **in, int *status ) * Class Membership: * FitsChan member function. * Description: * A set of M vectors is supplied, each vector being N-dimensional. * It is assumed that the supplied vectors span M axes within the * N dimensional space. A pointer to a set of N vectors is returned. * The first M returned vectors are copies of the M supplied vectors. * The remaining returned vectors are unit vectors chosen to be * orthogonal to all other vectors in the returned set. * Parameters: * n * The number of dimensions * m * The number of supplied vectors. * in * A pointer to an array with "m" elements, each element being a * pointer to an array with "n" elements. Each of these "n" element * array holds one of the supplied vectors. * status * Pointer to the inherited status variable. * Returned Value: * The pointer to some newly allocated memory holding the returned N * vectors. The pointer locates an array of N elements, each of which * is a pointer to an array holding the N elements of a single vector. * The memory (including the inner pointers) should be freed using * astFree when no longer needed. * Notes: * - NULL is returned if an error occurs. * - NULL is returned (without error) if the required vectors cannot * be found (e.g. becuase the supplied M vectors span less than M axes). */ /* Local Variables: */ double **ret; int i; int bad; /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Allocate required memory. */ ret = astMalloc( sizeof( double * )*(size_t) n ); /* Check memory can be used safely. */ bad = 0; if( astOK ) { /* Copy the supplied vectors into the returned array. */ for( i = 0; i < m; i++ ) { ret[ i ] = astStore( NULL, in[ i ], sizeof( double )*n ); } /* For the remaining vectors, find a vector which is orthogonal to all the vectors currently in the returned set. */ for( ; i < n; i++ ) { ret[ i ] = OrthVector( n, i, ret, status ); if( !ret[ i ] ) bad = 1; } } /* Free the returned vectors if an error has occurred. */ if( bad || !astOK ) { for( i = 0; ret && i < n; i++ ) ret[ i ] = astFree( ret[ i ] ); ret = astFree( ret ); } /* Return the answer. */ return ret; } static AstMapping *OtherAxes( AstFitsChan *this, AstFrameSet *fs, double *dim, int *wperm, char s, FitsStore *store, double *crvals, int *axis_done, const char *method, const char *class, int *status ){ /* * Name: * OtherAxes * Purpose: * Add values to a FitsStore describing unknown axes in a Frame. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *OtherAxes( AstFitsChan *this, AstFrameSet *fs, double *dim, * int *wperm, char s, FitsStore *store, * double *crvals, int *axis_done, * const char *method, const char *class, * int *status ) * Class Membership: * FitsChan member function. * Description: * FITS WCS keyword values are added to the supplied FitsStore which * describe any as yet undescribed axes in the supplied FrameSet. These * axes are assumed to be linear and to follow the conventions * of FITS-WCS paper I (if in fact they are not linear, then the * grid->iwc mapping determined by MakeIntWorld will not be linear and * so the axes will be rejected). * * Note, this function does not store values for keywords which define * the transformation from pixel coords to Intermediate World Coords * (CRPIX, PC and CDELT), but a Mapping is returned which embodies these * values. This Mapping is from the current Frame in the FrameSet (WCS * coords) to a Frame representing IWC. The IWC Frame has the same number * of axes as the WCS Frame which may be greater than the number of base * Frame (i.e. pixel) axes. * Parameters: * this * Pointer to the FitsChan. * fs * Pointer to the FrameSet. The base Frame should represent FITS pixel * coordinates, and the current Frame should represent FITS WCS * coordinates. The number of base Frame axes should not exceed the * number of current Frame axes. * dim * An array holding the image dimensions in pixels. AST__BAD can be * supplied for any unknwon dimensions. * wperm * Pointer to an array of integers with one element for each axis of * the current Frame. Each element holds the zero-based * index of the FITS-WCS axis (i.e. the value of "i" in the keyword * names "CTYPEi", "CRVALi", etc) which describes the Frame axis. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * store * The FitsStore in which to store the FITS WCS keyword values. * crvals * Pointer to an array holding the default CRVAL value for each * axis in the WCS Frame. * axis_done * An array of flags, one for each Frame axis, which indicate if a * description of the corresponding axis has yet been stored in the * FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * If any axis descriptions were added to the FitsStore, a Mapping from * the current Frame of the supplied FrameSet, to the IWC Frame is returned. * Otherwise, a UnitMap is returned. Note, the Mapping only defines the IWC * transformation for the described axes. Any other (previously * described) axes are passed unchanged by the returned Mapping. */ /* Local Variables: */ AstFitsTable *table; /* Pointer to structure holding -TAB table info */ AstFrame *wcsfrm; /* WCS Frame within FrameSet */ AstMapping *axmap; /* Mapping from WCS to IWC */ AstMapping *map; /* FITS pixel->WCS Mapping */ AstMapping *ret; /* Returned Mapping */ AstMapping *tmap0; /* Pointer to a temporary Mapping */ AstMapping *tmap1; /* Pointer to a temporary Mapping */ AstPermMap *pm; /* PermMap pointer */ AstPointSet *pset1; /* PointSet holding central pixel position */ AstPointSet *pset2; /* PointSet holding reference WCS position */ char buf[80]; /* Text buffer */ const char *lab; /* Pointer to axis Label */ const char *sym; /* Pointer to axis Symbol */ double **ptr1; /* Pointer to data for pset1 */ double **ptr2; /* Pointer to data for pset2 */ double *lbnd_p; /* Pointer to array of lower pixel bounds */ double *ubnd_p; /* Pointer to array of upper pixel bounds */ double crval; /* The value for the FITS CRVAL keyword */ int *inperm; /* Pointer to permutation array for input axes */ int *outperm; /* Pointer to permutation array for output axes */ int extver; /* Table version number for -TAB headers */ int fits_i; /* FITS WCS axis index */ int i; /* Loop count */ int iax; /* WCS Frame axis index */ int icolindex; /* Index of table column holding index vector */ int icolmain; /* Index of table column holding main coord array */ int interp; /* Interpolation method for look-up tables */ int log_axis; /* Is the axis logarithmically spaced? */ int nother; /* Number of axes still to be described */ int npix; /* Number of pixel axes */ int nwcs; /* Number of WCS axes */ int tab_axis; /* Can the axis be described by the -TAB algorithm? */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Get the number of WCS axes. */ nwcs = astGetNaxes( fs ); /* Count the number of WCS axes which have not yet been described. */ nother = 0; for( iax = 0; iax < nwcs; iax++ ) { if( ! axis_done[ iax ] ) nother++; } /* Only proceed if there are some axes to described. */ if( nother ) { /* Get a pointer to the WCS Frame. */ wcsfrm = astGetFrame( fs, AST__CURRENT ); /* Get a pointer to the pixel->wcs Mapping. */ map = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* Store the number of pixel and WCS axes. */ npix = astGetNin( fs ); nwcs = astGetNout( fs ); /* Store the upper and lower pixel bounds. */ lbnd_p = astMalloc( sizeof( double )*(size_t) npix ); ubnd_p = astMalloc( sizeof( double )*(size_t) npix ); if( astOK ) { for( iax = 0; iax < npix; iax++ ) { lbnd_p[ iax ] = 1.0; ubnd_p[ iax ] = ( dim[ iax ] != AST__BAD ) ? dim[ iax ] : 500; } } /* Transform the central pixel coords into WCS coords */ pset1 = astPointSet( 1, npix, "", status ); ptr1 = astGetPoints( pset1 ); pset2 = astPointSet( 1, nwcs, "", status ); ptr2 = astGetPoints( pset2 ); if( astOK ) { for( iax = 0; iax < npix; iax++ ) { ptr1[ iax ][ 0 ] = ( dim[ iax ] != AST__BAD ) ? floor( 0.5*dim[ iax ] ) : 1.0; } (void) astTransform( map, pset1, 1, pset2 ); } /* Loop round all WCS axes, producing descriptions of any axes which have not yet been described. */ for( iax = 0; iax < nwcs && astOK; iax++ ) { if( ! axis_done[ iax ] ) { /* Get the (one-based) FITS WCS axis index to use for this Frame axis. */ fits_i = wperm[ iax ]; /* Use the supplied default CRVAL value. If bad, use the WCS value corresponding to the central pixel found above (if this value is bad, abort). */ crval = crvals ? crvals[ iax ] : AST__BAD; if( crval == AST__BAD ) crval = ptr2[ iax ][ 0 ]; if( crval == AST__BAD ) { break; } else { SetItem( &(store->crval), fits_i, 0, s, crval, status ); } /* Initialise flags indicating the type of the axis. */ log_axis = 0; tab_axis = 0; /* Get the table version number to use if we end up using the -TAB algorithm. This is the set value of the TabOK attribute (if positive). */ extver = astGetTabOK( this ); /* See if the axis is linear. If so, create a ShiftMap which subtracts off the CRVAL value. */ if( IsMapLinear( map, lbnd_p, ubnd_p, iax, status ) ) { crval = -crval; tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status ); axmap = AddUnitMaps( tmap0, iax, nwcs, status ); tmap0 = astAnnul( tmap0 ); crval = -crval; /* If it is not linear, see if it is logarithmic. If the "log" algorithm is appropriate (as defined in FITS-WCS paper III), the supplied Frame (s) is related to pixel coordinate (p) by s = Sr.EXP( a*p - b ). If this is the case, the log of s will be linearly related to pixel coordinates. Test this. If the test is passed a Mapping is returned from WCS to IWC. */ } else if( (axmap = LogAxis( map, iax, nwcs, lbnd_p, ubnd_p, crval, status ) ) ) { log_axis = 1; /* If it is not linear or logarithmic, and the TabOK attribute is non-zero, describe it using the -TAB algorithm. */ } else if( extver > 0 ){ /* Get any pre-existing FitsTable from the FitsStore. This is the table in which the tabular data will be stored (if the Mapping can be expressed in -TAB form). */ if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL; /* See if the Mapping can be expressed in -TAB form. */ tmap0 = IsMapTab1D( map, 1.0, NULL, wcsfrm, dim, iax, fits_i, &table, &icolmain, &icolindex, &interp, status ); if( tmap0 ) { tab_axis = 1; /* The values stored in the table index vector are GRID coords. So we need to ensure that IWC are equivalent to GRID coords. So set CRVAL to zero. */ crval = 0.0; /* Store TAB-specific values in the FitsStore. First the name of the FITS binary table extension holding the coordinate info. */ SetItemC( &(store->ps), fits_i, 0, s, AST_TABEXTNAME, status ); /* Next the table version number. This is the set (positive) value for the TabOK attribute. */ SetItem( &(store->pv), fits_i, 1, s, extver, status ); /* Also store the table version in the binary table header. */ astSetFitsI( table->header, "EXTVER", extver, "Table version number", 0 ); /* Next the name of the table column containing the main coords array. */ SetItemC( &(store->ps), fits_i, 1, s, astColumnName( table, icolmain ), status ); /* Next the name of the column containing the index array */ if( icolindex >= 0 ) SetItemC( &(store->ps), fits_i, 2, s, astColumnName( table, icolindex ), status ); /* The interpolation method (an AST extension to the published -TAB algorithm, communicated through the QVi_4a keyword). */ SetItem( &(store->pv), fits_i, 4, s, interp, status ); /* Also store the FitsTable itself in the FitsStore. */ astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL ); /* Create the WCS -> IWC Mapping (AST uses grid coords as IWC coords for the -TAB algorithm). First, get a Mapping that combines the TAB axis Mapping( tmap0) in parallel with one or two UnitMaps in order to put the TAB axis at the required index. */ tmap1 = AddUnitMaps( tmap0, iax, nwcs, status ); /* Now get a PermMap that permutes the WCS axes into the FITS axis order. */ inperm = astMalloc( sizeof( double )*nwcs ); outperm = astMalloc( sizeof( double )*nwcs ); if( astOK ) { for( i = 0; i < nwcs; i++ ) { inperm[ i ] = wperm[ i ]; outperm[ wperm[ i ] ] = i; } } pm = astPermMap( nwcs, inperm, nwcs, outperm, NULL, "", status ); /* Combine these two Mappings in series, to get the Mapping from WCS to IWC. */ axmap = (AstMapping *) astCmpMap( pm, tmap1, 1, " ", status ); /* Free resources. */ inperm = astFree( inperm ); outperm = astFree( outperm ); pm = astAnnul( pm ); tmap0 = astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); } if( table ) table = astAnnul( table ); } /* If the axis cannot be described by any of the above methods, we pretend it is linear. This will generate a non-linear PIXEL->IWC mapping later (in MakeIntWorld) which will cause the write operation to fail. */ if( !axmap ) { crval = -crval; tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status ); axmap = AddUnitMaps( tmap0, iax, nwcs, status ); tmap0 = astAnnul( tmap0 ); crval = -crval; } /* Combine the Mapping for this axis in series with those of earlier axes. */ if( ret ) { tmap0 = (AstMapping *) astCmpMap( ret, axmap, 1, "", status ); (void) astAnnul( ret ); ret = tmap0; } else { ret = astClone( axmap ); } /* Get axis label and symbol. */ sym = astGetSymbol( wcsfrm, iax ); lab = astGetLabel( wcsfrm, iax ); /* The axis symbols are taken as the CTYPE values. Append "-LOG" or "-TAB" if the axis is logarithmic or tabular. */ if( sym && strlen( sym ) ) { (void) sprintf( buf, "%s", sym ); } else { (void) sprintf( buf, "AXIS%d", iax + 1 ); } if( log_axis ) { SetAlgCode( buf, "-LOG", status ); } else if( tab_axis ) { SetAlgCode( buf, "-TAB", status ); } SetItemC( &(store->ctype), fits_i, 0, s, buf, status ); /* The axis labels are taken as the comment for the CTYPE keywords and as the CNAME keyword (but only if a label has been set and is different to the symbol). */ if( lab && lab[ 0 ] && astTestLabel( wcsfrm, iax ) && strcmp( sym, lab ) ) { SetItemC( &(store->ctype_com), fits_i, 0, s, (char *) lab, status ); SetItemC( &(store->cname), fits_i, 0, s, (char *) lab, status ); } else { sprintf( buf, "Type of co-ordinate on axis %d", iax + 1 ); SetItemC( &(store->ctype_com), fits_i, 0, s, buf, status ); } /* If a value has been set for the axis units, use it as CUNIT. */ if( astTestUnit( wcsfrm, iax ) ){ SetItemC( &(store->cunit), fits_i, 0, s, (char *) astGetUnit( wcsfrm, iax ), status ); } /* Indicate this axis has now been described. */ axis_done[ iax ] = 1; /* Release Resources. */ axmap = astAnnul( axmap ); } } /* Release Resources. */ wcsfrm = astAnnul( wcsfrm ); map = astAnnul( map ); pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); lbnd_p = astFree( lbnd_p ); ubnd_p = astFree( ubnd_p ); } /* If we have a Mapping to return, simplify it. Otherwise, create a UnitMap to return. */ if( ret ) { tmap0 = ret; ret = astSimplify( tmap0 ); tmap0 = astAnnul( tmap0 ); } else { ret = (AstMapping *) astUnitMap( nwcs, "", status ); } /* Return the result. */ return ret; } static int PCFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * PCFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-PC encoding. * Type: * Private function. * Synopsis: * int PCFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-PC encoding. * * Zero is returned if the primary axis descriptions cannot be produced. * Whether or not secondary axis descriptions can be produced does not * effect the returned value (i.e. failure to produce a specific set of * secondary axes does not prevent other axis descriptions from being * produced). * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ char *comm; /* Pointer to comment string */ char *cval; /* Pointer to string keyword value */ char combuf[80]; /* Buffer for FITS card comment */ char keyname[10]; /* Buffer for keyword name string */ char primsys[20]; /* Buffer for primnary RADECSYS value */ char type[MXCTYPELEN];/* Buffer for CTYPE value */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ char sup; /* Upper limit on s */ double *c; /* Pointer to next array element */ double *d; /* Pointer to next array element */ double *matrix; /* Pointer to Frame PC/CD matrix */ double *primpc; /* Pointer to primary PC/CD matrix */ double fd; /* Fraction of a day */ double mjd99; /* MJD at start of 1999 */ double primdt; /* Primary mjd-obs value */ double primeq; /* Primary equinox value */ double primln; /* Primary lonpole value */ double primlt; /* Primary latpole value */ double primpv[10]; /* Primary projection parameter values */ double val; /* General purpose value */ int axlat; /* Index of latitude FITS WCS axis */ int axlon; /* Index of longitude FITS WCS axis */ int axspec; /* Index of spectral FITS WCS axis */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int is; /* Co-ordinate version index */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int m; /* Parameter index */ int maxm; /* Upper limit on m */ int naxis; /* No. of axes */ int ok; /* Frame written out succesfully? */ int prj; /* Projection type */ int ret; /* Returned value. */ /* Initialise */ ret = 0; /* Check the inherited status. */ if( !astOK ) return ret; /* Find the number of co-ordinate versions in the FitsStore. FITS-PC can only encode 10 axis descriptions (including primary). */ sup = GetMaxS( &(store->crval), status ); if( sup > 'I' ) return ret; /* Initialise */ primdt = AST__BAD; primeq = AST__BAD; primln = AST__BAD; primlt = AST__BAD; /* Loop round all co-ordinate versions (0-9) */ primpc = NULL; for( s = ' '; s <= sup && astOK; s++ ){ is = s - 'A' + 1; /* Assume the Frame can be created succesfully. */ ok = 1; /* Save the number of wcs axes */ val = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { naxis = (int) ( val + 0.5 ); SetValue( this, FormatKey( "WCSAXES", -1, -1, s, status ), &naxis, AST__INT, "Number of WCS axes", status ); } else { naxis = GetMaxJM( &(store->crpix), s, status ) + 1; } /* PC matrix: --------- */ /* This encoding does not allow the PC matrix to be specified for each version - instead they all share the primary PC matrix. Therefore we need to check that all versions can use the primary PC matrix. Allocate memory to hold the PC matrix for this version. */ matrix = (double *) astMalloc( sizeof(double)*naxis*naxis ); if( matrix ){ /* Fill these array with the values supplied in the FitsStore. */ c = matrix; for( i = 0; i < naxis; i++ ){ for( j = 0; j < naxis; j++ ){ *c = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( *c == AST__BAD ) *c = ( i == j ) ? 1.0 : 0.0; c++; } } /* If we are currently processing the primary axis description, take a copy of the PC matrix. */ if( s == ' ' ) { primpc = (double *) astStore( NULL, (void *) matrix, sizeof(double)*naxis*naxis ); /* Store each matrix element in turn. */ c = matrix; for( i = 0; i < naxis; i++ ){ for( j = 0; j < naxis; j++ ){ /* Set the element bad if it takes its default value. */ val = *(c++); if( i == j ){ if( EQUAL( val, 1.0 ) ) val = AST__BAD; } else { if( EQUAL( val, 0.0 ) ) val = AST__BAD; } /* Only store elements which do not take their default values. */ if( val != AST__BAD ){ sprintf( keyname, "PC%.3d%.3d", i + 1, j + 1 ); SetValue( this, keyname, &val, AST__FLOAT, NULL, status ); } } } /* For secondary axis descriptions, a check is made that the PC values are the same as the primary PC values stored earlier. If not, the current Frame cannot be stored as a secondary axis description so continue on to the next Frame. */ } else { if( primpc ){ c = matrix; d = primpc; for( i = 0; i < naxis; i++ ){ for( j = 0; j < naxis; j++ ){ if( !EQUAL( *c, *d ) ){ ok = 0; } else { c++; d++; } } } /* Continue with the next Frame if the PC matrix for this Frame is different to the primary PC matrix. */ if( !ok ) goto next; } } matrix = (double *) astFree( (void *) matrix ); } /* CDELT: ------ */ for( i = 0; i < naxis; i++ ){ val = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Pixel scale on axis %d", i + 1 ); if( s == ' ' ) { sprintf( keyname, "CDELT%d", i + 1 ); } else { sprintf( keyname, "C%dELT%d", is, i + 1 ); } SetValue( this, keyname, &val, AST__FLOAT, combuf, status ); } /* CRPIX: ------ */ for( j = 0; j < naxis; j++ ){ val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Reference pixel on axis %d", j + 1 ); if( s == ' ' ) { sprintf( keyname, "CRPIX%d", j + 1 ); } else { sprintf( keyname, "C%dPIX%d", is, j + 1 ); } SetValue( this, keyname, &val, AST__FLOAT, combuf, status ); } /* CRVAL: ------ */ for( i = 0; i < naxis; i++ ){ val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 ); if( s == ' ' ) { sprintf( keyname, "CRVAL%d", i + 1 ); } else { sprintf( keyname, "C%dVAL%d", is, i + 1 ); } SetValue( this, keyname, &val, AST__FLOAT, combuf, status ); } /* CTYPE: ------ */ for( i = 0; i < naxis; i++ ){ cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( !cval || !strcmp( cval + 4, "-TAB" ) ) { ok = 0; goto next; } comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } if( s == ' ' ) { sprintf( keyname, "CTYPE%d", i + 1 ); } else { sprintf( keyname, "C%dYPE%d", is, i + 1 ); } /* FITS-PC cannot handle celestial axes of type "xxLT" or "xxLN". Neither can it handle the "-TAB". */ if( !strncmp( cval + 2, "LT-", 3 ) || !strncmp( cval + 2, "LN-", 3 ) || !strncmp( cval + 4, "-TAB", 4 ) ){ ok = 0; goto next; } /* Extract the projection type as specified by the last 4 characters in the CTYPE keyword value. This will be AST__WCSBAD for non-celestial axes. */ prj = astWcsPrjType( cval + 4 ); /* Change the new SFL projection code to to the older equivalent GLS */ if( prj == AST__SFL ) { strcpy( type, cval ); (void) strcpy( type + 4, "-GLS" ); cval = type; } /* FITS-PC cannot handle the AST-specific TPN projection. */ if( prj == AST__TPN ) { ok = 0; goto next; } /* Store the CTYPE value */ SetValue( this, keyname, &cval, AST__STRING, comm, status ); } /* Get and save CUNIT for all intermediate axes. These are NOT required, so do not pass on if they are not available. */ for( i = 0; i < naxis; i++ ){ cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( cval ) { sprintf( combuf, "Units for axis %d", i + 1 ); if( s == ' ' ) { sprintf( keyname, "CUNIT%d", i + 1 ); } else { sprintf( keyname, "C%dNIT%d", is, i + 1 ); } SetValue( this, keyname, &cval, AST__STRING, combuf, status ); } } /* Get and save RADESYS. This is NOT required, so do not pass on if it is not available. If RADECSYS is provided for a secondary axis, it must be the same as the primary axis RADECSYS value. If it is not, pass on to the next Frame. */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); if( cval ) { if( s == ' ' ) { strcpy( primsys, cval ); SetValue( this, "RADECSYS", &cval, AST__STRING, "Reference frame for RA/DEC values", status ); } else if( strcmp( cval, primsys ) ) { ok = 0; goto next; } } /* Reference equinox. This is NOT required, so do not pass on if it is not available. If equinox is provided for a secondary axis, it must be the same as the primary axis equinox value. If it is not, pass on to the next Frame. */ val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); if( s == ' ' ) { primeq = val; if( val != AST__BAD ) SetValue( this, "EQUINOX", &val, AST__FLOAT, "Epoch of reference equinox", status ); } else if( !EQUAL( val, primeq ) ){ ok = 0; goto next; } /* Latitude of native north pole. This is NOT required, so do not pass on if it is not available. If latpole is provided for a secondary axis, it must be the same as the primary axis value. If it is not, pass on to the next Frame. */ val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ); if( s == ' ' ) { primlt = val; if( val != AST__BAD ) SetValue( this, "LATPOLE", &val, AST__FLOAT, "Latitude of native north pole", status ); } else if( !EQUALANG( val, primlt ) ){ ok = 0; goto next; } /* Longitude of native north pole. This is NOT required, so do not pass on if it is not available. If lonpole is provided for a secondary axis, it must be the same as the primary axis value. If it is not, pass on to the next Frame. */ val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ); if( s == ' ' ) { primln = val; if( val != AST__BAD ) SetValue( this, "LONGPOLE", &val, AST__FLOAT, "Longitude of native north pole", status ); } else if( !EQUALANG( val, primln ) ){ ok = 0; goto next; } /* Date of observation. This is NOT required, so do not pass on if it is not available. If mjd-obs is provided for a secondary axis, it must be the same as the primary axis value. If it is not, pass on to the next Frame. */ val = GetItem( &(store->mjdobs), 0, 0, s, NULL, method, class, status ); if( s == ' ' ) { primdt = val; if( val != AST__BAD ) { SetValue( this, "MJD-OBS", &val, AST__FLOAT, "Modified Julian Date of observation", status ); /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", &cval, AST__STRING, "Date of observation", status ); } } else if( !EQUAL( val, primdt ) ){ ok = 0; goto next; } /* Look for the celestial and spectral axes. */ FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status ); /* If both longitude and latitude axes are present ...*/ if( axlon >= 0 && axlat >= 0 ) { /* Get the CTYPE values for the latitude axis. */ cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); /* Extract the projection type as specified by the last 4 characters in the CTYPE keyword value. */ prj = ( cval ) ? astWcsPrjType( cval + 4 ) : AST__WCSBAD; /* Projection parameters. If provided for a secondary axis, they must be the same as the primary axis value. If it is not, pass on to the next Frame. PC encoding ignores parameters associated with the longitude axis. The old PC TAN projection did not have any parameters. Pass on if a TAN projection with parameters is found. The number of parameters was limited to 10. Pass on if more than 10 are supplied. */ maxm = GetMaxJM( &(store->pv), ' ', status ); for( i = 0; i < naxis; i++ ){ if( i != axlon ) { for( m = 0; m <= maxm; m++ ){ val = GetItem( &(store->pv), i, m, s, NULL, method, class, status ); if( s == ' ' ){ if( val != AST__BAD ) { if( i != axlat || prj == AST__TAN || m >= 10 ){ ok = 0; goto next; } else { SetValue( this, FormatKey( "PROJP", m, -1, ' ', status ), &val, AST__FLOAT, "Projection parameter", status ); } } if( i == axlat && m < 10 ) primpv[m] = val; } else { if( ( ( i != axlat || m >= 10 ) && val != AST__BAD ) || ( i == axlat && m < 10 && !EQUAL( val, primpv[m] ) ) ){ ok = 0; goto next; } } } } } } /* See if a Frame was sucessfully written to the FitsChan. */ next: ok = ok && astOK; /* If so, indicate we have something to return. */ if( ok ) ret = 1; /* Clear any error status so we can continue to produce the next Frame. Retain the error if the primary axes could not be produced. After the primary axes, do the A axes. */ if( s != ' ' ) { astClearStatus; } else { s = 'A' - 1; } /* Remove the secondary "new" flags from the FitsChan. This flag is associated with cards which have been added to the FitsChan during this pass through the main loop in this function. If the Frame was written out succesfully, just clear the flags. If anything went wrong with this Frame, remove the flagged cards from the FitsChan. */ FixNew( this, NEW2, !ok, method, class, status ); /* Set the current card so that it points to the last WCS-related keyword in the FitsChan (whether previously read or not). */ FindWcs( this, 1, 1, 0, method, class, status ); } /* Annul the array holding the primary PC matrix. */ primpc = (double *) astFree( (void *) primpc ); /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ret : 0; } static void PreQuote( const char *value, char string[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ], int *status ) { /* * Name: * PreQuote * Purpose: * Pre-quote FITS character data. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void PreQuote( const char *value, * char string[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ] ) * Class Membership: * FitsChan member function. * Description: * This function processes a string value in such a way that it can * be stored as a FITS character value (associated with a keyword) * and later retrieved unchanged, except for possible truncation. * * This pre-processing is necessary because FITS does not regard * trailing white space as significant, so it is lost. This * function adds double quote (") characters around the string if * it is necessary in order to prevent this loss. These quotes are * also added to zero-length strings and to strings that are * already quoted (so that the original quotes are not lost when * they are later un-quoted). * * This function will silently truncate any string that is too long * to be stored as a FITS character value, but will ensure that the * maximum number of characters are retained, taking account of any * quoting required. * Parameters: * value * Pointer to a constant null-terminated string containing the * input character data to be quoted. All white space is * significant. * string * A character array into which the result string will be * written, with a terminating null. The maximum number of * characters from the input string that can be accommodated in * this is (AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 4), but this * will be reduced if quoting is necessary. * Notes: * - The UnPreQuote function should be used to reverse the effect * of this function on a string (apart from any truncation). */ /* Local Variables: */ int dq; /* Number of double quotes needed */ int dquotes; /* Final number of double quotes */ int i; /* Loop counter for input characters */ int j; /* Counter for output characters */ int nc; /* Number of characters to be accommodated */ int sq; /* Number of single quotes needed */ /* Check the global error status. */ if ( !astOK ) return; /* Initialise, setting the default number of double quotes (which applies to a zero-length string) to 2. */ dquotes = 2; nc = 0; sq = 0; /* Loop to consider each input character to see if it will fit into the result string. */ for ( i = 0; value[ i ]; i++ ) { /* If a single quote character is to be included, count it. When the string is encoded as FITS character data, these quotes will be doubled, so will increase the overall string length by one. */ if ( value[ i ] == '\'' ) sq++; /* See how many double quotes are needed around the string (0 or 2). These are needed if there is trailing white space that needs protecting (this is not significant in FITS and will be removed), or if the string already has quotes at either end (in which case an extra set is needed to prevent the original ones being removed when it is later un-quoted). Note we do not need to double existing double quote characters within the string, because the position of the ends of the string are known (from the quoting supplied by FITS) so only the first and last characters need be inspected when un-quoting the string. In assessing the number of double quotes, assume the string will be truncated after the current character. */ dq = ( isspace( value[ i ] ) || ( ( value[ 0 ] == '"' ) && ( value[ i ] == '"' ) ) ) ? 2 : 0; /* See if the length of the resulting string, including the current character and all necessary quotes, is too long. If so, give up here. */ if ( ( nc + 1 + dq + sq ) > ( AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 4 ) ) break; /* If the string is not too long, accept the character and note the number of double quotes needed. */ nc = i + 1; dquotes = dq; } /* If double quotes are needed, insert the opening quote into the output string. */ j = 0; if ( dquotes ) string[ j++ ] = '"'; /* Follow this with the maximum number of input string characters that can be accommodated. */ for ( i = 0; i < nc; i++ ) string[ j++ ] = value[ i ]; /* Append the closing quote if necessary and terminate the output string. */ if ( dquotes ) string[ j++ ] = '"'; string[ j ] = '\0'; } static void PurgeWCS( AstFitsChan *this, int *status ){ /* *++ * Name: c astPurgeWCS f AST_PURGEWCS * Purpose: * Delete all cards in the FitsChan describing WCS information. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astPurgeWCS( AstFitsChan *this ) f CALL AST_PURGEWCS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * deletes all cards in a FitsChan that relate to any of the recognised * WCS encodings. On exit, the current card is the first remaining card * in the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ AstObject *obj; int oldclean; /* Check the global status. */ if( !astOK ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Ensure the Clean attribute is set so that WCS keywords are removed even if an error occurs. */ if( astTestClean( this ) ) { oldclean = astGetClean( this ); astSetClean( this, 1 ); } else { astSetClean( this, 1 ); oldclean = -1; } /* Loop round attempting to read AST objects form the FitsChan. This will flag cards as used that are involved in the creation of these object (including NATIVE encodings). Ignore any error that ocurs whilst doing this. */ astClearCard( this ); if( astOK ) { int oldreporting = astReporting( 0 ); obj = astRead( this ); while( obj ) { obj = astAnnul( obj ); astClearCard( this ); obj = astRead( this ); } if( !astOK ) astClearStatus; astReporting( oldreporting ); } /* We now loop round to remove any spurious WCS-related cards left in the FitsChan that did not form part of a complete WCS encoding. Find the first WCS-related card left in the FitsChan. */ FindWcs( this, 0, 0, 1, "DeleteWcs", "FitsChan", status ); /* Loop round marking each WCS-related card as used until none are left */ while( this->card && astOK ) { /* Mark the current card as having been read. */ ( (FitsCard*) this->card )->flags = USED; /* Find the next WCS-related card. */ FindWcs( this, 0, 0, 0, "DeleteWcs", "FitsChan", status ); } /* Rewind the FitsChan. */ astClearCard( this ); /* Reset the Clean attribute. */ if( oldclean == -1 ) { astClearClean( this ); } else { astSetClean( this, oldclean ); } } static void PutCards( AstFitsChan *this, const char *cards, int *status ) { /* *++ * Name: c astPutCards f AST_PUTCARDS * Purpose: * Store a set of FITS header cards in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astPutCards( AstFitsChan *this, const char *cards ) f CALL AST_PUTCARDS( THIS, CARDS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * stores a set of FITS header cards in a FitsChan. The cards are * supplied concatenated together into a single character string. * Any existing cards in the FitsChan are removed before the new cards * are added. The FitsChan is "re-wound" on exit by clearing its Card * attribute. This means that a subsequent invocation of c astRead f AST_READ * can be made immediately without the need to re-wind the FitsChan * first. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c cards f CARDS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string f A character string * containing the FITS cards to be stored. Each individual card * should occupy 80 characters in this string, and there should be * no delimiters, new lines, etc, between adjacent cards. The final * card may be less than 80 characters long. c This is the format produced by the fits_hdr2str function in the c CFITSIO library. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - An error will result if the supplied string contains any cards * which cannot be interpreted. *-- */ /* Local Variables: */ const char *a; /* Pointer to start of next card */ int clen; /* Length of supplied string */ int i; /* Card index */ int ncard; /* No. of cards supplied */ /* Check the global error status. */ if ( !astOK ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Empty the FitsChan. */ astEmptyFits( this ); /* Loop round the supplied string in 80 character segments, inserting each segment into the FitsChan as a header card. Allow the last card to be less than 80 characters long. */ clen = strlen( cards ); ncard = clen/80; if( ncard*80 < clen ) ncard++; a = cards; for( i = 0; i < ncard; i++, a += 80 ) astPutFits( this, a, 1 ); /* Rewind the FitsChan. */ astClearCard( this ); } static void PutFits( AstFitsChan *this, const char card[ AST__FITSCHAN_FITSCARDLEN + 1 ], int overwrite, int *status ){ /* *++ * Name: c astPutFits f AST_PUTFITS * Purpose: * Store a FITS header card in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astPutFits( AstFitsChan *this, const char card[ 80 ], c int overwrite ) f CALL AST_PUTFITS( THIS, CARD, OVERWRITE, STATUS ) * Class Membership: * FitsChan method. * Description: c This function stores a FITS header card in a FitsChan. The card f This routine stores a FITS header card in a FitsChan. The card * is either inserted before the current card (identified by the * Card attribute), or over-writes the current card, as required. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c card f CARD = CHARACTER * ( 80 ) (Given) c Pointer to a possibly null-terminated character string c containing the FITS card to be stored. No more than 80 c characters will be used from this string (or fewer if a null c occurs earlier). f A character string string containing the FITS card to be f stored. No more than 80 characters will be used from this f string. c overwrite f OVERWRITE = LOGICAL (Given) c If this value is zero, the new card is inserted in front of f If this value is .FALSE., the new card is inserted in front of * the current card in the FitsChan (as identified by the c initial value of the Card attribute). If it is non-zero, the f initial value of the Card attribute). If it is .TRUE., the * new card replaces the current card. In either case, the Card * attribute is then incremented by one so that it subsequently * identifies the card following the one stored. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - If the Card attribute initially points at the "end-of-file" * (i.e. exceeds the number of cards in the FitsChan), then the new * card is appended as the last card in the FitsChan. * - An error will result if the supplied string cannot be interpreted * as a FITS header card. *-- */ /* Local Variables: */ char *comment; /* The keyword comment */ char *name; /* The keyword name */ char *value; /* The keyword value */ const char *class; /* Object class */ const char *method; /* Current method */ double cfval[2]; /* Complex floating point keyword value */ double fval; /* floating point keyword value */ int cival[2]; /* Complex integer keyword value */ int ival; /* Integer keyword value */ int len; /* No. of characters to read from the value string */ int nc; /* No. of characters read from value string */ int type; /* Keyword data type */ /* Check the global error status. */ if ( !astOK ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the current method, and the class of the supplied object for use in error messages.*/ method = "astPutFits"; class = astGetClass( this ); /* Split the supplied card up into name, value and commment strings, and get pointers to local copies of them. The data type associated with the keyword is returned. */ type = Split( card, &name, &value, &comment, method, class, status ); /* Check that the pointers can be used. */ if( astOK ){ /* Initialise the number of characters read from the value string. */ nc = 0; /* Store the number of characters in the value string. */ len = strlen( value ); /* Read and store floating point values from the value string. NB, this list is roughly in the order of descreasing frequency of use (i.e. most FITS keywords are simple floating point values, the next most common are strings, etc). */ if( type == AST__FLOAT ){ if( 1 == astSscanf( value, " %lf %n", &fval, &nc ) && nc >= len ){ astSetFitsF( this, name, fval, comment, overwrite ); } else { astError( AST__BDFTS, "%s(%s): Unable to read a floating point " "FITS keyword value.", status, method, class ); } /* Read and store string values from the value string. */ } else if( type == AST__STRING ){ astSetFitsS( this, name, value, comment, overwrite ); /* Read and store string values from the value string. */ } else if( type == AST__CONTINUE ){ astSetFitsCN( this, name, value, comment, overwrite ); /* Store comment card. */ } else if( type == AST__COMMENT ){ astSetFitsCom( this, name, comment, overwrite ); /* Read and store integer values from the value string. */ } else if( type == AST__INT ){ if( 1 == astSscanf( value, " %d %n", &ival, &nc ) && nc >= len ){ astSetFitsI( this, name, ival, comment, overwrite ); } else { astError( AST__BDFTS, "%s(%s): Unable to read an integer FITS " "keyword value.", status, method, class ); } /* Read and store logical values from the value string. */ } else if( type == AST__LOGICAL ){ astSetFitsL( this, name, (*value == 'T'), comment, overwrite ); /* Read and store undefined values from the value string. */ } else if( type == AST__UNDEF ){ astSetFitsU( this, name, comment, overwrite ); /* Read and store complex floating point values from the value string. */ } else if( type == AST__COMPLEXF ){ if( 2 == astSscanf( value, " %lf %lf %n", cfval, cfval + 1, &nc ) && nc >= len ){ astSetFitsCF( this, name, cfval, comment, overwrite ); } else { astError( AST__BDFTS, "%s(%s): Unable to read a complex pair " "of floating point FITS keyword values.", status, method, class ); } /* Read and store complex integer values from the value string. */ } else if( type == AST__COMPLEXI ){ if( 2 == astSscanf( value, " %d %d %n", cival, cival + 1, &nc ) && nc >= len ){ astSetFitsCI( this, name, cival, comment, overwrite ); } else { astError( AST__BDFTS, "%s(%s): Unable to read a complex pair " "of integer FITS keyword values.", status, method, class ); } /* Report an error for any other type. */ } else { astError( AST__INTER, "%s: AST internal programming error - " "FITS data-type '%d' not yet supported.", status, method, type ); } /* Give a context message if an error occurred. */ if( !astOK ){ astError( astStatus, "%s(%s): Unable to store the following FITS " "header card:\n%s\n", status, method, class, card ); } } /* Free the memory used to hold the keyword name, comment and value strings. */ (void) astFree( (void *) name ); (void) astFree( (void *) comment ); (void) astFree( (void *) value ); } static void PutTable( AstFitsChan *this, AstFitsTable *table, const char *extnam, int *status ) { /* *++ * Name: c astPutTable f AST_PUTTABLE * Purpose: * Store a single FitsTable in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astPutTable( AstFitsChan *this, AstFitsTable *table, c const char *extnam ) f CALL AST_PUTTABLE( THIS, TABLE, EXTNAM, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * allows a representation of a single FITS binary table to be * stored in a FitsChan. For instance, this may provide the coordinate * look-up tables needed subequently when reading FITS-WCS headers * for axes described using the "-TAB" algorithm. Since, in general, * the calling application may not know which tables will be needed - * if any - prior to calling c astRead, the astTablesSource function f AST_READ, the AST_TABLESOURCE routine * provides an alternative mechanism in which a caller-supplied * function is invoked to store a named table in the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c table f TABLE = INTEGER (Given) * Pointer to a FitsTable to be added to the FitsChan. If a FitsTable * with the associated extension name already exists in the FitsChan, * it is replaced with the new one. A deep copy of the FitsTable is * stored in the FitsChan, so any subsequent changes made to the * FitsTable will have no effect on the behaviour of the FitsChan. c extnam f EXTNAM = CHARACTER * ( * ) (Given) * The name of the FITS extension associated with the table. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Tables stored in the FitsChan may be retrieved using c astGetTables. f AST_GETTABLES. c - The astPutTables method can add multiple FitsTables in a single call. f - The AST_PUTTABLES method can add multiple FitsTables in a single call. *-- */ /* Local Variables: */ AstObject *ft; /* Check the global error status. */ if ( !astOK ) return; /* Create a KeyMap to hold the tables within the FitsChan, if this has not already been done. */ if( !this->tables ) this->tables = astKeyMap( " ", status ); /* Store a copy of the FitsTable in the FitsChan. */ ft = astCopy( table ); astMapPut0A( this->tables, extnam, ft, NULL ); ft = astAnnul( ft ); } static void PutTables( AstFitsChan *this, AstKeyMap *tables, int *status ) { /* *++ * Name: c astPutTables f AST_PUTTABLES * Purpose: * Store one or more FitsTables in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astPutTables( AstFitsChan *this, AstKeyMap *tables ) f CALL AST_PUTTABLES( THIS, TABLES, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * allows representations of one or more FITS binary tables to be * stored in a FitsChan. For instance, these may provide the coordinate * look-up tables needed subequently when reading FITS-WCS headers * for axes described using the "-TAB" algorithm. Since, in general, * the calling application may not know which tables will be needed - * if any - prior to calling c astRead, the astTablesSource function f AST_READ, the AST_TABLESOURCE routine * provides an alternative mechanism in which a caller-supplied * function is invoked to store a named table in the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c tables f TABLES = INTEGER (Given) * Pointer to a KeyMap holding the tables that are to be added * to the FitsChan. Each entry should hold a scalar value which is a * pointer to a FitsTable to be added to the FitsChan. Any unusable * entries are ignored. The key associated with each entry should be * the name of the FITS binary extension from which the table was * read. If a FitsTable with the associated key already exists in the * FitsChan, it is replaced with the new one. A deep copy of each * usable FitsTable is stored in the FitsChan, so any subsequent * changes made to the FitsTables will have no effect on the * behaviour of the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - Tables stored in the FitsChan may be retrieved using c astGetTables. f AST_GETTABLES. * - The tables in the supplied KeyMap are added to any tables already * in the FitsChan. c - The astPutTable f - The AST_PUTTABLE * method provides a simpler means of adding a single table to a FitsChan. *-- */ /* Local Variables: */ AstObject *obj; const char *key; int ientry; int nentry; /* Check the global error status. */ if ( !astOK ) return; /* Loop through all entries in the supplied KeyMap. */ nentry = astMapSize( tables ); for( ientry = 0; ientry < nentry; ientry++ ) { key = astMapKey( tables, ientry ); /* Ignore entries that do not contain AST Object pointers, or are not scalar. */ if( astMapType( tables, key ) == AST__OBJECTTYPE && astMapLength( tables, key ) == 1 ) { /* Get the pointer, amd ignore it if it is not a FitsTable. */ astMapGet0A( tables, key, &obj ); if( astIsAFitsTable( obj ) ) { /* Store it in the FitsChan. */ astPutTable( this, (AstFitsTable *) obj, key ); } /* Annul the Object pointer. */ obj = astAnnul( obj ); } } } static AstObject *Read( AstChannel *this_channel, int *status ) { /* * Name: * Read * Purpose: * Read an Object from a Channel. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstObject *Read( AstChannel *this_channel, int *status ) * Class Membership: * FitsChan member function (over-rides the astRead method * inherited from the Channel class). * Description: * This function reads an Object from a FitsChan. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new Object. This will always be a FrameSet. * Notes: * - The pixel Frame is given a title of "Pixel Coordinates", and * each axis in the pixel Frame is given a label of the form "Pixel * axis ", where is the axis index (starting at one). * - The FITS CTYPE keyword values are used to set the labels for any * non-celestial axes in the physical coordinate Frames, and the FITS * CUNIT keywords are used to set the corresponding units strings. * - On exit, the pixel Frame is the base Frame, and the physical * Frame derived from the primary axis descriptions is the current Frame. * - Extra Frames are added to hold any secondary axis descriptions. All * axes within such a Frame refer to the same coordinate version ('A', * 'B', etc). * - For foreign encodings, the first card in the FitsChan must be * the current card on entry (otherwise a NULL pointer is returned), * and the FitsChan is left at end-of-file on exit. * - For the Native encoding, reading commences from the current card * on entry (which need not be the first in the FitsChan), and the * current Card on exit is the first card following the last one read * (or end-of-file). */ /* Local Variables: */ AstObject *new; /* Pointer to returned Object */ AstFitsChan *this; /* Pointer to the FitsChan structure */ FitsStore *store; /* Intermediate storage for WCS information */ const char *method; /* Pointer to string holding calling method */ const char *class; /* Pointer to string holding object class */ int encoding; /* The encoding scheme */ int remove; /* Remove used cards? */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the calling method, and object class. */ method = "astRead"; class = astGetClass( this ); /* Get the encoding scheme used by the FitsChan. */ encoding = astGetEncoding( this ); /* If we are reading from a FitsChan in which AST objects are encoded using native AST-specific keywords, use the Read method inherited from the Channel class. */ if( encoding == NATIVE_ENCODING ){ new = (*parent_read)( this_channel, status ); /* Indicate that used cards should be removed from the FitsChan. */ remove = 1; /* If we are reading from a FitsChan in which AST objects are encoded using any of the other supported encodings, the header may only contain a single FrameSet. */ } else { remove = 0; /* Only proceed if the FitsChan is at start-of-file. */ if( !astTestCard( this ) && astOK ){ /* Extract the required information from the FITS header into a standard intermediary structure called a FitsStore. */ store = FitsToStore( this, encoding, method, class, status ); /* Now create a FrameSet from this FitsStore. */ new = FsetFromStore( this, store, method, class, status ); /* Release the resources used by the FitsStore. */ store = FreeStore( store, status ); /* Indicate that used cards should be retained in the FitsChan. */ remove = 0; /* If no object is being returned, rewind the fitschan in order to re-instate the original current Card. */ if( !new ) { astClearCard( this ); /* Otherwise, ensure the current card is at "end-of-file". */ } else { astSetCard( this, INT_MAX ); } } } /* If an error occurred, clean up by deleting the new Object and return a NULL pointer. */ if ( !astOK ) new = astDelete( new ); /* If no object is being returned, clear the "provisionally used" flags associated with cards which were read. We do not do this if the user wants to clean WCS cards from the FitsChan even if an error occurs. */ if( !new && !astGetClean( this ) ) { FixUsed( this, 0, 0, 0, method, class, status ); /* Otherwise, indicate that all the "provisionally used" cards have been "definitely used". If native encoding was used, these cards are totally removed from the FitsChan. */ } else { FixUsed( this, 0, 1, remove, method, class, status ); } /* Return the pointer to the new Object. */ return new; } static double *ReadCrval( AstFitsChan *this, AstFrame *wcsfrm, char s, const char *method, const char *class, int *status ){ /* * Name: * ReadCrval * Purpose: * Obtain the reference point from the supplied FitsChan in the * supplied WCS Frame. * Type: * Private function. * Synopsis: * #include "fitschan.h" * double *ReadCrval( AstFitsChan *this, AstFrame *wcsfrm, char s, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The original reference point in the "s" coordinate description is read * from the CRVAL keywords in the supplied FitsChan, and the original * FrameSet is re-read from the FitsChan. If possible, the reference * position is then converted from the "s" coordinate description to the * supplied WCS Frame, and a pointer to an array holding the axis * values for the transformed reference point is returned. * Parameters: * this * The FitsChan. * wcsfrm * The WCS Frame in the FitsChan being written to. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated array holding the reference * point in the supplied WCS Frame. NULL is returned if is is not * possible to determine the reference point for any reason (for * instance, if the FitsChan does not contain values for the CRVAL * keywords). */ /* Local Variables: */ AstFitsChan *fc; /* A copy of the supplied FitsChan */ AstFrame *tfrm; /* Temporary Frame pointer */ AstFrameSet *fs; /* The FITS FrameSet */ AstFrameSet *tfs; /* FrameSet connecting FITS and supplied WCS Frame */ const char *id; /* Pointer to Object "Id" string */ char buf[ 11 ]; /* FITS keyword template buffer */ double *crval; /* CRVAL keyword values in supplied FitsChan */ double *ret; /* Returned array */ int hii; /* Highest found FITS axis index */ int iax; /* Axis index (zero based) */ int ifr; /* Frames index */ int loi; /* Lowest found FITS axis index */ int nax; /* Axis count */ int nfr; /* No. of Frames in FITS FrameSet */ int ok; /* Were CRVAL values found? */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* We want to re-create the original FrameSet represented by the original contents of the supplied FitsChan. Some of the contents of the FitsChan will already have been marked as "having been read" and so will be ignored if we attempt to read a FrameSet directly from the supplied FitsChan. Therefore we take a deep copy of the supplied FitsChan and clear all the "previusly read" flags in the copy. */ fc = astCopy( this ); astClearEncoding( fc ); FixUsed( fc, 1, 0, 0, method, class, status ); /* Copy the CRVAL values for the "s" axis descriptions into a dynamically allocated array ("crval"). */ if( s == ' ' ) { strcpy( buf, "CRVAL%d" ); } else { sprintf( buf, "CRVAL%%d%c", s ); } if( astKeyFields( fc, buf, 1, &hii, &loi ) > 0 ) { crval = astMalloc( sizeof( double )*(size_t) hii ); ok = 1; for( iax = 0; iax < hii; iax++ ){ ok = ok && GetValue( fc, FormatKey( "CRVAL", iax + 1, -1, s, status ), AST__FLOAT, (void *) (crval + iax), 0, 0, method, class, status ); } } else { crval = NULL; ok = 0; } /* If the CRVAL values were obtained succesfully, attempt to read a FrameSet from the FitsChan copy. Do it in a new error report context so that we can annull any error when the FrameSet is read. */ if( ok ) { int oldreporting = astReporting( 0 ); astClearCard( fc ); fs = astRead( fc ); if( fs ) { /* We want to find a conversion from the Frame in this FrameSet which represents the FITS-WCS "s" coordinate descriptions and the supplied WCS Frame. So first find the Frame which has its Ident attribute set to "s" and make it the current Frame. */ nfr = astGetNframe( fs ); for( ifr = 1; ifr <= nfr; ifr++ ) { astSetCurrent( fs, ifr ); tfrm = astGetFrame( fs, ifr ); id = astTestIdent( tfrm ) ? astGetIdent( tfrm ) : NULL; tfrm = astAnnul( tfrm ); if( id && strlen( id ) == 1 && id[ 0 ] == s ) break; } /* Check a Frame was found, and that we have CRVAL values for all axes in the Frame. */ if( ifr <= nfr && astGetNaxes( fs ) == hii ) { /* Attempt to find a conversion route from the Frame found above to the supplied WCS Frame. */ tfs = astConvert( fs, wcsfrm, astGetDomain( wcsfrm ) ); if( tfs ) { /* Allocate memory to hold the returned reference point. */ nax = astGetNaxes( wcsfrm ); ret = astMalloc( sizeof( double )*(size_t) nax ); /* Transform the original reference position from the "s" Frame to the supplied WCS Frame using the Mapping returned by astConvert. */ astTranN( tfs, 1, hii, 1, crval, 1, nax, 1, ret ); /* Free resources. */ tfs = astAnnul( tfs ); } } /* Free resources. */ fs = astAnnul( fs ); /* Annul any error that occurred reading the FitsChan. */ } else if( !astOK ) { astClearStatus; } /* Re-instate error reporting. */ astReporting( oldreporting ); } /* Free resources. */ if( crval ) crval = astFree( crval ); fc = astAnnul( fc ); /* If an error occurred, free the returned array. */ if( !astOK ) ret = astFree( ret ); /* Return the result. */ return ret; } static void ReadFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astReadFits f AST_READFITS * Purpose: * Read cards into a FitsChan from the source function. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astReadFits( AstFitsChan *this ) f CALL AST_READFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * reads cards from the source function that was specified when the * FitsChan was created, and stores them in the FitsChan. This * normally happens once-only, when the FitsChan is accessed for the * first time. c This function f This routine * provides a means of forcing a re-read of the external source, and * may be useful if (say) new cards have been deposited into the * external source. Any newcards read from the source are appended to * the end of the current contents of the FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - This function returns without action if no source function was * specified when the FitsChan was created. * - The SourceFile attribute is ignored by this c function. f routine. * New cards are read from the source file whenever a new value is * assigned to the SourceFile attribute. *-- */ /* Check the inherited status */ if( !astOK ) return; /* If no source function is available, re-instate any saved source function pointer. */ if( !this->source ) { this->source = this->saved_source; this->saved_source = NULL; } /* Call the source function. */ ReadFromSource( this, status ); } static void ReadFromSource( AstFitsChan *this, int *status ){ /* * Name: * ReadFromSource * Purpose: * Fill the FitsChan by reading cards from the source function. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void ReadFromSource( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * The source function specified when the FitsChan was created is * called repeatedly until it returns a NULL pointer. The string * returned by each such call is assumed to be a FITS header card, * and is stored in the FitsChan using astPutFits. * * If no source function was provided, the FitsChan is left as supplied. * This is different to a standard Channel, which tries to read data * from standard input if no source function is provided. * * This function should be called at the start of most public or protected * FitsChan functions, and most private functions that are used to override * methods inherited form the Channel class. Previously, this function * was called only once, from the FitsChan initialiser (astInitFitschan). * However, calling it from astInitFitsChan means that application code * cannot use the astPutChannelData function with a FitsChan, since the * source function would already have been called by the time the * FitsChan constructor returned (and thus before astPutChannelData * could have been called). In order to ensure that the source * function is called only once, this function now nullifies the source * function pointer after its first use. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Notes: * - The new cards are appended to the end of the FitsChan. * - The first of the new cards is made the current card on exit. If no * source function is supplied, the current card is left unchanged. */ /* Local Variables: */ const char *(* source)( void ); /* Pointer to source function */ const char *card; /* Pointer to externally-read header card */ int icard; /* Current card index on entry */ /* Check the global status. */ if( !astOK || !this ) return; /* Only proceed if source function and wrapper were supplied when the FitsChan was created and are still available. */ if( this->source && this->source_wrap ){ /* Save the source function pointer and then nullify the pointer in the FitsChan structure. This avoids infinte loops. */ source = this->source; this->source = NULL; /* Save the source fubnction pointer in the FitsChan so that it can be re-instated if required (e.g. by astReadFits). */ this->saved_source = source; /* Ensure the FitsChan is at end-of-file. This will result in the new cards being appended to the end of the FitsChan. */ astSetCard( this, INT_MAX ); /* Store the current card index. */ icard = astGetCard( this ); /* Obtain the first header card from the source function. This is an externally supplied function which may not be thread-safe, so lock a mutex first. Also store the channel data pointer in a global variable so that it can be accessed in the source function using macro astChannelData. */ astStoreChannelData( this ); LOCK_MUTEX2; card = ( *this->source_wrap )( source, status ); UNLOCK_MUTEX2; /* Loop until a NULL pointer is returned by the source function, or an error occurs. */ while( card && astOK ){ /* Store the card in the FitsChan. */ astPutFits( this, card, 0 ); /* Free the memory holding the header card. */ card = (char *) astFree( (void *) card ); /* Obtain the next header card. Also store the channel data pointer in a global variable so that it can be accessed in the source function using macro astChannelData. */ astStoreChannelData( this ); LOCK_MUTEX2; card = ( *this->source_wrap )( source, status ); UNLOCK_MUTEX2; } /* Set the current card index so that the first of the new cards will be the next card to be read from the FitsChan. */ astSetCard( this, icard ); } } static void RemoveTables( AstFitsChan *this, const char *key, int *status ){ /* *++ * Name: c astRemoveTables f AST_REMOVETABLES * Purpose: * Remove one or more tables from a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astRemoveTables( AstFitsChan *this, const char *key ) f CALL AST_REMOVETABLES( THIS, KEY, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * removes the named tables from the FitsChan, it they exist (no error * is reported if any the tables do not exist). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c key f KEY = CHARACTER * ( * ) (Given) * The key indicating which tables to exist. A single key or a * comma-separated list of keys can be supplied. If a blank string * is supplied, all tables are removed. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local variables: */ char **words; int itable; int ntable; /* Return if the global error status has been set, or the FitsChan contains no tables KeyMap. */ if( !astOK || !this->tables ) return; /* If the string is blank, remove all tables. */ if( astChrLen( key ) == 0 ) { ntable = astMapSize( this->tables ); for( itable = 0; itable < ntable; itable++ ) { astMapRemove( this->tables, astMapKey( this->tables, itable ) ); } /* Otherwise, split the supplied comma-separated string up into individual items. */ } else { words = astChrSplitC( key, ',', &ntable ); /* Attempt to remove each one, and then free the string. */ if( astOK ) { for( itable = 0; itable < ntable; itable++ ) { astMapRemove( this->tables, words[ itable ] ); words[ itable ] = astFree( words[ itable ] ); } } /* Free the list. */ words = astFree( words ); } } static void RetainFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astRetainFits f AST_RETAINFITS * Purpose: * Indicate that the current card in a FitsChan should be retained. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astRetainFits( AstFitsChan *this ) f CALL AST_RETAINFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * stores a flag with the current card in the FitsChan indicating that * the card should not be removed from the FitsChan when an Object is * read from the FitsChan using c astRead. f AST_READ. * * Cards that have not been flagged in this way are removed when a * read operation completes succesfully, but only if the card was used * in the process of creating the returned AST Object. Any cards that * are irrelevant to the creation of the AST Object are retained whether * or not they are flagged. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - This function returns without action if the FitsChan is * initially positioned at the "end-of-file" (i.e. if the Card * attribute exceeds the number of cards in the FitsChan). * - The current card is not changed by this function. *-- */ /* Local variables: */ int flags; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Return if the global error status has been set, or the current card is not defined. */ if( !astOK || !this->card ) return; /* Set the PROTECTED flag in the current card. */ flags = ( (FitsCard *) this->card )->flags; ( (FitsCard *) this->card )->flags = flags | PROTECTED; } static void RoundFString( char *text, int width, int *status ){ /* * Name: * RoundString * Purpose: * Modify a formatted floating point number to round out long * sequences of zeros or nines. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void RoundFString( char *text, int width ) * Class Membership: * FitsChan member function. * Description: * The supplied string is assumed to be a valid decimal representation of * a floating point number. It is searched for sub-strings consisting * of NSEQ or more adjacent zeros, or NSEQ or more adjacent nines. If found * the string is modified to represent the result of rounding the * number to remove the sequence of zeros or nines. * Parameters: * text * The formatted number. Modified on exit to round out long * sequences of zeros or nines. The returned string is right justified. * width * The minimum field width to use. The value is right justified in * this field width. Ignored if zero. */ /* Local Constants: */ #define NSEQ 4 /* No. of adjacent 0's or 9's to produce rounding */ /* Local Variables: */ char *a; char *c; char *dot; char *exp; char *last; char *start; char *end; int i; int neg; int nnine; int nonzero; int nzero; int replace; int started; int len; int bu; int nls; /* Check the inherited status. */ if( !astOK ) return; /* Save the original length of the text. */ len = strlen( text ); /* Locate the start of any exponent string. */ exp = strpbrk( text, "dDeE" ); /* First check for long strings of adjacent zeros. =============================================== */ /* Indicate that we have not yet found a decimal point in the string. */ dot = NULL; /* The "started" flag controls whether *leading* zeros should be removed if there are more than NSEQ of them. They are only removed if there is an exponent. */ started = ( exp != NULL ); /* We are not currently replacing digits with zeros. */ replace = 0; /* We have not yet found any adjacent zeros. */ nzero = 0; /* We have no evidence yet that the number is non-zero. */ nonzero = 0; /* Loop round the supplied text string. */ c = text; while( *c && c != exp ){ /* If this is a zero, increment the number of adjacent zeros found, so long as we have previously found a non-zero digit (or there is an exponent). If this is the NSEQ'th adjacent zero, indicate that subsequent digits should be replaced by zeros. */ if( *c == '0' ){ if( started && ++nzero >= NSEQ ) replace = 1; /* Note if the number contains a decimal point. */ } else if( *c == '.' ){ dot = c; /* If this character is a non-zero digit, indicate that we have found a non-zero digit. If we have previously found a long string of adjacent zeros, replace the digit by '0'. Otherwise, reset the count of adjacent zeros, and indicate the final number is non-zero. */ } else if( *c != ' ' && *c != '+' && *c != '-' ){ started = 1; if( replace ) { *c = '0'; } else { nzero = 0; nonzero = 1; } } /* Move on to the next character. */ c++; } /* If the final number is zero, just return the most simple decimal zero value. */ if( !nonzero ) { strcpy( text, "0.0" ); /* Otherwise, we remove any trailing zeros which occur to the right of a decimal point. */ } else if( dot ) { /* Find the last non-zero digit. */ while( c-- > text && *c == '0' ); /* If any trailing zeros were found... */ if( c > text ) { /* Retain one trailing zero after a decimal point. */ if( *c == '.' ) c++; /* We put a terminator following the last non-zero character. The terminator is the exponent, if there was one, or a null character. Remember to update the pointer to the start of the exponent. */ c++; if( exp ) { a = exp; exp = c; while( ( *(c++) = *(a++) ) ); } else { *c = 0; } } } /* Next check for long strings of adjacent nines. ============================================= */ /* We have not yet found any adjacent nines. */ nnine = 0; /* We have not yet found a non-nine digit. */ a = NULL; /* We have not yet found a non-blank character */ start = NULL; last = NULL; /* Number is assumed positive. */ neg = 0; /* Indicate that we have not yet found a decimal point in the string. */ dot = NULL; /* Loop round the supplied text string. */ c = text; while( *c && c != exp ){ /* Note the address of the first non-blank character. */ if( !start && *c != ' ' ) start = c; /* If this is a nine, increment the number of adjacent nines found. */ if( *c == '9' ){ ++nnine; /* Note if the number contains a decimal point. */ } else if( *c == '.' ){ dot = c; /* Note if the number is negative. */ } else if( *c == '-' ){ neg = 1; /* If this character is a non-nine digit, and we have not had a long sequence of 9's, reset the count of adjacent nines, and update a pointer to "the last non-nine digit prior to a long string of nines". */ } else if( *c != ' ' && *c != '+' ){ if( nnine < NSEQ ) { nnine = 0; a = c; } } /* Note the address of the last non-blank character. */ if( *c != ' ' ) last = c; /* Move on to the next character. */ c++; } /* If a long string of adjacent nines was found... */ if( nnine >= NSEQ ) { c = NULL; /* If we found at least one non-nine digit. */ if( a ) { /* "a" points to the last non-nine digit before the first of the group of 9's. Increment this digit by 1. Since we know the digit is not a nine, there is no danger of a carry. */ *a = *a + 1; /* Fill with zeros up to the decimal point, or to the end if there is no decimal point. */ c = a + 1; if( dot ) { while( c < dot ) *(c++) = '0'; } else { while( *c ) *(c++) = '0'; } /* Now make "c" point to the first character for the terminator. This is usually the character following the last non-nine digit. However, if the last non-nine digit appears immediately before a decimal point, then we append ".0" to the string before appending the terminator. */ if( *c == '.' ) { *(++c) = '0'; c++; } /* If all digits were nines, the rounded number will occupy one more character than the supplied number. We can only do the rounding if there is a spare character (i.e.a space) in the supplied string. */ } else if( last - start + 1 < len ) { /* Put the modified text at the left of the available space. */ c = text; /* Start with a minus sing if needed, followed by the leading "1" (caused by the overflow from the long string of 9's). */ if( neg ) *(c++) = '-'; *(c++) = '1'; /* Now find the number of zeros to place after the leading "1". This is the number of characters in front of the terminator marking the end of the integer part of the number. */ if( dot ) { nzero = dot - start; } else if( exp ) { nzero = exp - start; } else { nzero = last - start; } /* If the number is negative, the above count will include the leading minus sign, which is not a digit. So reduce the count by one. */ if( neg ) nzero--; /* Now put in the correct number of zeros. */ for( i = 0; i < nzero; i++ ) *(c++) = '0'; /* If the original string containsed a decimal point, make sure the returned string also contains one. */ if( dot ) { *(c++) = '.'; if( *c ) *(c++) = '0'; } } /* We put a terminator following the last non-zero character. The terminator is the exponent, if there was one, or a null character. */ if( c ) { if( exp ) { while( ( *(c++) = *(exp++) ) ); } else { *c = 0; } } } /* Right justify the returned string in the original field width. */ end = text + len; c = text + strlen( text ); if( c != end ) { while( c >= text ) *(end--) = *(c--); while( end >= text ) *(end--) = ' '; } /* If a minimum field width was given, shunt the text to the left in order to reduce the used field width to the specified value. This requires there to be some leading spaces (because we do not want to loose any non-blank characters from the left hand end of the string). If there are insufficient leading spaces to allow the field width to be reduced to the specified value, then reduce the field width as far as possible. First find the number of spaces we would like to remove from the front of the string (in order to reduce the used width to the specified value). */ bu = len - width; /* If we need to remove any leading spaces... */ if( width > 0 && bu > 0 ) { /* Find the number of leading spaces which are available to be removed. */ c = text - 1; while( *(++c) == ' ' ); nls = c - text; /* If there are insufficient leading spaces, just use however many there are. */ if( bu > nls ) bu = nls; /* Shift the string. */ c = text; a = c + bu; while( ( *(c++) = *(a++) ) ); } /* Undefine local constants. */ #undef NSEQ } static int SAOTrans( AstFitsChan *this, AstFitsChan *out, const char *method, const char *class, int *status ){ /* * Name: * SAOTrans * Purpose: * Translate an SAO encoded header into a TPN encoded header. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int SAOTrans( AstFitsChan *this, AstFitsChan *out, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Search "this" for keywords that give a description of a distorted * TAN projection using the SAO representation and, if found, write * keywords to "out" that describe an equivalent projection using TPN * representation. The definition of the SAO polynomial is taken from * the platepos.c file included in Doug Mink's WCSTools. * Parameters: * this * Pointer to the FitsChan to read. * out * Pointer to a FitsCHan in which to store translated keywords. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if "this" contained an SAO encoded header. Zero otherwise. */ #define NC 13 /* Local Variables: */ char keyname[10]; double co[ 2 ][ NC ]; double pv; int i; int is_sao; int m; int ok; int result; /* Initialise */ result = 0; /* Check the inherited status. */ if( !astOK ) return result; /* Check there are exactly two CTYPE keywords in the header. */ if( 2 == astKeyFields( this, "CTYPE%d", 0, NULL, NULL ) ){ /* Initialise all cooefficients. */ memset( co, 0, sizeof( co ) ); /* Get the required SAO keywords. */ is_sao = 1; ok = 1; for( i = 0; i < 2 && ok && is_sao; i++ ) { ok = 0; for( m = 0; m < NC; m++ ) { /* Get the value of the next "COi_j" keyword. If any of the first 3 values are missing on either axis, we assume this is not an SAO header. */ sprintf( keyname, "CO%d_%d", i + 1, m + 1 ); if( !GetValue( this, keyname, AST__FLOAT, &co[ i ][ m ], 0, 1, method, class, status ) ) { if( m < 3 ) is_sao = 0; break; } /* Check that we have at least one non-zero coefficient (excluding the first constant term ). */ if( co[ i ][ m ] != 0.0 && m > 0 ) ok = 1; } } /* If this is an SAO header.. */ if( is_sao ) { /* Issue a warning if all coefficients for this axis are zero. */ if( !ok ) { Warn( this, "badpv", "This FITS header describes an SAO encoded " "distorted TAN projection, but all the distortion " "coefficients for at least one axis are zero.", method, class, status ); /* Otherwise, calculate and store the equivalent PV projection parameters. */ } else { pv = co[ 0 ][ 0 ]; if( pv != AST__BAD ) SetValue( out, "PV1_0", &pv, AST__FLOAT, NULL, status ); pv = co[ 0 ][ 1 ]; if( pv != AST__BAD ) SetValue( out, "PV1_1", &pv, AST__FLOAT, NULL, status ); pv = co[ 0 ][ 2 ]; if( pv != AST__BAD ) SetValue( out, "PV1_2", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 3 ] != AST__BAD ) pv += co[ 0 ][ 3 ]; if( co[ 0 ][ 10 ] != AST__BAD ) pv += co[ 0 ][ 10 ]; if( pv != AST__BAD ) SetValue( out, "PV1_4", &pv, AST__FLOAT, NULL, status ); pv = co[ 0 ][ 5 ]; if( pv != AST__BAD ) SetValue( out, "PV1_5", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 4 ] != AST__BAD ) pv += co[ 0 ][ 4 ]; if( co[ 0 ][ 10 ] != AST__BAD ) pv += co[ 0 ][ 10 ]; if( pv != AST__BAD ) SetValue( out, "PV1_6", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 6 ] != AST__BAD ) pv += co[ 0 ][ 6 ]; if( co[ 0 ][ 11 ] != AST__BAD ) pv += co[ 0 ][ 11 ]; if( pv != AST__BAD ) SetValue( out, "PV1_7", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 8 ] != AST__BAD ) pv += co[ 0 ][ 8 ]; if( co[ 0 ][ 12 ] != AST__BAD ) pv += co[ 0 ][ 12 ]; if( pv != AST__BAD ) SetValue( out, "PV1_8", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 9 ] != AST__BAD ) pv += co[ 0 ][ 9 ]; if( co[ 0 ][ 11 ] != AST__BAD ) pv += co[ 0 ][ 11 ]; if( pv != AST__BAD ) SetValue( out, "PV1_9", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 0 ][ 7 ] != AST__BAD ) pv += co[ 0 ][ 7 ]; if( co[ 0 ][ 12 ] != AST__BAD ) pv += co[ 0 ][ 12 ]; if( pv != AST__BAD ) SetValue( out, "PV1_10", &pv, AST__FLOAT, NULL, status ); pv = co[ 1 ][ 0 ]; if( pv != AST__BAD ) SetValue( out, "PV2_0", &pv, AST__FLOAT, NULL, status ); pv = co[ 1 ][ 2 ]; if( pv != AST__BAD ) SetValue( out, "PV2_1", &pv, AST__FLOAT, NULL, status ); pv = co[ 1 ][ 1 ]; if( pv != AST__BAD ) SetValue( out, "PV2_2", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 4 ] != AST__BAD ) pv += co[ 1 ][ 4 ]; if( co[ 1 ][ 10 ] != AST__BAD ) pv += co[ 1 ][ 10 ]; if( pv != AST__BAD ) SetValue( out, "PV2_4", &pv, AST__FLOAT, NULL, status ); pv = co[ 1 ][ 5 ]; if( pv != AST__BAD ) SetValue( out, "PV2_5", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 3 ] != AST__BAD ) pv += co[ 1 ][ 3 ]; if( co[ 1 ][ 10 ] != AST__BAD ) pv += co[ 1 ][ 10 ]; if( pv != AST__BAD ) SetValue( out, "PV2_6", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 7 ] != AST__BAD ) pv += co[ 1 ][ 7 ]; if( co[ 1 ][ 12 ] != AST__BAD ) pv += co[ 1 ][ 12 ]; if( pv != AST__BAD ) SetValue( out, "PV2_7", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 9 ] != AST__BAD ) pv += co[ 1 ][ 9 ]; if( co[ 1 ][ 11 ] != AST__BAD ) pv += co[ 1 ][ 11 ]; if( pv != AST__BAD ) SetValue( out, "PV2_8", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 8 ] != AST__BAD ) pv += co[ 1 ][ 8 ]; if( co[ 1 ][ 12 ] != AST__BAD ) pv += co[ 1 ][ 12 ]; if( pv != AST__BAD ) SetValue( out, "PV2_9", &pv, AST__FLOAT, NULL, status ); pv = 0.0; if( co[ 1 ][ 6 ] != AST__BAD ) pv += co[ 1 ][ 6 ]; if( co[ 1 ][ 11 ] != AST__BAD ) pv += co[ 1 ][ 11 ]; if( pv != AST__BAD ) SetValue( out, "PV2_10", &pv, AST__FLOAT, NULL, status ); /* From an example header provided by Bill Joye, it seems that the SAO polynomial includes the rotation and scaling effects of the CD matrix. Therefore we mark as read all CDi_j, CDELT and CROTA values. Without this, the rotation and scaling would be applied twice. First, mark the original values as having been used, no matter which FitsChan they are in. */ GetValue( this, "CD1_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CD1_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CD2_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CD2_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "PC1_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "PC1_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "PC2_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "PC2_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CDELT1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CDELT2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CROTA1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( this, "CROTA2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CD1_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CD1_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CD2_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CD2_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "PC1_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "PC1_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "PC2_1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "PC2_2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CDELT1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CDELT2", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CROTA1", AST__FLOAT, &pv, 0, 1, method, class, status ); GetValue( out, "CROTA2", AST__FLOAT, &pv, 0, 1, method, class, status ); /* Now store new default values in the returned FitsChan. */ pv = 1.0; SetValue( out, "PC1_1", &pv, AST__FLOAT, NULL, status ); SetValue( out, "PC2_2", &pv, AST__FLOAT, NULL, status ); SetValue( out, "CDELT1", &pv, AST__FLOAT, NULL, status ); SetValue( out, "CDELT2", &pv, AST__FLOAT, NULL, status ); pv = 0.0; SetValue( out, "PC1_2", &pv, AST__FLOAT, NULL, status ); SetValue( out, "PC2_1", &pv, AST__FLOAT, NULL, status ); /* Indicate we have converted an SAO header. */ result = 1; } } } /* Return a flag indicating if an SAO header was found. */ return result; } #undef NC static int SearchCard( AstFitsChan *this, const char *name, const char *method, const char *class, int *status ){ /* * Name: * SearchCard * Purpose: * Search the whole FitsChan for a card refering to given keyword. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int SearchCard( AstFitsChan *this, const char *name, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * Searches the whole FitsChan for a card refering to the supplied keyword, * and makes it the current card. The card following the current card is * checked first. If this is not the required card, then a search is * performed starting with the first keyword in the FitsChan. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a string holding the keyword name. * method * Pointer to string holding name of calling method. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if a card was found refering to the given * keyword. Otherwise zero is returned. * Notes: * - If a NULL pointer is supplied for "name" then the current card * is left unchanged. * - The current card is set to NULL (end-of-file) if no card can be * found for the supplied keyword. */ /* Local Variables: */ int ret; /* Was a card found? */ /* Check the global status, and supplied keyword name. */ if( !astOK || !name ) return 0; /* Indicate that no card has been found yet. */ ret = 0; /* The required card is very often the next card in the FitsChan, so check the next card, and only search the entire FitsChan if the check fails. */ MoveCard( this, 1, method, class, status ); if( !astFitsEof( this ) && !Ustrncmp( CardName( this, status ), name, FITSNAMLEN, status ) ){ ret = 1; /* If the next card is not the required card, rewind the FitsChan back to the first card. */ } else { astClearCard( this ); /* Attempt to find the supplied keyword, searching from the first card. */ ret = FindKeyCard( this, name, method, class, status ); } /* Return. */ return ret; } static void SetAlgCode( char *buf, const char *algcode, int *status ){ /* * Name: * SetAlgCode * Purpose: * Create a non-linear CTYPE string from a system code and an algorithm * code. * Type: * Private function. * Synopsis: * void SetAlgCode( char *buf, const char *algcode, int *status ) * Class Membership: * FitsChan * Description: * FITS-WCS paper 1 says that non-linear axes must have a CTYPE of the * form "4-3" (e.g. "VRAD-TAB"). This function handles the truncation * of long system codes, or the padding of short system codes. * Parameters: * buf * A buffer in which is stored the system code. Modified on exit to * hold the combined CTYPE value. It should have a length long * enough to hold the system code and the algorithm code. * algcode * Pointer to a string holding the algorithm code (with a leading * "-", e.g. "-TAB"). * status * Pointer to the inherited status variable. */ /* Local Variables: */ int nc; /* Check inherited status */ if( !astOK ) return; /* Pad the supplied string to at least 4 characters using "-" characters. */ nc = strlen( buf ); while( nc < 4 ) buf[ nc++ ] = '-'; /* Insert the null-terminated code at position 4. */ strcpy( buf + 4, algcode ); } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SetAttrib( AstObject *this, const char *setting ) * Class Membership: * FitsChan member function (over-rides the astSetAttrib protected * method inherited from the Channel class). * Description: * This function assigns an attribute value for a FitsChan, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the FitsChan. * setting * Pointer to a null-terminated string specifying the new attribute * value. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ const char *class; /* Object class */ int ival; /* Integer attribute value */ int len; /* Length of setting string */ int nc; /* Number of characters read by astSscanf */ int warn; /* Offset of Warnings string */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* Obtain the object class. */ class = astGetClass( this ); /* Card. */ /* ----- */ if ( nc = 0, ( 1 == astSscanf( setting, "card= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetCard( this, ival ); /* Encoding. */ /* --------- */ } else if( nc = 0, ( 0 == astSscanf( setting, "encoding=%n%*[^\n]%n", &ival, &nc ) ) && ( nc >= len ) ) { nc = ChrLen( setting + ival, status ); if( !Ustrncmp( setting + ival, NATIVE_STRING, nc, status ) ){ astSetEncoding( this, NATIVE_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSPC_STRING, nc, status ) ){ astSetEncoding( this, FITSPC_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSPC_STRING2, nc, status ) ){ astSetEncoding( this, FITSPC_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSWCS_STRING, nc, status ) ){ astSetEncoding( this, FITSWCS_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSWCS_STRING2, nc, status ) ){ astSetEncoding( this, FITSWCS_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSIRAF_STRING, nc, status ) ){ astSetEncoding( this, FITSIRAF_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSIRAF_STRING2, nc, status ) ){ astSetEncoding( this, FITSIRAF_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSAIPS_STRING, nc, status ) ){ astSetEncoding( this, FITSAIPS_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSAIPS_STRING2, nc, status ) ){ astSetEncoding( this, FITSAIPS_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSAIPSPP_STRING, nc, status ) ){ astSetEncoding( this, FITSAIPSPP_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSAIPSPP_STRING2, nc, status ) ){ astSetEncoding( this, FITSAIPSPP_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSCLASS_STRING, nc, status ) ){ astSetEncoding( this, FITSCLASS_ENCODING ); } else if( !Ustrncmp( setting + ival, FITSCLASS_STRING2, nc, status ) ){ astSetEncoding( this, FITSCLASS_ENCODING ); } else if( !Ustrncmp( setting + ival, DSS_STRING, nc, status ) ){ astSetEncoding( this, DSS_ENCODING ); } else { astError( AST__BADAT, "astSet(%s): Unknown encoding system '%s' " "requested for a %s.", status, class, setting + ival, class ); } /* FitsDigits. */ /* ----------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "fitsdigits= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetFitsDigits( this, ival ); /* CDMatrix */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "cdmatrix= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetCDMatrix( this, ival ); /* DefB1950 */ /* -------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "defb1950= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetDefB1950( this, ival ); /* TabOK */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "tabok= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetTabOK( this, ival ); /* CarLin */ /* ------ */ } else if ( nc = 0, ( 1 == astSscanf( setting, "carlin= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetCarLin( this, ival ); /* PolyTan */ /* ------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "polytan= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetPolyTan( this, ival ); /* Iwc */ /* --- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "iwc= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetIwc( this, ival ); /* Clean */ /* ----- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "clean= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetClean( this, ival ); /* Warnings. */ /* -------- */ } else if ( nc = 0, ( 0 == astSscanf( setting, "warnings=%n%*[^\n]%n", &warn, &nc ) ) && ( nc >= len ) ) { astSetWarnings( this, setting + warn ); /* Define a macro to see if the setting string matches any of the read-only attributes of this class. */ #define MATCH(attrib) \ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ ( nc >= len ) ) /* If the attribute was not recognised, use this macro to report an error if a read-only attribute has been specified. */ } else if ( MATCH( "ncard" ) || MATCH( "cardtype" ) || MATCH( "cardcomm" ) || MATCH( "cardname" ) || MATCH( "nkey" ) || MATCH( "allwarnings" ) ){ astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, setting, astGetClass( this ) ); astError( AST__NOWRT, "This is a read-only attribute." , status); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static void SetCard( AstFitsChan *this, int icard, int *status ){ /* *+ * Name: * astSetCard * Purpose: * Set the value of the Card attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * void astSetCard( AstFitsChan *this, int icard ) * Class Membership: * FitsChan method. * Description: * This function sets the value of the Card attribute for the supplied * FitsChan. This is the index of the next card to be read from the * FitsChan. If a value of 1 or less is supplied, the first card in * the FitsChan will be read next. If a value greater than the number * of cards in the FitsChan is supplied, the FitsChan will be left in an * "end-of-file" condition, in which no further read operations can be * performed. * Parameters: * this * Pointer to the FitsChan. * icard * The index of the next card to read. * Notes: * - This function attempts to execute even if an error has occurred. *- */ /* Check the supplied object. */ if ( !this ) return; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Rewind the FitsChan. */ astClearCard( this ); /* Move forward the requested number of cards. */ MoveCard( this, icard - 1, "astSetCard", astGetClass( this ), status ); /* Return. */ return; } static void SetItem( double ****item, int i, int jm, char s, double val, int *status ){ /* * Name: * SetItem * Purpose: * Store a value for a axis keyword value in a FitStore structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SetItem( double ****item, int i, int jm, char s, double val, int *status ) * Class Membership: * FitsChan member function. * Description: * The supplied keyword value is stored in the specified array, * at a position indicated by the axis and co-ordinate version. * The array is created or extended as necessary to make room for * the new value. Any old value is over-written. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->crval) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword values. These arrays of keyword values have * one element for every pixel axis (j) or projection parameter (m). * i * The zero based intermediate axis index in the range 0 to 98. Set * this to zero for keywords (e.g. CRPIX) which are not indexed by * intermediate axis number. * jm * The zero based pixel axis index (in the range 0 to 98) or parameter * index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for * keywords (e.g. CRVAL) which are not indexed by either pixel axis or * parameter number. * val * The keyword value to store. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int el; /* Array index */ int nel; /* Number of elements in array */ int si; /* Integer co-ordinate version index */ /* Check the inherited status. */ if( !astOK ) return; /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "SetItem(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); /* Check the intermediate axis index is within range. */ } else if( i < 0 || i > 98 ) { astError( AST__INTER, "SetItem(fitschan): AST internal error; " "intermediate axis index %d is invalid.", status, i ); /* Check the pixel axis or parameter index is within range. */ } else if( jm < 0 || jm > 99 ) { astError( AST__INTER, "SetItem(fitschan): AST internal error; " "pixel axis or parameter index %d is invalid.", status, jm ); /* Otherwise proceed... */ } else { /* Store the current number of coordinate versions in the supplied array */ nel = astSizeOf( (void *) *item )/sizeof(double **); /* If required, extend the array located by the supplied pointer so that it is long enough to hold the specified co-ordinate version. */ if( nel < si + 1 ){ *item = (double ***) astGrow( (void *) *item, si + 1, sizeof(double **) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold NULL. Note, astGrow may add more elements to the array than is actually needed, so use the actual current size of the array as implied by astSize rather than the index si. */ for( el = nel; el < astSizeOf( (void *) *item )/sizeof(double **); el++ ) (*item)[el] = NULL; } } /* If the above went OK... */ if( astOK ){ /* Store the currrent number of intermediate axes in the supplied array */ nel = astSizeOf( (void *) (*item)[si] )/sizeof(double *); /* If required, extend the array so that it is long enough to hold the specified intermediate axis. */ if( nel < i + 1 ){ (*item)[si] = (double **) astGrow( (void *) (*item)[si], i + 1, sizeof(double *) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold NULL. */ for( el = nel; el < astSizeOf( (void *) (*item)[si] )/sizeof(double *); el++ ) (*item)[si][el] = NULL; } } /* If the above went OK... */ if( astOK ){ /* Store the current number of pixel axis or parameter values in the array. */ nel = astSizeOf( (void *) (*item)[si][i] )/sizeof(double); /* If required, extend the array so that it is long enough to hold the specified axis. */ if( nel < jm + 1 ){ (*item)[si][i] = (double *) astGrow( (void *) (*item)[si][i], jm + 1, sizeof(double) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold AST__BAD. */ for( el = nel; el < astSizeOf( (void *) (*item)[si][i] )/sizeof(double); el++ ) (*item)[si][i][el] = AST__BAD; } } /* If the above went OK, store the supplied keyword value. */ if( astOK ) (*item)[si][i][jm] = val; } } } } static void SetItemC( char *****item, int i, int jm, char s, const char *val, int *status ){ /* * Name: * SetItemC * Purpose: * Store a character string for an axis keyword value in a FitStore * structure. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SetItemC( char *****item, int i, int jm, char s, const char *val, * int *status ) * Class Membership: * FitsChan member function. * Description: * The supplied keyword string value is stored in the specified array, * at a position indicated by the axis and co-ordinate version. * The array is created or extended as necessary to make room for * the new value. Any old value is over-written. * Parameters: * item * The address of the pointer within the FitsStore which locates the * arrays of values for the required keyword (eg &(store->ctype) ). * The array located by the supplied pointer contains a vector of * pointers. Each of these pointers is associated with a particular * co-ordinate version (s), and locates an array of pointers for that * co-ordinate version. Each such array of pointers has an element * for each intermediate axis number (i), and the pointer locates an * array of axis keyword string pointers. These arrays of keyword * string pointers have one element for every pixel axis (j) or * projection parameter (m). * i * The zero based intermediate axis index in the range 0 to 98. Set * this to zero for keywords (e.g. RADESYS) which are not indexed by * intermediate axis number. * jm * The zero based pixel axis index (in the range 0 to 98) or parameter * index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for * keywords (e.g. CTYPE) which are not indexed by either pixel axis or * parameter number. * val * The keyword string value to store. A copy of the supplied string * is taken. * status * Pointer to the inherited status variable. */ /* Local Variables: */ int el; /* Array index */ int nel; /* Number of elements in array */ int si; /* Integer co-ordinate version index */ /* Check the inherited status and the supplied pointer. */ if( !astOK || !val ) return; /* Convert the character co-ordinate version into an integer index, and check it is within range. The primary axis description (s=' ') is given index zero. 'A' is 1, 'B' is 2, etc. */ if( s == ' ' ) { si = 0; } else if( islower(s) ){ si = (int) ( s - 'a' ) + 1; } else { si = (int) ( s - 'A' ) + 1; } if( si < 0 || si > 26 ) { astError( AST__INTER, "SetItemC(fitschan): AST internal error; " "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s ); /* Check the intermediate axis index is within range. */ } else if( i < 0 || i > 98 ) { astError( AST__INTER, "SetItemC(fitschan): AST internal error; " "intermediate axis index %d is invalid.", status, i ); /* Check the pixel axis or parameter index is within range. */ } else if( jm < 0 || jm > 99 ) { astError( AST__INTER, "SetItemC(fitschan): AST internal error; " "pixel axis or parameter index %d is invalid.", status, jm ); /* Otherwise proceed... */ } else { /* Store the current number of coordinate versions in the supplied array */ nel = astSizeOf( (void *) *item )/sizeof(char ***); /* If required, extend the array located by the supplied pointer so that it is long enough to hold the specified co-ordinate version. */ if( nel < si + 1 ){ *item = (char ****) astGrow( (void *) *item, si + 1, sizeof(char ***) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold NULL. Note, astGrow may add more elements to the array than is actually needed, so use the actual current size of the array as implied by astSize rather than the index si. */ for( el = nel; el < astSizeOf( (void *) *item )/sizeof(char ***); el++ ) (*item)[el] = NULL; } } /* If the above went OK... */ if( astOK ){ /* Store the currrent number of intermediate axes in the supplied array */ nel = astSizeOf( (void *) (*item)[si] )/sizeof(char **); /* If required, extend the array so that it is long enough to hold the specified intermediate axis. */ if( nel < i + 1 ){ (*item)[si] = (char ***) astGrow( (void *) (*item)[si], i + 1, sizeof(char **) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold NULL. */ for( el = nel; el < astSizeOf( (void *) (*item)[si] )/sizeof(char **); el++ ) (*item)[si][el] = NULL; } } /* If the above went OK... */ if( astOK ){ /* Store the current number of pixel axis or parameter values in the array. */ nel = astSizeOf( (void *) (*item)[si][i] )/sizeof(char *); /* If required, extend the array so that it is long enough to hold the specified axis. */ if( nel < jm + 1 ){ (*item)[si][i] = (char **) astGrow( (void *) (*item)[si][i], jm + 1, sizeof(char *) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the new elements to hold NULL. */ for( el = nel; el < astSizeOf( (void *) (*item)[si][i] )/sizeof(char *); el++ ) (*item)[si][i][el] = NULL; } } /* If the above went OK... */ if( astOK ){ /* Store a copy of the supplied string, using any pre-allocated memory. */ (*item)[si][i][jm] = (char *) astStore( (void *) (*item)[si][i][jm], (void *) val, strlen( val ) + 1 ); } } } } } static void SetSourceFile( AstChannel *this_channel, const char *source_file, int *status ) { /* * Name: * SetSourceFile * Purpose: * Set a new value for the SourceFile attribute. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SetSourceFile( AstChannel *this, const char *source_file, * int *status ) * Class Membership: * FitsChan member function (over-rides the astSetSourceFile * method inherited from the Channel class). * Description: * This function stores the supplied string as the new value for the * SourceFile attribute. In addition, it also attempts to open the * file, read FITS headers from it and append them to the end of the * FitsChan. It then closes the SourceFile. * Parameters: * this * Pointer to the FitsChan. * source_file * The new attribute value. Should be the path to an existing text * file, holding FITS headers (one per line) * status * Inherited status pointer. */ /* Local Constants: */ #define ERRBUF_LEN 80 /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ FILE *fd; /* Descriptor for source file */ char *errstat; /* Pointer for system error message */ char card[ AST__FITSCHAN_FITSCARDLEN + 2 ]; /* Buffer for source line */ char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Invoke the parent astSetSourceFile method to store the supplied string in the Channel structure. */ (*parent_setsourcefile)( this_channel, source_file, status ); /* Attempt to open the file. */ fd = NULL; if( astOK ) { fd = fopen( source_file, "r" ); if( !fd ) { if ( errno ) { #if HAVE_STRERROR_R strerror_r( errno, errbuf, ERRBUF_LEN ); errstat = errbuf; #else errstat = strerror( errno ); #endif astError( AST__RDERR, "astSetSourceFile(%s): Failed to open input " "SourceFile '%s' - %s.", status, astGetClass( this ), source_file, errstat ); } else { astError( AST__RDERR, "astSetSourceFile(%s): Failed to open input " "SourceFile '%s'.", status, astGetClass( this ), source_file ); } } } /* Move the FitsChan to EOF */ astSetCard( this, INT_MAX ); /* Read each line from the file, remove trailing space, and append to the FitsChan. */ while( astOK && fgets( card, AST__FITSCHAN_FITSCARDLEN + 2, fd ) ) { card[ astChrLen( card ) ] = 0; astPutFits( this, card, 0 ); } /* Close the source file. */ if( fd ) fclose( fd ); } static void SetTableSource( AstFitsChan *this, void (*tabsource)( void ), void (*tabsource_wrap)( void (*)( void ), AstFitsChan *, const char *, int, int, int * ), int *status ){ /* *+ * Name: * astSetTableSource * Purpose: * Register source and wrapper function for accessing tables in FITS files. * Type: * Protected function. * Synopsis: * #include "fitschan.h" * void astSetTableSource( AstFitsChan *this, * void (*tabsource)( void ), * void (*tabsource_wrap)( void (*)( void ), * AstFitsChan *, const char *, * int, int, int * ), * int *status ) * Class Membership: * FitsChan member function. * Description: * This function registers a table source function and its wrapper. A * wrapper function exists to adapt the API of the table source * function to the needs of different languages. The wrapper is called * from the FitsChan code. The wrapper then adjusts the arguments as * required and then calls the actualy table source function. * Parameters: * this * Pointer to the FitsChan. * tabsource * Pointer to the table source function. The API for this function * will depend on the language, and so is cast to void here. It * should be cast to the required form within the wrapper function. * tabsource_wrap * The wrapper function. *- */ /* Local Variables: */ /* Check the global error status. */ if ( !astOK ) return; this->tabsource = tabsource; this->tabsource_wrap = tabsource_wrap; } static void SetValue( AstFitsChan *this, const char *keyname, void *value, int type, const char *comment, int *status ){ /* * Name: * SetValue * Purpose: * Save a FITS keyword value, over-writing any existing keyword value. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SetValue( AstFitsChan *this, char *keyname, void *value, * int type, const char *comment, int *status ) * Class Membership: * FitsChan * Description: * This function saves a keyword value as a card in the supplied * FitsChan. Comment cards are always inserted in-front of the current * card. If the keyword is not a comment card, any existing value * for the keyword is over-written with the new value (even if it is * marked as having been read). Otherwise, (i.e. if it is not a comment * card, and no previous value exists) it is inserted in front * of the current card. * Parameters: * this * A pointer to the FitsChan. * keyname * A pointer to a string holding the keyword name. * value * A pointer to a buffer holding the keyword value. For strings, * the buffer should hold a pointer to the character string. * type * The FITS data type of the supplied keyword value. * comment * A comment to store with the keyword. * status * Pointer to the inherited status variable. * Notes: * - Nothing is stored if a NULL pointer is supplied for "value". * - If the keyword has a value of AST__BAD then nothing is stored, * and an error is reported. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ FitsCard *card; /* Pointer to original current card */ const char *class; /* Class name to include in error messages */ const char *method; /* Method name to include in error messages */ int newcard; /* Has the original current card been deleted? */ int old_ignore_used; /* Original setting of external ignore_used variable */ int stored; /* Has the keyword been stored? */ /* Check the status and supplied value pointer. */ if( !astOK || !value ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Set up the method and class names for inclusion in error mesages. */ method = "astWrite"; class = astGetClass( this ); /* Comment card are always inserted in-front of the current card. */ if ( type == AST__COMMENT ) { SetFits( this, keyname, value, type, comment, 0, status ); /* Otherwise... */ } else { /* Report an error if a bad value is stored for a keyword. */ if( type == AST__FLOAT ){ if( *( (double *) value ) == AST__BAD && astOK ) { astError( AST__BDFTS, "%s(%s): The required FITS keyword " "\"%s\" is indeterminate.", status, method, class, keyname ); } } /* Save a pointer to the current card. */ card = (FitsCard *) this->card; /* Indicate that we should not skip over cards marked as having been read. */ old_ignore_used = ignore_used; ignore_used = 0; /* Indicate that we have not yet stored the keyword value. */ stored = 0; /* Attempt to find a card refering to the supplied keyword. If one is found, it becomes the current card. */ if( SearchCard( this, keyname, "astWrite", astGetClass( this ), status ) ){ /* If the card which was current on entry to this function will be over-written, we will need to take account of this when re-instating the original current card. Make a note of this. */ newcard = ( card == (FitsCard *) this->card ); /* Replace the current card with a card holding the supplied information. */ SetFits( this, keyname, value, type, comment, 1, status ); stored = 1; /* If we have just replaced the original current card, back up a card so that the replacement card becomes the current card. */ if( newcard ) { MoveCard( this, -1, "astWrite", astGetClass( this ), status ); /* Otherwise, re-instate the original current card. */ } else { this->card = (void *) card; } } /* If the keyword has not yet been stored (i.e. if it did not exist in the FitsChan), re-instate the original current card and insert the new card before the original current card, leaving the current card unchanged. */ if( !stored ) { this->card = (void *) card; SetFits( this, keyname, value, type, comment, 0, status ); } /* Re-instate the original flag indicating if cards marked as having been read should be skipped over. */ ignore_used = old_ignore_used; } } static void Shpc1( double xmin, double xmax, int n, double *d, double *w, int *status ){ /* * Name: * Shpc1 * Purpose: * Modifies a one-dimensional polynomial to scale the polynomial argument. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void Shpc1( double xmin, double xmax, int n, double *d, double *w, * int *status ) * Description: * Given the coefficients of a one-dimensional polynomial P(u) defined on a * unit interval (i.e. -1 <= u <= +1 ), find the coefficients of another * one-dimensional polynomial Q(x) where: * * Q(x) = P(u) * u = ( 2*x - ( xmax + xmin ) ) / ( xmax - xmin ) * * That is, u is a scaled version of x, such that the unit interval in u * maps onto (xmin:xmax) in x. * Parameters: * xmin * X value corresponding to u = -1 * xmax * X value corresponding to u = +1 * n * One more than the maximum power of u within P. * d * An array of n elements supplied holding the coefficients of P such * that the coefficient of (u^i) is held in element (i). * w * An array of n elements returned holding the coefficients of Q such * that the coefficient of (x^i) is held in element (i). * status * Pointer to the inherited status variable. * Notes: * - Vaguely inspired by the Numerical Recipes routine "pcshft". But the * original had bugs, so I wrote this new version from first principles. */ /* Local Variables: */ double b; double a; int j; int i; /* Check inherited status */ if( !astOK ) return; /* Get the scale and shift terms so that u = a*x + b */ a = 2.0/( xmax - xmin ); b = ( xmin + xmax )/( xmin - xmax ); /* Initialise the returned coeffs */ for( i = 0; i < n; i++ ) w[ i ] = 0.0; /* The supplied Polynomial is P(u) = d0 + d1*u + d2*u^2 + ... = d0 + u*( d1 + u*( d2 + ... u*( d{n-1} ) ) ) . . . . . (1) = d0 + (a*x+b)*( d1 + (a*x+b)*( d2 + ... (a*x+b)*( d[n-1] ) ) ) The inner-most parenthesised expression is a polynomial of order zero (a constant - d[n-1]). Store the coefficients of this zeroth order polynomial in the returned array. The "w" array is used to hold the coefficients of Q, i.e. coefficients of powers of "x", not "u", but since the inner-most polynomial is a constant, it makes no difference (x^0 == u^0 == 1). */ w[ 0 ] = d[ n - 1 ]; /* Now loop through each remaining level of parenthetic nesting in (1). At each level, the parenthesised expression represents a polynomial of order "i". At the end of each pass though this loop, the returned array "w" holds the coefficients of this "i"th order polynomial. So on the last loop, i = n-1, "w" holds the required coefficients of Q. */ for( i = 1; i < n; i++ ) { /* If "R" is the polynomial at the "i-1"th level of nesting (the coefficiemts of which are currently held in "w"), and "S" is the polynomial at the "i"th level of nesting, we can see from (1) that: S = d[ n - 1 - i ] + u*R Substituting for "u", this becomes S = d[ n - 1 - i ] + ( a*x + b )*R = d[ n - 1 - i ] + a*R*x + b*R Looking at each of these three terms in reverse order: 1) The "b*R" term is implemented by simply scaling the current contents of the "w" array by "b"; in the "a*R*x" term. 2) In "a*R*x", the effect of multiplying by "x" is to move the existing coefficients in "w" up one element. We then multiply the shifted coefficients by "a" and add them onto the coefficients produced at step 1) above. We know that "w" still contains the initial zeros at indices higher than "i" so we only need to scale the bottom "i" elements. We do not do the zeroth term in this loop since there is no lower term to shift up into it. */ for( j = i; j > 0; j-- ){ w[ j ] = b*w[ j ] + a*w[ j - 1 ]; } /* Now do the zeroth term. Scale the existing zeroth term by "b" as required by step 1) and add on the first term, the constant "d[ n - 1 - i ]". Step 2) is a no-op, since in effect the value of "w[-1]" is zero. */ w[ 0 ] = d[ n - i - 1 ] + b*w[ 0 ]; } } static void ShowFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astShowFits f AST_SHOWFITS * Purpose: * Display the contents of a FitsChan on standard output. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astShowFits( AstFitsChan *this ) f CALL AST_SHOWFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * formats and displays all the cards in a FitsChan on standard output. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ char card[ AST__FITSCHAN_FITSCARDLEN + 1]; /* Buffer for header card */ int icard; /* Current card index on entry */ int old_ignore_used; /* Original value of external variable ignore_used */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Store the current card index. */ icard = astGetCard( this ); /* Indicate that cards which have been read into an AST object should skipped over by the functions which navigate the linked list of cards. */ old_ignore_used = ignore_used; ignore_used = 1; /* Ensure that the first card in the FitsChan will be the next one to be read. */ astSetCard( this, 1 ); /* Loop round obtaining and writing out each card, until all cards have been processed. */ while( !astFitsEof( this ) && astOK ){ /* Get the current card, and display it. The call to astFindFits increments the current card. */ if( astFindFits( this, "%f", card, 1 ) ) printf( "%s\n", card ); } /* Re-instate the original flag indicating if cards marked as having been read should be skipped over. */ ignore_used = old_ignore_used; /* Set the current card index back to what it was on entry. */ astSetCard( this, icard ); } static int Similar( const char *str1, const char *str2, int *status ){ /* * Name: * Similar * Purpose: * Are two string effectively the same to human readers? * Type: * Private function. * Synopsis: * #include "fitschan.h" * void Similar( const char *str1, const char *str2, int *status ) * Class Membership: * FitsChan * Description: * This function returns a non-zero value if the two supplied strings * are equivalent to a human reader. This is assumed to be the case if * the strings are equal apart from leading and trailing white space, * multiple embedded space, and case. * Parameters: * str1 * The first string * str2 * The second string * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if the two supplied strings are equivalent, and zero * otherwise. */ /* Local Variables: */ const char *ea; /* Pointer to end of string a */ const char *eb; /* Pointer to end of string b */ const char *a; /* Pointer to next character in string a */ const char *b; /* Pointer to next character in string b */ int result; /* Are the two strings equivalent? */ int ss; /* Skip subsequent spaces? */ /* Initialise */ result = 0; /* Check the status and supplied value pointer. */ if( !astOK ) return result; /* Initialise pointers into the two strings. */ a = str1; b = str2; /* Get a pointer to the character following the last non-blank character in each string. */ ea = a + ChrLen( a, status ) - 1; eb = b + ChrLen( b, status ) - 1; /* Set a flag indicating that spaces before the next non-blank character should be ignored. */ ss = 1; /* Compare the strings. */ while( 1 ){ /* Move on to the next significant character in both strings. */ while( a < ea && *a == ' ' && ss ) a++; while( b < eb && *b == ' ' && ss ) b++; /* If one string has been exhausted but the other has not, the strings are not equivalent. */ if( ( a < ea && b == eb ) || ( a == ea && b < eb ) ) { break; /* If both strings have been exhausted simultaneously, the strings are equivalent. */ } else if( b == eb && a == ea ) { result = 1; break; /* If neither string has been exhausted, compare the current character for equality, ignoring case. Break if they are different. */ } else if( tolower( *a ) != tolower( *b ) ){ break; /* If the two characters are both spaces, indicate that subsequent spaces should be skipped. */ } else if( *a == ' ' ) { ss = 1; /* If the two characters are not spaces, indicate that subsequent spaces should not be skipped. */ } else { ss = 0; } /* Move on to the next characters. */ a++; b++; } /* Return the result. */ return result; } static void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) { /* * Name: * SinkWrap * Purpose: * Wrapper function to invoke a C FitsChan sink function. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) * Class Membership: * FitsChan member function. * Description: * This function invokes the sink function whose pointer is * supplied in order to write an output line to an external data * store. * Parameters: * sink * Pointer to a sink function, whose single parameter is a * pointer to a const, null-terminated string containing the * text to be written, and which returns void. This is the form * of FitsChan sink function employed by the C language interface * to the AST library. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if ( !astOK ) return; /* Invoke the sink function. */ ( *sink )( line ); } static AstMapping *SIPMapping( double *dim, FitsStore *store, char s, int naxes, const char *method, const char *class, int *status ){ /* * Name: * SIPMapping * Purpose: * Create a Mapping descriping "-SIP" (Spitzer) distortion. * Type: * Private function. * Synopsis: * AstMapping *SIPMapping( double *dim, FitsStore *store, char s, int naxes, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function uses the values in the supplied FitsStore to create a * Mapping which implements the "-SIP" distortion code. This is the * code used by the Spitzer project and is described in: * * http://irsa.ipac.caltech.edu/data/SPITZER/docs/files/spitzer/shupeADASS.pdf * * SIP distortion can only be applied to axes 0 and 1. Other axes are * passed unchanged by the returned Mapping. * Parameters: * dim * The dimensions of the array in pixels. AST__BAD is stored for * each value if dimensions are not known. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstMapping *ret; /* Pointer to the returned Mapping */ AstPolyMap *pmap; /* PolyMap describing the distortion */ AstPolyMap *pmap2; /* New PolyMap describing the distortion */ double ****item; /* Address of FitsStore item to use */ double *c; /* Pointer to start of coefficient description */ double *coeff_f; /* Array of coeffs. for forward transformation */ double *coeff_i; /* Array of coeffs. for inverse transformation */ double cof; /* Coefficient value */ double lbnd[ 2 ]; /* Lower bounds of fitted region */ double ubnd[ 2 ]; /* Upper bounds of fitted region */ int def; /* Is transformation defined? */ int iin; /* Input (u or v) index */ int iout; /* Output (U or V) index */ int ncoeff_f; /* No. of coeffs. for forward transformation */ int ncoeff_i; /* No. of coeffs. for inverse transformation */ int p; /* Power of u or U */ int pmax; /* Max power of u or U */ int q; /* Power of v or V */ int qmax; /* Max power of v or V */ /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Store coefficients of the forward transformation: ================================================ */ /* Indicate that we have as yet no coefficients for the forward polynomials. */ ncoeff_f = 0; /* Indicate that we do not yet have any evidence that the forward transformation is defined. */ def = 0; /* Allocate workspace to hold descriptions of (initially) 20 coefficients used within the forward polynomials. */ coeff_f = astMalloc( sizeof( double )*20 ); /* Store the coefficients of the polynomial which produces each output axis (U or V) in turn. */ for( iout = 0; iout < 2; iout++ ){ /* Get a pointer to the FitsStore item holding the values defining this output. */ item = ( iout == 0 ) ? &(store->asip) : &(store->bsip); /* Get the largest powers used of u and v. */ pmax = GetMaxI( item, s, status ); qmax = GetMaxJM( item, s, status ); /* Loop round all combination of powers. */ for( p = 0; p <= pmax; p++ ){ for( q = 0; q <= qmax; q++ ){ /* Get the polynomial coefficient for this combination of powers. */ cof = GetItem( item, p, q, s, NULL, method, class, status ); /* If there is no coefficient for this combination of powers, use a value of zero. Otherwise indicate we have found at least one coefficient. */ if( cof == AST__BAD ) { cof = 0.0; } else { def = 1; } /* The distortion polynomial gives a correction to be added on to the input value. On the other hand, the returned Mapping is a direct transformation from input to output. Therefore increment the coefficient value by 1 for the term which corresponds to the current output axis. */ if( p == ( 1 - iout ) && q == iout ) cof += 1.0; /* If the coefficient is not zero, store it in the array of coefficient descriptions. */ if( cof != 0.0 ) { /* Increment the number of coefficients for the forward polynomials. */ ncoeff_f++; /* Ensure the "coeff_f" array is large enough to hold the new coefficient. */ coeff_f = astGrow( coeff_f, sizeof( double )*4, ncoeff_f ); if( astOK ) { /* Store it. Each coefficient is described by 4 values (since we have 2 inputs to the Mapping). The first is the coefficient value, the second is the (1-based) index of the output to which the coefficient relates. The next is the power of input 0, and the last one is the power of input 1. */ c = coeff_f + 4*( ncoeff_f - 1 ); c[ 0 ] = cof; c[ 1 ] = iout + 1; c[ 2 ] = p; c[ 3 ] = q; } } } } } /* If no coefficients were supplied in the FitsStore, the forward transformation is undefined. */ if( !def ) ncoeff_f = 0; /* Store coefficients of the inverse transformation: ================================================ */ /* Indicate that we have as yet no coefficients for the inverse polynomials. */ ncoeff_i = 0; /* Indicate that we do not yet have any evidence that the forward transformation is defined. */ def = 0; /* Allocate workspace to hold descriptions of (initially) 20 coefficients used within the inverse polynomials. */ coeff_i = astMalloc( sizeof( double )*20 ); /* Store the coefficients of the polynomial which produces each input axis (u or v) in turn. */ for( iin = 0; iin < 2; iin++ ){ /* Get a pointer to the FitsStore item holding the values defining this output. */ item = ( iin == 0 ) ? &(store->apsip) : &(store->bpsip); /* Get the largest powers used of U and V. */ pmax = GetMaxI( item, s, status ); qmax = GetMaxJM( item, s, status ); /* Loop round all combination of powers. */ for( p = 0; p <= pmax; p++ ){ for( q = 0; q <= qmax; q++ ){ /* Get the polynomial coefficient for this combination of powers. */ cof = GetItem( item, p, q, s, NULL, method, class, status ); /* If there is no coefficient for this combination of powers, use a value of zero. Otherwise indicate we have found at least one coefficient. */ if( cof == AST__BAD ) { cof = 0.0; } else { def = 1; } /* The distortion polynomial gives a correction to be added on to the output value. On the other hand, the returned Mapping is a direct transformation from output to input. Therefore increment the coefficient value by 1 for the term which corresponds to the current input axis. */ if( p == ( 1 - iin ) && q == iin ) cof += 1.0; /* If the coefficient is not zero, store it in the array of coefficient descriptions. */ if( cof != 0.0 ) { /* Increment the number of coefficients for the inverse polynomials. */ ncoeff_i++; /* Ensure the "coeff_i" array is large enough to hold the new coefficient. */ coeff_i = astGrow( coeff_i, sizeof( double )*4, ncoeff_i ); if( astOK ) { /* Store it. Each coefficient is described by 4 values (since we have 2 outputs to the Mapping). The first is the coefficient value, the second is the (1-based) index of the input to which the coefficient relates. The next is the power of output 0, and the last one is the power of output 1. */ c = coeff_i + 4*( ncoeff_i - 1 ); c[ 0 ] = cof; c[ 1 ] = iin + 1; c[ 2 ] = p; c[ 3 ] = q; } } } } } /* If no coefficients were supplied in the FitsStore, the forward transformation is undefined. */ if( !def ) ncoeff_i = 0; /* Create the returned Mapping: ============================ */ /* If neither transformation is defined, create a UnitMap. */ if( ncoeff_f == 0 && ncoeff_i == 0 ){ ret = (AstMapping *) astUnitMap( naxes, "", status ); /* Otherwise, create a PolyMap to describe axes 0 and 1. */ } else { pmap = astPolyMap( 2, 2, ncoeff_f, coeff_f, ncoeff_i, coeff_i, "", status ); /* The inverse transformations supplied within SIP headers are often inaccurate. So replace any existing inverse by sampling the supplied transformation, and fitting a polynomial to the sampled positions. If the fit fails to reach 0.01 pixel accuracy, forget it and rely on the (slower) iterative inverse provided by the PolyMap class. Do the fit over an area three times the size of the image to provide accurate values outside the image.*/ lbnd[ 0 ] = ( dim[ 0 ] != AST__BAD ) ? -dim[ 0 ] : -1000.0; lbnd[ 1 ] = ( dim[ 1 ] != AST__BAD ) ? -dim[ 1 ] : -1000.0; ubnd[ 0 ] = ( dim[ 0 ] != AST__BAD ) ? 2*dim[ 0 ] : 2000.0; ubnd[ 1 ] = ( dim[ 1 ] != AST__BAD ) ? 2*dim[ 1 ] : 2000.0; pmap2 = astPolyTran( pmap, (ncoeff_f == 0), 0.0001, 0.01, 7, lbnd, ubnd ); if( pmap2 ) { (void) astAnnul( pmap ); pmap = pmap2; } else { astSet( pmap, "IterInverse=1,NiterInverse=6,TolInverse=1.0E-8", status ); } /* Add the above Mapping in parallel with a UnitMap which passes any other axes unchanged. */ ret = AddUnitMaps( (AstMapping *) pmap, 0, naxes, status ); pmap = astAnnul( pmap ); } /* Free resources. */ coeff_f = astFree( coeff_f ); coeff_i = astFree( coeff_i ); /* Return the result. */ return ret; } static void SkyPole( AstWcsMap *map2, AstMapping *map3, int ilon, int ilat, int *wperm, char s, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * SkyPole * Purpose: * Put values for FITS keywords LONPOLE and LATPOLE into a FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void SkyPole( AstWcsMap *map2, AstMapping *map3, int ilon, int ilat, * int *wperm, char s, FitsStore *store, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function calculates values for the LONPOLE and LATPOLE FITS * keywords and stores them in the supplied FitsStore. LONPOLE and * LATPOLE are the longitude and latitude of the celestial north pole * in native spherical coordinates. * Parameters: * map2 * Pointer to the Mapping from Intermediate World Coordinates to Native * Spherical Coordinates. * map3 * Pointer to the Mapping from Native Spherical Coordinates to celestial * coordinates. * ilon * Zero-based index of longitude output from "map3". * ilat * Zero-based index of latitude output from "map3". * wperm * Pointer to an array of integers with one element for each axis of * the current Frame. Each element holds the zero-based * index of the FITS-WCS axis (i.e. the value of "i" in the keyword * names "CTYPEi", "CRVALi", etc) which describes the Frame axis. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * store * The FitsStore in which to store the FITS WCS keyword values. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstPointSet *pset1; /* PointSet holding intermediate wcs coords */ AstPointSet *pset2; /* PointSet holding final WCS coords */ double **ptr1; /* Pointer to coordinate data */ double **ptr2; /* Pointer to coordinate data */ double alpha0; /* Long. of fiducial point in standard system */ double alphap; /* Celestial longitude of native north pole */ double deflonpole; /* Default value for lonpole */ double delta0; /* Lat. of fiducial point in standard system */ double latpole; /* Native latitude of celestial north pole */ double lonpole; /* Native longitude of celestial north pole */ double phi0; /* Native longitude at fiducial point */ double theta0; /* Native latitude at fiducial point */ int axlat; /* Index of latitude output from "map2" */ int axlon; /* Index of longitude output from "map2" */ int fits_ilat; /* FITS WCS axis index for latitude axis */ int fits_ilon; /* FITS WCS axis index for longitude axis */ int iax; /* Axis index */ int nax; /* Number of IWC axes */ int nax2; /* Number of WCS axes */ /* Check the inherited status. */ if( !astOK ) return; /* Store the indices of the native longitude and latitude outputs of the WcsMap. */ axlon = astGetWcsAxis( map2, 0 ); axlat = astGetWcsAxis( map2, 1 ); /* Store the indices of the FITS WCS axes for longitude and latitude */ fits_ilon = wperm[ ilon ]; fits_ilat = wperm[ ilat ]; /* To find the longitude and latitude of the celestial north pole in native spherical coordinates, we will transform the coords of the celestial north pole into spherical cords using the inverse of "map2", and if the resulting native spherical coords differ from the default values of LONPOLE and LATPOLE, we store them in the FitsStore. However, for zenithal projections, any value can be used simply by introducing an extra rotation into the (X,Y) projection plane. If values have been set in the WcsMap (as projection parameters PVi_3 and PVi_4 for longitude axis "i") uses them. Otherwise, set the values bad to indicate that the default values should be used. Note, these projection parameters are used for other purposes in a TPN projection. */ lonpole = AST__BAD; latpole = AST__BAD; if( astIsZenithal( map2 ) ) { if( astGetWcsType( map2 ) != AST__TPN ) { lonpole = astTestPV( map2, axlon, 3 ) ? astGetPV( map2, axlon, 3 ) : AST__BAD; latpole = astTestPV( map2, axlon, 4 ) ? astGetPV( map2, axlon, 4 ) : AST__BAD; } /* For non-zenithal projections, do the full calculation. */ } else { /* Allocate resources. */ nax = astGetNin( map2 ); pset1 = astPointSet( 1, nax, "", status ); ptr1 = astGetPoints( pset1 ); nax2 = astGetNout( map3 ); pset2 = astPointSet( 1, nax2, "", status ); ptr2 = astGetPoints( pset2 ); if( astOK ) { /* Calculate the longitude and latitude of the celestial north pole in native spherical coordinates (using the inverse of map3). These values correspond to the LONPOLE and LATPOLE keywords. */ for( iax = 0; iax < nax2; iax++ ) ptr2[ iax ][ 0 ] = 0.0; ptr2[ ilat ][ 0 ] = AST__DPIBY2; (void) astTransform( map3, pset2, 0, pset1 ); /* Retrieve the latitude and longitude (in the standard system) of the fiducial point (i.e. CRVAL), in radians. */ delta0 = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status ); if( delta0 == AST__BAD ) delta0 = 0.0; delta0 *= AST__DD2R; alpha0 = GetItem( &(store->crval), fits_ilon, 0, s, NULL, method, class, status ); if( alpha0 == AST__BAD ) alpha0 = 0.0; alpha0 *= AST__DD2R; /* The default value of the LATPOLE is defined by equation 8 of FITS-WCS paper II (taking the +ve signs). Find this value. */ if( WcsNatPole( NULL, map2, alpha0, delta0, 999.0, ptr1[ axlon ], &alphap, &latpole, status ) ){ /* If the default value is defined, compare it to the latitude of the north pole found above. If they are equal use a bad value instead to prevent an explicit keyword from being added to the FitsChan. */ if( EQUALANG( ptr1[ axlat ][ 0 ], latpole ) ) { latpole = AST__BAD; } else { latpole = ptr1[ axlat ][ 0 ]; } /* If the default value is not defined, always store an explicit LATPOLE value. */ } else { latpole = ptr1[ axlat ][ 0 ]; } /* The default LONPOLE value is zero if the celestial latitude at the fiducial point is greater than or equal to the native latitude at the fiducial point. Otherwise, the default is (+ or -) 180 degrees. If LONPOLE takes the default value, replace it with AST__BAD to prevent an explicit keyword being stored in the FitsChan. */ GetFiducialNSC( map2, &phi0, &theta0, status ); lonpole = palDranrm( ptr1[ axlon ][ 0 ] ); if( delta0 >= theta0 ){ deflonpole = 0.0; } else { deflonpole = AST__DPI; } if( EQUALANG( lonpole, deflonpole ) ) lonpole = AST__BAD; } /* Convert from radians to degrees. */ if( lonpole != AST__BAD ) lonpole *= AST__DR2D; if( latpole != AST__BAD ) latpole *= AST__DR2D; /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); } /* Store these values. */ SetItem( &(store->lonpole), 0, 0, s, lonpole, status ); SetItem( &(store->latpole), 0, 0, s, latpole, status ); /* FITS-WCS paper 2 recommends putting a copy of LONPOLE and LATPOLE in projection parameters 3 and 4 associated with the longitude axis. Only do this if the projection is not TPN (since this projection uses these parameters for other purposes). */ if( astGetWcsType( map2 ) != AST__TPN ) { SetItem( &(store->pv), fits_ilon, 3, s, lonpole, status ); SetItem( &(store->pv), fits_ilon, 4, s, latpole, status ); } } static int SkySys( AstFitsChan *this, AstSkyFrame *skyfrm, int wcstype, int wcsproj, FitsStore *store, int axlon, int axlat, char s, int isoff, const char *method, const char *class, int *status ){ /* * Name: * SkySys * Purpose: * Return FITS-WCS values describing a sky coordinate system. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int SkySys( AstFitsChan *this, AstSkyFrame *skyfrm, int wcstype, * int wcsproj, FitsStore *store, int axlon, int axlat, char s, * int isoff, const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function sets values for the following FITS-WCS keywords * within the supplied FitsStore structure: CTYPE, CNAME, RADESYS, EQUINOX, * MJDOBS, CUNIT, OBSGEO-X/Y/Z. The values are derived from the supplied * SkyFrame and WcsMap. * Parameters: * this * Pointer to the FitsChan. * skyfrm * A pointer to the SkyFrame to be described. * wcstype * The type of WCS: 0 = TAB, 1 = WcsMap projection. * wcsproj * An identifier for the type of WCS projection to use. Should be * one of the values defined by the WcsMap class. Only used if "wcstype" * is 1. * store * A pointer to the FitsStore structure in which to store the * results. * axlon * The index of the FITS WCS longitude axis (i.e. the value of "i" * in "CTYPEi"). * axlat * The index of the FITS WCS latitude axis (i.e. the value of "i" * in "CTYPEi"). * s * Co-ordinate version character. * isoff * If greater than zero, the description to add to the FitsStore * should describe offset coordinates. If less than zero, the * description to add to the FitsStore should describe absolute * coordinates but should include the SkyRefIs, SkyRef and SkyRefP * attributes. If zero, ignore all offset coordinate info. The * absolute value indicates the nature of the reference point: * 1 == "pole", 2 == "origin", otherwise "ignored". * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * Are the keywords values in the FitsStore usable? */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ char *label; /* Pointer to axis label string */ char attr[20]; /* Buffer for AST attribute name */ char com[80]; /* Buffer for keyword comment */ char lattype[MXCTYPELEN];/* Latitude axis CTYPE value */ char lontype[MXCTYPELEN];/* Longitude axis CTYPE value */ const char *latsym; /* SkyFrame latitude axis symbol */ const char *lonsym; /* SkyFrame longitude axis symbol */ const char *prj_name; /* Pointer to projection name string */ const char *skyref; /* Formatted SkyRef position */ const char *skyrefis; /* SkyRefIs value */ const char *sys; /* Celestal coordinate system */ const char *timesys; /* Timescale specified in FitsChan */ double ep; /* Epoch of observation in required timescale (MJD) */ double ep_tdb; /* Epoch of observation in TDB timescale (MJD) */ double ep_utc; /* Epoch of observation in UTC timescale (MJD) */ double eq; /* Epoch of reference equinox (MJD) */ double geolat; /* Geodetic latitude of observer (radians) */ double geolon; /* Geodetic longitude of observer (radians) */ double h; /* Geodetic altitude of observer (metres) */ double skyref_lat; /* SkyRef latitude value (rads) */ double skyrefp_lat; /* SkyRefP latitude value (rads) */ double skyref_lon; /* SkyRef longitude value (rads) */ double skyrefp_lon; /* SkyRefP longitude value (rads) */ double xyz[3]; /* Geocentric position vector (in m) */ int defdate; /* Can the date keywords be defaulted? */ int i; /* Character count */ int isys; /* Celestial coordinate system */ int latax; /* Index of latitude axis in SkyFrame */ int lonax; /* Index of longitude axis in SkyFrame */ int ok; /* Do axis symbols conform to FITS-WCS CTYPE form? */ int old_ignore_used; /* Original setting of external ignore_used variable */ int ret; /* Returned flag */ /* Check the status. */ if( !astOK ) return 0; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Check we have a SkyFrame. */ if( !astIsASkyFrame( skyfrm ) ) return 0; /* Initialise */ ret = 1; /* Get the equinox, epoch of observation, and system of the SkyFrame. The epoch is in TDB. It is assumed the Equinox is in UTC. */ eq = astGetEquinox( skyfrm ); sys = astGetC( skyfrm, "system" ); ep_tdb = astTestEpoch( skyfrm ) ? astGetEpoch( skyfrm ) : AST__BAD; /* Convert the epoch to UTC. */ ep_utc = TDBConv( ep_tdb, AST__UTC, 1, method, class, status ); /* See if the FitsChan contains a value for the TIMESYS keyword (include previously used cards in the search). If so, and if it is not UTC, convert the epoch to the specified time scale, and store a TIMESYS value in the FitsStore. */ old_ignore_used = ignore_used; ignore_used = 0; if( GetValue( this, "TIMESYS", AST__STRING, (void *) ×ys, 0, 0, method, class, status ) && strcmp( timesys, "UTC" ) ) { ep = TDBConv( ep_tdb, TimeSysToAst( this, timesys, method, class, status ), 1, method, class, status ); SetItemC( &(store->timesys), 0, 0, s, timesys, status ); /* If no TIMESYS keyword was found in the FitsChan, or the timesys was UTC, we use the UTC epoch value found above. In this case no TIMESYS value need be stored in the FitsSTore since UTC is the default for TIMESYS. */ } else { ep = ep_utc; } /* Reinstate the original value for the flag that indicates whether keywords in the FitsChan that have been used previously should be ignored. */ ignore_used = old_ignore_used; /* The MJD-OBS and DATE-OBS keywords default to the epoch of the reference equinox if not supplied. Therefore MJD-OBS and DATE-OBS do not need to be stored in the FitsChan if the epoch of observation is the same as the epoch of the reference equinox. This can avoid producing FITS headers which say unlikely things like DATE-OBS = "01/01/50". Set a flag indicating if MJD-OBS and DATE-OBS can be defaulted. */ defdate = EQUAL( ep_utc, eq ); /* Convert the equinox to a Julian or Besselian epoch. Also get the reference frame and standard system. */ if( !Ustrcmp( sys, "FK4", status ) ){ eq = palEpb( eq ); isys = RADEC; SetItemC( &(store->radesys), 0, 0, s, "FK4", status ); } else if( !Ustrcmp( sys, "FK4_NO_E", status ) || !Ustrcmp( sys, "FK4-NO-E", status ) ){ eq = palEpb( eq ); isys = RADEC; SetItemC( &(store->radesys), 0, 0, s, "FK4-NO-E", status ); } else if( !Ustrcmp( sys, "FK5", status ) ){ eq = palEpj( eq ); isys = RADEC; SetItemC( &(store->radesys), 0, 0, s, "FK5", status ); } else if( !Ustrcmp( sys, "ICRS", status ) ){ eq = AST__BAD; isys = RADEC; SetItemC( &(store->radesys), 0, 0, s, "ICRS", status ); } else if( !Ustrcmp( sys, "GAPPT", status ) || !Ustrcmp( sys, "Apparent", status ) || !Ustrcmp( sys, "Geocentric", status ) ){ eq = AST__BAD; isys = RADEC; SetItemC( &(store->radesys), 0, 0, s, "GAPPT", status ); } else if( !Ustrcmp( sys, "Helioecliptic", status ) ){ eq = AST__BAD; isys = HECLIP; } else if( !Ustrcmp( sys, "Galactic", status ) ){ eq = AST__BAD; isys = GALAC; } else if( !Ustrcmp( sys, "Supergalactic", status ) ){ eq = AST__BAD; isys = SUPER; } else if( !Ustrcmp( sys, "AzEl", status ) ){ eq = AST__BAD; isys = AZEL; } else { eq = AST__BAD; isys = NOCEL; } /* Store these values. Only store the date if it does not take its default value. */ SetItem( &(store->equinox), 0, 0, s, eq, status ); if( !defdate ) SetItem( &(store->mjdobs), 0, 0, ' ', ep, status ); /* Only proceed if we have usable values */ if( astOK ) { /* Get the indices of the latitude and longitude axes within the SkyFrame. */ latax = astGetLatAxis( skyfrm ); lonax = 1 - latax; /* The first 4 characters in CTYPE are determined by the celestial coordinate system and the second 4 by the projection type. If we are describing offset coordinates, then use "OFLN" and "OFLT. Otherwise use the standard FITS-WCS name of the system. */ if( isoff > 0 ){ strcpy( lontype, "OFLN" ); strcpy( lattype, "OFLT" ); } else if( isys == RADEC ){ strcpy( lontype, "RA--" ); strcpy( lattype, "DEC-" ); } else if( isys == ECLIP ){ strcpy( lontype, "ELON" ); strcpy( lattype, "ELAT" ); } else if( isys == HECLIP ){ strcpy( lontype, "HLON" ); strcpy( lattype, "HLAT" ); } else if( isys == GALAC ){ strcpy( lontype, "GLON" ); strcpy( lattype, "GLAT" ); } else if( isys == SUPER ){ strcpy( lontype, "SLON" ); strcpy( lattype, "SLAT" ); } else if( isys == AZEL ){ strcpy( lontype, "AZ--" ); strcpy( lattype, "EL--" ); /* For unknown systems, use the axis symbols within CTYPE if they conform to the requirement of FITS-WCS (i.e. "xxLN/xxLT" or "xLON/xLAT") or use "UNLN/UNLT" otherwise. */ } else { latsym = astGetSymbol( skyfrm, latax ); lonsym = astGetSymbol( skyfrm, lonax ); if( astOK ) { ok = 0; if( strlen( latsym ) == 4 && strlen( lonsym ) == 4 ) { if( !strcmp( latsym + 2, "LT" ) && !strcmp( lonsym + 2, "LN" ) && !strncmp( latsym, lonsym, 2 ) ) { ok = 1; } else if( !strcmp( latsym + 1, "LAT" ) && !strcmp( lonsym + 1, "LON" ) && !strncmp( latsym, lonsym, 1 ) ) { ok = 1; } } if( !ok ) { latsym = "UNLT"; lonsym = "UNLN"; } strncpy( lontype, lonsym, 4 ); for( i = strlen( lonsym ); i < 4; i++ ) { lontype[ i ] = '-'; } strncpy( lattype, latsym, 4 ); for( i = strlen( latsym ); i < 4; i++ ) { lattype[ i ] = '-'; } } } /* Store the projection strings. */ prj_name = ( wcstype == 0 ) ? "-TAB" : astWcsPrjName( wcsproj ); if( astOK ) { strcpy( lontype + 4, prj_name ); strcpy( lattype + 4, prj_name ); } /* Store the total CTYPE strings */ SetItemC( &(store->ctype), axlon, 0, s, lontype, status ); SetItemC( &(store->ctype), axlat, 0, s, lattype, status ); /* Store offset coord information. */ if( isoff ) { /* If the description is for offset coords store suitable comments for the CTYPE keywords. */ if( isoff > 0 ) { skyref = astGetC( skyfrm, "SkyRef" ); sprintf( attr, "Symbol(%d)", axlon + 1 ); sprintf( com, "%s offset from %s",astGetC( skyfrm, attr )+1, skyref ); SetItemC( &(store->ctype_com), axlon, 0, s, com, status ); sprintf( attr, "Symbol(%d)", axlat + 1 ); sprintf( com, "%s offset from %s",astGetC( skyfrm, attr )+1, skyref ); SetItemC( &(store->ctype_com), axlat, 0, s, com, status ); /* If the description is for absolute coords store the SkyFrame attribute values in AST-specific keywords. */ } else { sprintf( attr, "SkyRef(%d)", axlon + 1 ); skyref_lon = astGetD( skyfrm, attr ); sprintf( attr, "SkyRef(%d)", axlat + 1 ); skyref_lat = astGetD( skyfrm, attr ); sprintf( attr, "SkyRefP(%d)", axlon + 1 ); skyrefp_lon = astGetD( skyfrm, attr ); sprintf( attr, "SkyRefP(%d)", axlat + 1 ); skyrefp_lat = astGetD( skyfrm, attr ); skyrefis = (isoff < -2) ? "IGNORED" : ( (isoff < -1) ? "ORIGIN" : "POLE" ); SetItemC( &(store->skyrefis), 0, 0, s, skyrefis, status ); if( astTest( skyfrm, "SkyRef(1)" ) ) { SetItem( &(store->skyref), axlon, 0, s, skyref_lon, status ); SetItem( &(store->skyref), axlat, 0, s, skyref_lat, status ); } if( astTest( skyfrm, "SkyRefP(1)" ) ) { SetItem( &(store->skyrefp), axlon, 0, s, skyrefp_lon, status ); SetItem( &(store->skyrefp), axlat, 0, s, skyrefp_lat, status ); } } } /* If the Label attribute has been set for an axis, use it as the CTYPE comment and CNAME value. */ if( astTestLabel( skyfrm, latax ) ) { label = (char *) astGetLabel( skyfrm, latax ); SetItemC( &(store->ctype_com), axlat, 0, s, label, status ); SetItemC( &(store->cname), axlat, 0, s, label, status ); } if( astTestLabel( skyfrm, lonax ) ) { label = (char *) astGetLabel( skyfrm, lonax ); SetItemC( &(store->ctype_com), axlon, 0, s, label, status ); SetItemC( &(store->cname), axlon, 0, s, label, status ); } /* Nullify any CUNITS strings for the longitude and latitude axes (they always take the default value of degrees). */ SetItemC( &(store->cunit), axlat, 0, s, NULL, status ); SetItemC( &(store->cunit), axlon, 0, s, NULL, status ); } /* Store the Domain name as the WCSNAME keyword (if set). */ if( astTestDomain( skyfrm ) ) { SetItemC( &(store->wcsname), 0, 0, s, (char *) astGetDomain( skyfrm ), status ); } /* Store the observer's position if set (needed for definition of AzEl systems). */ if( astTestObsLon( skyfrm ) && astTestObsLat( skyfrm ) && s == ' ' ) { geolon = astGetObsLon( skyfrm ); geolat = astGetObsLat( skyfrm ); h = astGetObsAlt( skyfrm ); if( geolat != AST__BAD && geolon != AST__BAD && h != AST__BAD ) { iauGd2gc( 1, geolon, geolat, h, xyz ); SetItem( &(store->obsgeox), 0, 0, ' ', xyz[0], status ); SetItem( &(store->obsgeoy), 0, 0, ' ', xyz[1], status ); SetItem( &(store->obsgeoz), 0, 0, ' ', xyz[2], status ); } } if( !astOK ) ret = 0; return ret; } static char *SourceWrap( const char *(* source)( void ), int *status ) { /* * Name: * SourceWrap * Purpose: * Wrapper function to invoke a C FitsChan source function. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *SourceWrap( const char *, int *status(* source)( void ) ) * Class Membership: * FitsChan member function. * Description: * This function invokes the source function whose pointer is * supplied in order to read the next input line from an external * data store. It then returns a pointer to a dynamic string * containing a copy of the text that was read. * Parameters: * source * Pointer to a source function, with no parameters, that * returns a pointer to a const, null-terminated string * containing the text that it read. This is the form of FitsChan * source function employed by the C language interface to the * AST library. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a dynamically allocated, null terminated string * containing a copy of the text that was read. This string must be * freed by the caller (using astFree) when no longer required. * * A NULL pointer will be returned if there is no more input text * to read. * Notes: * - A NULL pointer value will be returned if this function is * invoked with the global error status set or if it should fail * for any reason. */ /* Local Variables: */ char *result; /* Pointer value to return */ const char *line; /* Pointer to input line */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Invoke the source function to read the next input line and return a pointer to the resulting string. */ line = ( *source )(); /* If a string was obtained, make a dynamic copy of it and save the resulting pointer. */ if ( line ) result = astString( line, (int) strlen( line ) ); /* Return the result. */ return result; } static AstMapping *SpectralAxes( AstFitsChan *this, AstFrameSet *fs, double *dim, int *wperm, char s, FitsStore *store, double *crvals, int *axis_done, const char *method, const char *class, int *status ){ /* * Name: * SpectralAxes * Purpose: * Add values to a FitsStore describing spectral axes in a Frame. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *SpectralAxes( AstFitsChan *this, AstFrameSet *fs, * double *dim, int *wperm, * char s, FitsStore *store, double *crvals, * int *axis_done, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The current Frame of the supplied FrameSet is searched for spectral * axes. If any are found, FITS WCS keyword values describing the axis * are added to the supplied FitsStore, if possible (the conventions * of FITS-WCS paper III are used). Note, this function does not store * values for keywords which define the transformation from pixel * coords to Intermediate World Coords (CRPIX, PC and CDELT), but a * Mapping is returned which embodies these values. This Mapping is * from the current Frame in the FrameSet (WCS coords) to a Frame * representing IWC. The IWC Frame has the same number of axes as the * WCS Frame which may be greater than the number of base Frame (i.e. * pixel) axes. * * If a spectral axis is found, the RafRA and RefDec attributes of the * SpecFrame describing the axis are ignored: it is assumed that the * WCS Frame also contains a pair of celestial axes which will result * in appropriate celestial reference values being stored in the * FitsStore (this asumption should be enforced by calling function * MakeFitsFrameSet prior to calling this function). * Parameters: * this * Pointer to the FitsChan. * fs * Pointer to the FrameSet. The base Frame should represent FITS pixel * coordinates, and the current Frame should represent FITS WCS * coordinates. The number of base Frame axes should not exceed the * number of current Frame axes. The spectral Unit in the returned * FrameSet will always be linearly related to the default Units for * the spectral System in use by the axis. If this requires a * change to the existing spectral Unit, the integrity of the * FrameSet will be maintained by suitable adjustments to the Mappings * within the FrameSet. * dim * An array holding the image dimensions in pixels. AST__BAD can be * supplied for any unknwon dimensions. * wperm * Pointer to an array of integers with one element for each axis of * the current Frame. Each element holds the zero-based * index of the FITS-WCS axis (i.e. one les than the value of "i" in * the keyword names "CTYPEi", "CRVALi", etc) which describes the * Frame axis. * s * The co-ordinate version character. A space means the primary * axis descriptions. Otherwise the supplied character should be * an upper case alphabetical character ('A' to 'Z'). * store * The FitsStore in which to store the FITS WCS keyword values. * crvals * Pointer to an array holding the default CRVAL value for each * axis in the WCS Frame. * axis_done * An array of flags, one for each Frame axis, which indicate if a * description of the corresponding axis has yet been stored in the * FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * If a spectral axis was found which can be described using the * conventions of FITS-WCS paper III, then a Mapping from the current Frame * of the supplied FrameSet, to the IWC Frame is returned. Otherwise, * a UnitMap is returned. Note, the Mapping only defines the IWC * transformation for spectral axes. Any non-spectral axes are passed * unchanged by the returned Mapping. */ /* Local Variables: */ AstFitsTable *table; /* Pointer to structure holding -TAB table info */ AstFrame *pframe; /* Primary Frame containing current WCS axis*/ AstFrame *tfrm1; /* A temporary Frame */ AstFrame *tfrm; /* A temporary Frame */ AstFrame *wcsfrm; /* WCS Frame within FrameSet */ AstFrameSet *tfs; /* A temporary FrameSet */ AstGrismMap *gmap; /* GrismMap defining the spectral axis */ AstMapping *axmap; /* Mapping from WCS to IWC */ AstMapping *map; /* Pixel -> WCS mapping */ AstMapping *ret; /* Returned Mapping */ AstMapping *tmap0; /* A temporary Mapping */ AstMapping *tmap1; /* A temporary Mapping */ AstMapping *tmap2; /* A temporary Mapping */ AstMapping *tmap3; /* A temporary Mapping */ AstMapping *tmap4; /* A temporary Mapping */ AstMapping *tmap5; /* A temporary Mapping */ AstMapping *tmap6; /* A temporary Mapping */ AstPermMap *pm; /* PermMap pointer */ AstSpecFrame *specfrm; /* The SpecFrame defining current WCS axis */ char *cname; /* Pointer to CNAME value */ char ctype[ MXCTYPELEN ]; /* The value for the FITS CTYPE keyword */ char lin_unit[ 20 ]; /* Linear spectral Units being used */ char orig_system[ 40 ]; /* Value of System attribute for current WCS axis */ char system_attr[ 10 ]; /* Name of System attribute for current WCS axis */ char unit_attr[ 10 ]; /* Name of Unit attribute for current WCS axis */ const char *cval; /* Pointer to temporary character string */ const char *x_sys[ 4 ]; /* Basic spectral systems */ double *lbnd_p; /* Pointer to array of lower pixel bounds */ double *ubnd_p; /* Pointer to array of upper pixel bounds */ double crval; /* The value for the FITS CRVAL keyword */ double dgbyds; /* Rate of change of grism parameter wrt "S" at ref. point */ double dsbydx; /* Rate of change of "S" wrt "X" at ref. point */ double geolat; /* Geodetic latitude of observer (radians) */ double geolon; /* Geodetic longitude of observer (radians) */ double gval; /* Value of grism parameter at reference point */ double h; /* Geodetic altitude of observer (metres) */ double imagfreq; /* Image sideband equivalent to the rest frequency (Hz) */ double lbnd_s; /* Lower bound on spectral axis */ double pv; /* Value of projection parameter */ double restfreq; /* Rest frequency (Hz) */ double ubnd_s; /* Upper bound on spectral axis */ double vsource; /* Rel.vel. of source (m/s) */ double xval; /* Value of "X" system at reference point */ double xyz[3]; /* Geocentric position vector (in m) */ double zsource; /* Redshift of source */ int *inperm; /* Pointer to permutation array for input axes */ int *outperm; /* Pointer to permutation array for output axes */ int extver; /* Table version number for -TAB headers */ int fits_i; /* FITS WCS axis index for current WCS axis */ int iax; /* Axis index */ int icolindex; /* Index of table column holding index vector */ int icolmain; /* Index of table column holding main coord array */ int interp; /* INterpolation method for look-up tables */ int ix; /* System index */ int j; /* Loop count */ int npix; /* Number of pixel axes */ int nwcs; /* Number of WCS axes */ int paxis; /* Axis index within primary Frame */ int sourcevrf; /* Rest Frame in which SourceVel is accesed */ /* Initialise */ ret = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* Every supported spectral system is linearly related to one of the following four systems. */ x_sys[ 0 ] = "FREQ"; x_sys[ 1 ] = "WAVE"; x_sys[ 2 ] = "AWAV"; x_sys[ 3 ] = "VELO"; /* Get a pointer to the WCS Frame. */ wcsfrm = astGetFrame( fs, AST__CURRENT ); /* Store the number of pixel and WCS axes. */ npix = astGetNin( fs ); nwcs = astGetNout( fs ); /* Store the upper and lower pixel bounds. */ lbnd_p = astMalloc( sizeof( double )*(size_t) npix ); ubnd_p = astMalloc( sizeof( double )*(size_t) npix ); if( astOK ) { for( iax = 0; iax < npix; iax++ ) { lbnd_p[ iax ] = 1.0; ubnd_p[ iax ] = ( dim[ iax ] != AST__BAD ) ? dim[ iax ] : 500; } } /* Check each axis in the WCS Frame to see if it is a spectral axis. */ axmap = NULL; for( iax = 0; iax < nwcs; iax++ ) { /* Obtain a pointer to the primary Frame containing the current WCS axis. */ astPrimaryFrame( wcsfrm, iax, &pframe, &paxis ); /* If the current axis belongs to a SpecFrame, we have found a spectral axis. */ if( astIsASpecFrame( pframe ) ) { specfrm = (AstSpecFrame *) pframe; /* Note the (zero-based) FITS WCS axis index to be used for the current Frame axis. */ fits_i = wperm[ iax ]; /* Note the name and original value of the System attribute for the spectral axis within the FrameSet current Frame. */ sprintf( system_attr, "System(%d)", iax + 1 ); cval = astGetC( wcsfrm, system_attr ); if( cval ) strcpy( orig_system, cval ); /* Note the name of the Unit attribute for the spectral axis within the FrameSet current Frame. */ sprintf( unit_attr, "Unit(%d)", iax + 1 ); /* Get a pointer to the Mapping from FITS pixel coordinates to SpecFrame. */ map = astGetMapping( fs, AST__BASE, AST__CURRENT ); /* Find the bounds of the Spectral axis over the volume of the pixel grid. */ astMapBox( map, lbnd_p, ubnd_p, 1, iax, &lbnd_s, &ubnd_s, NULL, NULL ); /* The Unit attribute of a SpecFrame can be set to arbitrary non-linear functions of standard linear spectral units. FITS-WCS paper III requires CRVAL etc to be given in linear units. So first we ensure that we have a SpecFrame with linear Units. Create a copy of the SpecFrame and clear its Unit attribute (this ensures the copy has the default linear units). Then find a Mapping from the original spectral units to the default linear units. If the conversion is possible, see if the Mapping between the units is linear. If it is, then the original Unit attribute of the SpecFrame is OK (i.e. the units are linear). If not, clear the Unit attribute of the spectral axis in the FrameSet so that it uses the default linear units (retaining the original value so that it can be re-instated later). Using the clear method on the FrameSet pointer rather than the SpecFrame pointer causes the SpecFrame to be re-mapped within the FrameSet to maintain its correct relationship with the other Frames in the FrameSet. Also update the pixel->spectrum Mapping to take account of the change in units and re-calculate the new bounds on the spectral axis. Also update any supplied CRVAL value for the spectral axis. */ tfrm = astCopy( specfrm ); astClearUnit( tfrm, 0 ); tfs = astConvert( specfrm, tfrm, "" ); tfrm = astAnnul( tfrm ); if( tfs ) { crval = crvals ? crvals[ iax ] : AST__BAD; tmap1 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); tfs = astAnnul( tfs ); if( !IsMapLinear( tmap1, &lbnd_s, &ubnd_s, 0, status ) ) { astClear( fs, unit_attr ); (void) astAnnul( map ); map = astGetMapping( fs, AST__BASE, AST__CURRENT ); astMapBox( map, lbnd_p, ubnd_p, 1, iax, &lbnd_s, &ubnd_s, NULL, NULL ); astTran1( tmap1, 1, &crval, 1, &crval ); } tmap1 = astAnnul( tmap1 ); /* Note the linear spectral Unit currently in use. */ cval = astGetUnit( specfrm, 0 ); if( cval ) strcpy( lin_unit, cval ); /* For some of the algorithms, the reference value CRVAL is arbitrary. For these algorithms we choose to use the supplied default CRVAL value. If no default CRVAL value was suppllied, we use the mid spectral value if the size of the spectral axis was given, or the lower bound (i.e. pixel 1) if the size of the spectral axis was not given. */ if( crval == AST__BAD ) { if( dim[ iax ] != AST__BAD ) { crval = 0.5*( lbnd_s + ubnd_s ); } else { crval = lbnd_s; } } /* Modify this crval value so that it correpsonds to an integer pixel coordinate. */ crval = NearestPix( map, crval, iax, status ); /* We now check to see if the Mapping from pixel coords -> linear spectral coords corresponds to one of the algorithms supported in FITS-WCS paper III. First check for the "linear" algorithm in which the linear spectral coordinate given by the SpecFrame is related linearly to the pixel coords. */ ctype[ 0 ] = 0; if( IsMapLinear( map, lbnd_p, ubnd_p, iax, status ) ) { /* The CTYPE value is just the spectral system. */ strcpy( ctype, orig_system ); /* Create the Mapping which defines the spectral IWC axis. This is initially the Mapping from WCS to IWCS - it subtracts the CRVAL value from the spectral WCS value to get the spectral IWC value (other non-spectral axes are left unchanged by this Mapping). This results in the spectral IWC axis having the same axis index as the spectral WCS axis. */ crval = -crval; tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status ); crval = -crval; axmap = AddUnitMaps( tmap0, iax, nwcs, status ); tmap0 = astAnnul( tmap0 ); } /* If the "linear" algorithm above is inappropriate, see if the "non-linear" algorithm defined in FITS-WCS paper III can be used, in which pixel coords are linearly related to some spectral system (called "X") other than the one represented by the supplied SpecFrame (called "S"). */ if( !ctype[ 0 ] ) { /* Loop round each of the 4 allowed X systems. All other spectral systems are linearly related to one of these 4 systems and so do not need to be tested. */ for( ix = 0; ix < 4 && !ctype[ 0 ]; ix++ ) { /* Set the system of the spectral WCS axis to the new trial X system. Clear the Unit attribute to ensure we are using the default linear units. Using the FrameSet pointer "fs" ensures that the Mappings within the FrameSet are modified to maintain the correct inter-Frame relationships. */ astSetC( fs, system_attr, x_sys[ ix ] ); astClear( fs, unit_attr ); /* Now we check to see if the current X system is linearly related to pixel coordinates. */ tmap3 = astGetMapping( fs, AST__BASE, AST__CURRENT ); if( IsMapLinear( tmap3, lbnd_p, ubnd_p, iax, status ) ) { /* CTYPE: First 4 characters specify the "S" system. */ strcpy( ctype, orig_system ); /* The non-linear algorithm code to be appended to the "S" system is of the form "-X2P" ("P" is the system which is linearly related to "S"). */ if( !strcmp( x_sys[ ix ], "FREQ" ) ) { strcpy( ctype + 4, "-F2" ); } else if( !strcmp( x_sys[ ix ], "WAVE" ) ) { strcpy( ctype + 4, "-W2" ); } else if( !strcmp( x_sys[ ix ], "AWAV" ) ) { strcpy( ctype + 4, "-A2" ); } else { strcpy( ctype + 4, "-V2" ); } if( !strcmp( orig_system, "FREQ" ) || !strcmp( orig_system, "ENER" ) || !strcmp( orig_system, "WAVN" ) || !strcmp( orig_system, "VRAD" ) ) { strcpy( ctype + 7, "F" ); } else if( !strcmp( orig_system, "WAVE" ) || !strcmp( orig_system, "VOPT" ) || !strcmp( orig_system, "ZOPT" ) ) { strcpy( ctype + 7, "W" ); } else if( !strcmp( orig_system, "AWAV" ) ) { strcpy( ctype + 7, "A" ); } else { strcpy( ctype + 7, "V" ); } /* Create a Mapping which gives S as a function of X. */ tfrm = astCopy( specfrm ); astSetC( tfrm, "System(1)", orig_system ); astSetC( tfrm, "Unit(1)", lin_unit ); tfs = astConvert( specfrm, tfrm, "" ); tmap5 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); tfs = astAnnul( tfs ); tfrm = astAnnul( tfrm ); /* Use the inverse of this Mapping to get the X value at the reference S value. */ astTran1( tmap5, 1, &crval, 0, &xval ); /* Also use it to get the rate of change of S with respect to X at the reference point. */ dsbydx = astRate( tmap5, &xval, 0, 0 ); /* Create the Mapping which defines the spectral IWC axis. This is the Mapping from WCS to IWC - it first converts from S to X, then subtracts the X reference value value, and then scales the axis to ensure that the rate of change of S with respect to IWC is unity (as required by FITS-WCS paper III). Other non-spectral axes are left unchanged by the Mapping. The spectral IWC axis has the same axis index as the spectral WCS axis. */ xval = -xval; tmap2 = (AstMapping *) astShiftMap( 1, &xval, "", status ); astInvert( tmap5 ); tmap0 = (AstMapping *) astCmpMap( tmap5, tmap2, 1, "", status ); tmap5 = astAnnul( tmap5 ); tmap2 = astAnnul( tmap2 ); tmap2 = (AstMapping *) astZoomMap( 1, dsbydx, "", status ); tmap1 = (AstMapping *) astCmpMap( tmap0, tmap2, 1, "", status ); tmap0 = astAnnul( tmap0 ); tmap2 = astAnnul( tmap2 ); axmap = AddUnitMaps( tmap1, iax, nwcs, status ); tmap1 = astAnnul( tmap1 ); } tmap3 = astAnnul( tmap3 ); /* Re-instate the original system and unit attributes for the spectral axis. */ astSetC( fs, system_attr, orig_system ); astSetC( fs, unit_attr, lin_unit ); } } /* If the "non-linear" algorithm above is inappropriate, see if the "log-linear" algorithm defined in FITS-WCS paper III can be used, in which the spectral axis is logarithmically spaced in the spectral system given by the SpecFrame. */ if( !ctype[ 0 ] ) { /* If the "log-linear" algorithm is appropriate, the supplied SpecFrame (s) is related to pixel coordinate (p) by s = Sr.EXP( a*p - b ). If this is the case, then the log of s will be linearly related to pixel coordinates. Test this. If the test is passed a Mapping is returned from WCS to IWC. */ axmap = LogAxis( map, iax, nwcs, lbnd_p, ubnd_p, crval, status ); /* If the axis is logarithmic... */ if( axmap ) { /* CTYPE: First 4 characters specify the "S" system. */ strcpy( ctype, orig_system ); /* The rest is "-LOG". */ strcpy( ctype + 4, "-LOG" ); } } /* If the "log-linear" algorithm above is inappropriate, see if the "grism" algorithm defined in FITS-WCS paper III can be used, in which pixel coords are related to wavelength using a grism dispersion function, implemented in AST by a GrismMap. GrismMaps produce either vacuum wavelength or air wavelength as output. Temporarily set the SpecFrame to these two systems in turn before we do the check for a GrismMap. */ for( ix = 0; ix < 2 && !ctype[ 0 ]; ix++ ) { astSetC( fs, system_attr, ( ix == 0 ) ? "WAVE" : "AWAV" ); astSetC( fs, unit_attr, "m" ); /* Get the simplified Mapping from pixel to wavelength. If the Mapping is a CmpMap containing a GrismMap, and if the output of the GrismMap is scaled by a neighbouring ZoomMap (e.g. into different wavelength units), then the GrismMap will be modified to incorporate the effect of the ZoomMap, and the ZoomMap will be removed. */ tmap2 = astGetMapping( fs, AST__BASE, AST__CURRENT ); tmap1 = astSimplify( tmap2 ); tmap2 = astAnnul( tmap2 ); /* Analyse this Mapping to see if the iax'th output is created diretcly by a GrismMap (i.e. the output of theGrismMap must not subsequently be modified by some other Mapping). If so, ExtractGrismMap returns a pointer to the GrismMap as its function value, and also returns "tmap2" as a copy of tmap1 in which the GrismMap has been replaced by a UnitMap. */ gmap = ExtractGrismMap( tmap1, iax, &tmap2, status ); if( gmap ) { /* The Mapping without the GrismMap must be linear on the spectral axis. */ if( IsMapLinear( tmap2, lbnd_p, ubnd_p, iax, status ) ) { /* Get the reference wavelength (in "m") stored in the GrismMap. */ crval = astGetGrismWaveR( gmap ); /* Save a copy of the current Wavelength (in "m") SpecFrame. */ tfrm1 = astCopy( specfrm ); /* Re-instate the original System and Unit attributes for the SpecFrame. */ astSetC( fs, system_attr, orig_system ); astSetC( fs, unit_attr, lin_unit ); /* Find the Mapping from the original "S" system to wavelength (in "m"). */ tfs = astConvert( specfrm, tfrm1, "" ); tfrm1 = astAnnul( tfrm1 ); if( tfs ) { tmap3 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); tfs = astAnnul( tfs ); /* Use the inverse of this Mapping to convert the reference value from wavelength to the "S" system. */ astTran1( tmap3, 1, &crval, 0, &crval ); /* Concatenate the "S"->wavelength Mapping with the inverse GrismMap (from wavelength to grism parameter), to get the "S" -> "grism parameter" Mapping. */ astInvert( gmap ); tmap4 = (AstMapping *) astCmpMap( tmap3, gmap, 1, "", status ); tmap3 = astAnnul( tmap3 ); /* Use this Mapping to find the grism parameter at the reference point. */ astTran1( tmap4, 1, &crval, 1, &gval ); /* Also use it to find the rate of change of grism parameter with respect to "S" at the reference point. */ dgbyds = astRate( tmap4, &crval, 0, 0 ); /* FITS-WCS paper III required ds/dw to be unity at the reference point. Therefore the rate of change of grism parameter with respect to IWC ("w") is equal to the rate of change of grism parameter with respect to "S" (at the reference point). The mapping from "w" to grism parameter is a ZoomMap which scales "w" by "dgbyds" followed by a ShiftMap which adds on "gval". */ tmap5 = (AstMapping *) astZoomMap( 1, dgbyds, "", status ); tmap6 = (AstMapping *) astShiftMap( 1, &gval, "", status ); tmap3 = (AstMapping *) astCmpMap( tmap5, tmap6, 1, "", status ); tmap5 = astAnnul( tmap5 ); tmap6 = astAnnul( tmap6 ); /* Create the Mapping which defines the spectral IWC axis. This is the Mapping from WCS "S" to IWCS "w", formed by combining the Mapping from "S" to grism parameter (tmap4), with the Mapping from grism parameter to "w" (inverse of tmap3). Other non-spectral axes are left unchanged by the Mapping. The spectral IWC axis has the same axis index as the spectral WCS axis. */ astInvert( tmap3 ); tmap5 = (AstMapping *) astCmpMap( tmap4, tmap3, 1, "", status ); tmap3 = astAnnul( tmap3 ); tmap4 = astAnnul( tmap4 ); axmap = AddUnitMaps( tmap5, iax, nwcs, status ); tmap5 = astAnnul( tmap5 ); /* CTYPE: First 4 characters specify the "S" system. */ strcpy( ctype, orig_system ); /* Last 4 characters are "-GRA" or "-GRI". */ strcpy( ctype + 4, ( ix == 0 ) ? "-GRI" : "-GRA" ); /* Store values for the projection parameters in the FitsStore. Ignore parameters which are set to the default values defined in FITS-WCS paper III. */ pv = astGetGrismG( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 0, s, pv, status ); pv = (double) astGetGrismM( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 1, s, pv, status ); pv = astGetGrismAlpha( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 2, s, pv*AST__DR2D, status ); pv = astGetGrismNR( gmap ); if( pv != 1.0 ) SetItem( &(store->pv), fits_i, 3, s, pv, status ); pv = astGetGrismNRP( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 4, s, pv, status ); pv = astGetGrismEps( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 5, s, pv*AST__DR2D, status ); pv = astGetGrismTheta( gmap ); if( pv != 0 ) SetItem( &(store->pv), fits_i, 6, s, pv*AST__DR2D, status ); } } /* Release resources. */ tmap2 = astAnnul( tmap2 ); gmap = astAnnul( gmap ); } /* Release resources. */ tmap1 = astAnnul( tmap1 ); /* Re-instate the original System and Unit attributes for the SpecFrame. */ astSetC( fs, system_attr, orig_system ); astSetC( fs, unit_attr, lin_unit ); } /* If none of the above algorithms are appropriate, we must resort to using the -TAB algorithm, in which the Mapping is defined by a look-up table. Check the TabOK attribute to see -TAB is to be supported. */ extver = astGetTabOK( this ); if( !ctype[ 0 ] && extver > 0 ) { /* Get any pre-existing FitsTable from the FitsStore. This is the table in which the tabular data will be stored (if the Mapping can be expressed in -TAB form). */ if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL; /* See if the Mapping can be expressed in -TAB form. */ tmap0 = IsMapTab1D( map, 1.0, NULL, wcsfrm, dim, iax, fits_i, &table, &icolmain, &icolindex, &interp, status ); if( tmap0 ) { /* CTYPE: First 4 characters specify the "S" system. Last 4 characters are "-TAB". */ strcpy( ctype, orig_system ); strcpy( ctype + 4, "-TAB" ); /* The values stored in the table index vector are GRID coords. So we need to ensure that IWC are equivalent to GRID coords. So set CRVAL to zero. First store the original CRVAL value (which gives the observation centre) in AXREF. */ SetItem( &(store->axref), fits_i, 0, s, crval, status ); crval = 0.0; /* Store TAB-specific values in the FitsStore. First the name of the FITS binary table extension holding the coordinate info. */ SetItemC( &(store->ps), fits_i, 0, s, AST_TABEXTNAME, status ); /* Next the table version number. This is the set (positive) value for the TabOK attribute. */ SetItem( &(store->pv), fits_i, 1, s, extver, status ); /* Also store the table version in the binary table header. */ astSetFitsI( table->header, "EXTVER", extver, "Table version number", 0 ); /* Next the name of the table column containing the main coords array. */ SetItemC( &(store->ps), fits_i, 1, s, astColumnName( table, icolmain ), status ); /* Next the name of the column containing the index array */ if( icolindex >= 0 ) SetItemC( &(store->ps), fits_i, 2, s, astColumnName( table, icolindex ), status ); /* The interpolation method (an AST extension to the published -TAB algorithm, communicated through the QVi_4a keyword). */ SetItem( &(store->pv), fits_i, 4, s, interp, status ); /* Also store the FitsTable itself in the FitsStore. */ astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL ); /* Create the WCS -> IWC Mapping (AST uses grid coords as IWC coords for the -TAB algorithm). First, get a Mapping that combines the TAB axis Mapping( tmap0) in parallel with one or two UnitMaps in order to put the TAB axis at the required index. */ tmap1 = AddUnitMaps( tmap0, iax, nwcs, status ); /* Now get a PermMap that permutes the WCS axes into the FITS axis order. */ inperm = astMalloc( sizeof( double )*nwcs ); outperm = astMalloc( sizeof( double )*nwcs ); if( astOK ) { for( j = 0; j < nwcs; j++ ) { inperm[ j ] = wperm[ j ]; outperm[ wperm[ j ] ] = j; } } pm = astPermMap( nwcs, inperm, nwcs, outperm, NULL, "", status ); /* Combine these two Mappings in series, to get the Mapping from WCS to IWC. */ axmap = (AstMapping *) astCmpMap( pm, tmap1, 1, " ", status ); /* Free resources. */ inperm = astFree( inperm ); outperm = astFree( outperm ); pm = astAnnul( pm ); tmap0 = astAnnul( tmap0 ); tmap1 = astAnnul( tmap1 ); } if( table ) table = astAnnul( table ); } /* If this axis is a usable spectral axis... */ if( ctype[ 0 ] ) { /* Add the Mapping for this axis in series with any existing result Mapping. */ if( ret ) { tmap0 = (AstMapping *) astCmpMap( ret, axmap, 1, "", status ); (void) astAnnul( ret ); ret = tmap0; } else { ret = astClone( axmap ); } axmap = astAnnul( axmap ); /* Store values for CTYPE, CRVAL and CUNIT in the FitsStore. */ SetItemC( &(store->ctype), fits_i, 0, s, ctype, status ); SetItem( &(store->crval), fits_i, 0, s, crval, status ); SetItemC( &(store->cunit), fits_i, 0, s, lin_unit, status ); /* If the axis label has been set, use it as the CTYPE comment and CNAME value. */ if( astTestLabel( specfrm, 0 ) ) { cname = (char *) astGetLabel( specfrm, 0 ); SetItemC( &(store->ctype_com), fits_i, 0, s, cname, status ); SetItemC( &(store->cname), fits_i, 0, s, cname, status ); } /* Store values for the other FITS-WCS keywords which describe the spectral system. Only store values which have been explicitly set in the SpecFrame, which are different to the default values defined by FITS-WCS paper III (if any), and which are not bad. */ if( astTestObsLon( specfrm ) && astTestObsLat( specfrm ) && s == ' ' ) { geolon = astGetObsLon( specfrm ); geolat = astGetObsLat( specfrm ); h = astGetObsAlt( specfrm ); if( geolat != AST__BAD && geolon != AST__BAD && h != AST__BAD ) { iauGd2gc( 1, geolon, geolat, h, xyz ); SetItem( &(store->obsgeox), 0, 0, ' ', xyz[0], status ); SetItem( &(store->obsgeoy), 0, 0, ' ', xyz[1], status ); SetItem( &(store->obsgeoz), 0, 0, ' ', xyz[2], status ); } } if( astTestRestFreq( specfrm ) ) { restfreq = astGetRestFreq( specfrm ); if( restfreq != AST__BAD ) { if( !strcmp( orig_system, "WAVE" ) || !strcmp( orig_system, "VOPT" ) || !strcmp( orig_system, "ZOPT" ) || !strcmp( orig_system, "AWAV" ) ) { SetItem( &(store->restwav), 0, 0, s, AST__C/restfreq, status ); } else { SetItem( &(store->restfrq), 0, 0, s, restfreq, status ); } } if( astIsADSBSpecFrame( specfrm ) ) { imagfreq = astGetImagFreq( (AstDSBSpecFrame *) specfrm ); if( imagfreq != AST__BAD ) { SetItem( &(store->imagfreq), 0, 0, s, imagfreq, status ); } } } cval = GetFitsSor( astGetC( specfrm, "StdOfRest" ), status ); if( cval ) SetItemC( &(store->specsys), 0, 0, s, cval, status ); if( astTestSourceVel( specfrm ) ) { vsource = astGetSourceVel( specfrm ); if( vsource != AST__BAD && fabs( vsource ) < AST__C ) { zsource = sqrt( (AST__C + vsource)/ (AST__C - vsource) ) - 1.0; SetItem( &(store->zsource), 0, 0, s, zsource, status ); cval = GetFitsSor( astGetC( specfrm, "SourceVRF" ), status ); if( cval ) SetItemC( &(store->ssyssrc), 0, 0, s, cval, status ); } } else { vsource = AST__BAD; } /* Store the VELOSYS value (not strictly needed since it can be determined from the other values, but FITS-WCS paper III says it can be useful). We temporarily change the source velocity to be zero m/s in the main rest frame (StdOfRest) (unless the main rest frame is already the source rest frame). We then change the source rest frame to topocentric and get the source velocity (i.e. the velocity of the main rest Frame) in the topocentric system. We then re-instate the original attribute values if they were set. */ if( astGetStdOfRest( specfrm ) != AST__SCSOR ) { sourcevrf = astGetSourceVRF( specfrm ); astSetSourceVRF( specfrm, astGetStdOfRest( specfrm ) ); astSetSourceVel( specfrm, 0.0 ); } else { vsource = AST__BAD; sourcevrf = AST__NOSOR; } astSetSourceVRF( specfrm, AST__TPSOR ); SetItem( &(store->velosys), 0, 0, s, astGetSourceVel( specfrm ), status ); if( vsource != AST__BAD ){ astSetSourceVRF( specfrm, sourcevrf ); astSetSourceVel( specfrm, vsource ); } /* Indicate that this axis has been described. */ axis_done[ iax ] = 1; } /* Release resources. */ map = astAnnul( map ); } } pframe = astAnnul( pframe ); } /* Release resources. */ lbnd_p = astFree( lbnd_p ); ubnd_p = astFree( ubnd_p ); wcsfrm = astAnnul( wcsfrm ); /* If we have a Mapping to return, simplify it. Otherwise, create a UnitMap to return. */ if( ret ) { tmap0 = ret; ret = astSimplify( tmap0 ); tmap0 = astAnnul( tmap0 ); } else { ret = (AstMapping *) astUnitMap( nwcs, "", status ); } /* Return the result. */ return ret; } static AstFitsChan *SpecTrans( AstFitsChan *this, int encoding, const char *method, const char *class, int *status ){ /* * Name: * SpecTrans * Purpose: * Translated non-standard WCS FITS headers into equivalent standard * ones. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstFitsChan *SpecTrans( AstFitsChan *this, int encoding, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function checks the supplied FitsChan for selected * non-standard WCS keywords and, if found, stores equivalent * standard keywords in a newly created FitsChan which is returned as * the function value. All the original keywords are marked * as having been used, so that they are not written out when the * FitsChan is deleted. * * At the moment, the non-standard keywords checked for are: * * 1) RADECSYS is renamed as RADESYS * * 2) LONGPOLE is renamed as LONPOLE * * 3) CDjjjiii and CDj_i are converted to PCi_j (with unit CDELT) * * 4) CROTAj are converted to PCi_j * * 5) PROJPi are converted to PV_i * * 6) CmVALi are converted to CRVALis (s=A,B,,, for m=1,2...). This * is also done for CmPIXi, CmYPEi, and CmNITi. CmELTi is converted * to a CDj_is array. * * 7) EQUINOX keywords with string values equal to a date preceded * by the letter B or J (eg "B1995.0"). These are converted to the * corresponding Julian floating point value without any epoch * specifier. * * 8) EPOCH values are converted into Julian EQUINOX values (but only * if the FitsChan does not already contain an EQUINOX value). * * 9) DATE-OBS values are converted into MJD-OBS values (but only * if the FitsChan does not already contain an MJD-OBS value). * * 10) EQUINOX or EPOCH keywords with value zero are converted to * B1950. * * 11) The AIPS NCP and GLS projections are converted into equivalent SIN * or SFL projections. * * 12) The IRAF "ZPX" projection. If the last 4 chacaters of CTYPEi * (i = 1, naxis) are "-ZPX", then: * - "ZPX" is replaced by "ZPN" within the CTYPEi value * - A distortion code of "-ZPX" is appended to the end of the CTYPEi * value (this is used later by the DistortMaps function). * - If the FitsChan contains no PROJP keywords, then projection * parameter valus are read from any WATi_nnn keywords, and * corresponding PV keywords are added to the FitsChan. * * 13) The IRAF "TNX" projection. If the last 4 chacaters of CTYPEi * (i = 1, naxis) are "-TNX", then: * - "TNX" is replaced by "TAN" within the CTYPEi value (the distorted * TAN projection included in a pre-final version of FITS-WCS is still * supported by AST using the WcsMap AST__TPN projection). * - If the FitsChan contains no PROJP keywords, then projection * parameter valus are read from any WATi_nnn keywords, and * corresponding PV keywords are added to the FitsChan. * - If the TNX projection cannot be converted exactly into a TAN * projection, ASTWARN keywords are added to the FitsChan * containing a warning message. The calling application can (if it * wants to) check for this keyword, and report its contents to the * user. * * 14) Keywords relating to the IRAF "mini-WCS" system are removed. * This is the IRAF equivalent of the AST native encoding. Mini-WCS * keywords are removed in order to avoid confusion arising between * potentially inconsistent encodings. * * 15) "QV" parameters for TAN projections (as produced by AUTOASTROM) * or "-TAB" (as produced by FitsChan) are renamed to "PV". * * 16) RESTFREQ is converted to RESTFRQ. * * 17) the "-WAV", "-FRQ" and "-VEL" CTYPE algorithms included in an * early draft of FITS-WCS paper III are translated to the * corresponding modern "-X2P" form. * * 18) AIPS spectral CTYPE values are translated to FITS-WCS paper III * equivalents. * * 19) AIPS spectral keywords OBSRA and OBSDEC are used to create a * pair of celestial axes with reference point at the specified * (OBSRA,OBSDEC) position. This is only done if the header does not * already contain a pair of celestial axes. * * 20) Common case insensitive CUNIT values: "Hz", "Angstrom", "km/s", * "M/S" * * 21) Various translations specific to the FITS-CLASS encoding. * * 22) SAO distorted TAN projections (uses COi_j keywords to store * polynomial coefficients) are converted to TPN projections. * 23) CTYPE == "LAMBDA" changed to CTYPE = "WAVE" * * 24) if the projection is TAN and the PolyTan attribute is non-zero, * or if the projection is TPV (produced by SCAMP), the projection is * changed to TPN (the AST code for the draft FITS-WCS paper II * conventions for a distorted TAN projection). * Parameters: * this * Pointer to the FitsChan. * encoding * The FitsChan encoding in use. * method * Pointer to string holding name of calling method. * class * Pointer to a string holding the name of the supplied object class. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new FitsChan containing the keywords which * constitute the standard equivalents to any non-standard keywords in * the supplied FitsChan. A NULL pointer is returned if there are no * non-standard keywords in the supplied FitsChan. */ /* Local Variables: */ AstFitsChan *ret; /* The returned FitsChan */ char *assys; /* AIPS standad of rest type */ char *astype; /* AIPS spectral type */ char *comm; /* Pointer to comment string */ char *cval; /* Pointer to character string */ char *start; /* Pointer to start of projp term */ char *watmem; /* Pointer to total WAT string */ char bj; /* Besselian/Julian indicator */ char format[ 50 ]; /* scanf format string */ char keyname[ FITSNAMLEN + 5 ];/* General keyword name + formats */ char lattype[MXCTYPELEN]; /* CTYPE value for latitude axis */ char lontype[MXCTYPELEN]; /* CTYPE value for longitude axis */ char prj[6]; /* Spatial projection string */ char s; /* Co-ordinate version character */ char spectype[MXCTYPELEN]; /* CTYPE value for spectral axis */ char sprj[6]; /* Spectral projection string */ char ss; /* Co-ordinate version character */ char template[ FITSNAMLEN + 1 ];/* General keyword name template */ double *cvals; /* PVi_m values for TPN projection */ double cdelti; /* CDELT for longitude axis */ double cdeltj; /* CDELT for latitude axis */ double cosrota; /* Cos( CROTA ) */ double crota; /* CROTA Value */ double dval; /* General floating value */ double lambda; /* Ratio of CDELTs */ double projp; /* Projection parameter value */ double rowsum2; /* Sum of squared CDi_j row elements */ double sinrota; /* Sin( CROTA ) */ double sinval; /* Sin( dec ref ) */ int *mvals; /* "m" index of each PVi_m value */ int axlat; /* Index of latitude axis */ int axlon; /* Index of longitude axis */ int diag; /* Sign of diagonal CDi_j element */ int gotpcij; /* Does FitsChan contain any PCi_j keywords? */ int i,j; /* Indices */ int iaxis; /* Axis index */ int icoeff; /* Index of next PVi_m value */ int iproj; /* Projection parameter index */ int jhi; /* Highest axis index */ int jlo; /* Lowest axis index */ int lbnd[ 2 ]; /* Lower index bounds */ int m; /* Co-ordinate version index */ int naxis; /* Number of axes */ int ncoeff; /* Number of PVi_m values */ int ok; /* Can projection be represented in FITS-WCS?*/ int shifted; /* Non-zero if there is an origin shift */ int tlbnd[ 2 ]; /* Lower index bounds */ int tubnd[ 2 ]; /* Upper index bounds */ int ubnd[ 2 ]; /* Upper index bounds */ int use_projp; /* Use PROJP keywors in favour of PV keywords? */ size_t size; /* Length of string value */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise to avoid compiler warnings. */ size = 0; prj[ 0 ] = 0; /* Create the returned FitsChan. */ ret = astFitsChan( NULL, NULL, "", status ); /* Loop round all axis descriptions, starting with primary (' '). */ for( s = 'A' - 1; s <= 'Z' && astOK; s++ ){ if( s == 'A' - 1 ) s = ' '; /* Find the number of axes by finding the highest axis number in any CRPIXi keyword name. Pass on if there are no axes for this axis description. */ if( s != ' ' ) { sprintf( template, "CRPIX%%d%c", s ); } else { strcpy( template, "CRPIX%d" ); } if( !astKeyFields( this, template, 1, &naxis, lbnd ) ) { if( s == ' ' ) s = 'A' - 1; continue; } /* Find the longitude and latitude axes by examining the CTYPE values. They are marked as read. Such markings are only provisional, and they can be read again any number of times until the current astRead operation is completed. Also note the projection type. */ j = 0; axlon = -1; axlat = -1; while( j < naxis && astOK ){ if( GetValue2( ret, this, FormatKey( "CTYPE", j + 1, -1, s, status ), AST__STRING, (void *) &cval, 0, method, class, status ) ){ if( !strncmp( cval, "RA--", 4 ) || !strncmp( cval, "AZ--", 4 ) || !strncmp( cval + 1, "LON", 3 ) || !strncmp( cval + 2, "LN", 2 ) ) { axlon = j; strncpy( prj, cval + 4, 4 ); strncpy( lontype, cval, 10 ); prj[ 4 ] = 0; } else if( !strncmp( cval, "DEC-", 4 ) || !strncmp( cval, "EL--", 4 ) || !strncmp( cval + 1, "LAT", 3 ) || !strncmp( cval + 2, "LT", 2 ) ) { axlat = j; strncpy( prj, cval + 4, 4 ); strncpy( lattype, cval, 10 ); prj[ 4 ] = 0; /* Check for spectral algorithms from early drafts of paper III */ } else { sprj[ 0 ] = '-'; if( !strncmp( cval + 4, "-WAV", 4 ) ) { sprj[ 1 ] = 'W'; } else if( !strncmp( cval + 4, "-FRQ", 4 ) ) { sprj[ 1 ] = 'F'; } else if( !strncmp( cval + 4, "-VEL", 4 ) ) { sprj[ 1 ] = 'V'; } else { sprj[ 0 ] = 0; } if( *sprj ) { sprj[ 2 ] = '2'; if( !strncmp( cval, "WAVE", 4 ) ) { sprj[ 3 ] = 'W'; } else if( !strncmp( cval, "FREQ", 4 ) ) { sprj[ 3 ] = 'F'; } else if( !strncmp( cval, "VELO", 4 ) ) { sprj[ 3 ] = 'V'; } else if( !strncmp( cval, "VRAD", 4 ) ) { sprj[ 3 ] = 'F'; } else if( !strncmp( cval, "VOPT", 4 ) ) { sprj[ 3 ] = 'W'; } else if( !strncmp( cval, "ZOPT", 4 ) ) { sprj[ 3 ] = 'W'; } else if( !strncmp( cval, "ENER", 4 ) ) { sprj[ 3 ] = 'F'; } else if( !strncmp( cval, "WAVN", 4 ) ) { sprj[ 3 ] = 'F'; } else if( !strncmp( cval, "BETA", 4 ) ) { sprj[ 3 ] = 'V'; } else { sprj[ 0 ] = 0; } } if( *sprj ) { strcpy( spectype, cval ); if( sprj[ 1 ] == sprj[ 3 ] ) { strcpy( sprj, strlen( cval ) > 8 ? "----" : " " ); } else { sprj[ 4 ] = 0; } strncpy( spectype + 4, sprj, 4 ); cval = spectype; SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); } } j++; } else { break; } } /* RADECSYS keywords ----------------- */ if( s == ' ' ) { if( GetValue2( ret, this, "RADECSYS", AST__STRING, (void *) &cval, 0, method, class, status ) ){ if( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ){ SetValue( ret, "RADESYS", (void *) &cval, AST__STRING, CardComm( this, status ), status ); } } /* LONGPOLE keywords ----------------- */ if( GetValue2( ret, this, "LONGPOLE", AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ if( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ){ SetValue( ret, "LONPOLE", (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } } /* Zero CDELT values. ----------------- */ /* Check there are some CDELT keywords... */ if( s != ' ' ) { sprintf( template, "CDELT%%d%c", s ); } else { strcpy( template, "CDELT%d" ); } if( astKeyFields( this, template, 0, NULL, NULL ) ){ /* Do each row in the matrix. */ for( j = 0; j < naxis; j++ ){ /* Get the CDELT value for this row. */ GetValue2( ret, this, FormatKey( "CDELT", j + 1, -1, s, status ), AST__FLOAT, (void *) &cdeltj, 0, method, class, status ); /* If CDELT is zero, use 1.0E-6 of the corresponding CRVAL value instead, or 1.0 if CRVAL is zero. Otherwise, the zeros could cause the matrix to be non-invertable. The Mapping could then not be simplified or used by a Plot. CDELT values of zero are usually used to indicate "redundant" axes. For instance, a 2D image may be stored as a 3D cube with a single plane with the "redundant" 3rd axis used to specify the wavelength of the filter. The actual value used for CDELT shouldn't matter since the axis only spans a single pixel anyway. */ if( cdeltj == 0.0 ){ GetValue2( ret, this, FormatKey( "CDELT", j + 1, -1, s, status ), AST__FLOAT, (void *) &dval, 1, method, class, status ); cdeltj = 1.0E-6*dval; if( cdeltj == 0.0 ) cdeltj = 1.0; SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ), (void *) &cdeltj, AST__FLOAT, NULL, status ); } } } /* Following conversions produce PCi_j keywords. Only do them if there are currently no PCi_j keywords in the header. */ if( s != ' ' ) { sprintf( template, "PC%%d_%%d%c", s ); } else { strcpy( template, "PC%d_%d" ); } gotpcij = astKeyFields( this, template, 0, NULL, NULL ); if( !gotpcij ){ /* CDjjjiii -------- */ if( s == ' ' && astKeyFields( this, "CD%3d%3d", 0, NULL, NULL ) ){ /* Do each row in the matrix. */ for( j = 0; j < naxis; j++ ){ /* Do each column in the matrix. */ for( i = 0; i < naxis; i++ ){ /* Get the CDjjjiii matrix element */ sprintf( keyname, "CD%.3d%.3d", j + 1, i + 1 ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ /* If found, save it with name PCj_i, and ensure the default value of 1.0 is used for CDELT. */ if( encoding == FITSIRAF_ENCODING ){ SetValue( ret, FormatKey( "PC", j + 1, i + 1, ' ', status ), (void *) &dval, AST__FLOAT, NULL, status ); dval = 1.0; SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); gotpcij = 1; } } } } } /* CDj_i ---- */ if( s != ' ' ) { sprintf( template, "CD%%d_%%d%c", s ); } else { strcpy( template, "CD%d_%d" ); } if( !gotpcij && astKeyFields( this, template, 0, NULL, NULL ) ){ /* Do each row in the matrix. */ for( j = 0; j < naxis; j++ ){ /* First find the sum of the squared elements in the row. and note the sign of the diagonal element. */ rowsum2 = 0.0; diag = +1; for( i = 0; i < naxis; i++ ){ if( GetValue2( ret, this, FormatKey( "CD", j + 1, i + 1, s, status ), AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ rowsum2 += dval*dval; if( i == j ) diag = ( dval >= 0.0 ) ? +1 : -1; } } /* The CDELT value for this row will be the length of the row vector. This means that each row will be a unit vector when converted to PCi_j form, and the CDELT will give a real indication of the pixel size. Ensure that the diagonal PCi+j element has a positive sign. */ cdelti = sqrt( rowsum2 )*diag; SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ), (void *) &cdelti, AST__FLOAT, NULL, status ); /* Do each column in the matrix. */ for( i = 0; i < naxis; i++ ){ /* Get the CDj_i matrix element (note default value for all CD elements is zero (even diagonal elements!). */ if( !GetValue2( ret, this, FormatKey( "CD", j + 1, i + 1, s, status ), AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ dval = 0.0; } /* Divide by the rows cdelt value and save it with name PCj_i. */ if( cdelti != 0.0 ) dval /= cdelti; SetValue( ret, FormatKey( "PC", j + 1, i + 1, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); gotpcij = 1; } } } /* PCjjjiii and CROTAi keywords ---------------------------- */ /* Check there are some CDELT keywords... */ if( s != ' ' ) { sprintf( template, "CDELT%%d%c", s ); } else { strcpy( template, "CDELT%d" ); } if( !gotpcij && astKeyFields( this, template, 0, NULL, NULL ) ){ /* See if there is a CROTA keyword. Try to read values for both axes since they are sometimes both included. This ensures they will not be included in the output when the FitsChan is deleted. Read the latitude axis second in order to give it priority in cases where both are present. */ crota = AST__BAD; GetValue2( ret, this, FormatKey( "CROTA", axlon + 1, -1, s, status ), AST__FLOAT, (void *) &crota, 0, method, class, status ); GetValue2( ret, this, FormatKey( "CROTA", axlat + 1, -1, s, status ), AST__FLOAT, (void *) &crota, 0, method, class, status ); /* If there are any PCjjjiii keywords, rename them as PCj_i. */ if( s == ' ' && astKeyFields( this, "PC%3d%3d", 0, NULL, NULL ) ){ /* Do each row in the matrix. */ for( j = 0; j < naxis; j++ ){ /* Do each column in the matrix. */ for( i = 0; i < naxis; i++ ){ /* Get the PCiiijjj matrix element */ sprintf( keyname, "PC%.3d%.3d", j + 1, i + 1 ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ } else if( i == j ) { dval = 1.0; } else { dval = 0.0; } /* Store it as PCi_j */ SetValue( ret, FormatKey( "PC", j + 1, i + 1, ' ', status ), (void *) &dval, AST__FLOAT, NULL, status ); gotpcij = 1; } } /* If there is a CROTA value and no PCjjjii keywords, create a PCj_i matrix from the CROTA values. We need to have latitude and longitude axes for this. */ } else if( s == ' ' && axlat != -1 && axlon != -1 && crota != AST__BAD ){ /* Get the sin and cos of CROTA */ cosrota = cos( crota*AST__DD2R ); sinrota = sin( crota*AST__DD2R ); /* Get the CDELT values for the longitude and latitude axes. */ if( GetValue2( ret, this, FormatKey( "CDELT", axlat + 1, -1, ' ', status ), AST__FLOAT, (void *) &cdeltj, 1, method, class, status ) && GetValue2( ret, this, FormatKey( "CDELT", axlon + 1, -1, ' ', status ), AST__FLOAT, (void *) &cdelti, 1, method, class, status ) ){ /* Save the ratio, needed below. */ lambda = cdeltj/cdelti; /* Save a corresponding set of PCi_j keywords in the FitsChan. First do the diagonal terms. */ for( i = 0; i < naxis; i++ ){ if( i == axlat ) { dval = cosrota; } else if( i == axlon ) { dval = cosrota; } else { dval = 1.0; } SetValue( ret, FormatKey( "PC", i + 1, i + 1, ' ', status ), (void *) &dval, AST__FLOAT, NULL, status ); gotpcij = 1; } /* Now do the non-zero off-diagonal terms. */ dval = sinrota/lambda; SetValue( ret, FormatKey( "PC", axlat + 1, axlon + 1, ' ', status ), (void *) &dval, AST__FLOAT, NULL, status ); dval = -sinrota*lambda; SetValue( ret, FormatKey( "PC", axlon + 1, axlat + 1, ' ', status ), (void *) &dval, AST__FLOAT, NULL, status ); } } } } /* Conversion of old PROJP, etc, is done once on the "primary" pass. */ if( s == ' ' ) { /* PROJP keywords -------------- */ if( astKeyFields( this, "PROJP%d", 1, ubnd, lbnd ) && axlat != -1 ) { /* Some people produce headers with both PROJP and PV. Even worse, the PROJP and PV values are sometimes inconsistent. In this case we trust the PV values rather than the PROJP values, but only if the PV values are not obviously incorrect for some reason. In particularly, we check that, *if* either PVi_1 or PVi_2 (where i=longitude axis) is present, then PVi_0 is also present. Conversely we check that if PVi_0 is present then at least one of PVi_1 or PVi_2 is present. */ use_projp = 1; if( axlat != -1 && astKeyFields( this, "PV%d_%d", 2, tubnd, tlbnd ) ){ use_projp = 0; /* Are there any PV values for the longitude axis? */ if( tlbnd[ 0 ] <= axlon + 1 && axlon + 1 <= tubnd[ 0 ] ) { /* Are either PVi_1 or PVi_2 available? */ if( HasCard( this, FormatKey( "PV", axlon + 1, 1, ' ', status ), method, class, status ) || HasCard( this, FormatKey( "PV", axlon + 1, 2, ' ', status ), method, class, status ) ) { /* If so use PROJP if PVi_0 is not also available. */ if( !HasCard( this, FormatKey( "PV", axlon + 1, 0, ' ', status ), method, class, status ) ) use_projp = 1; /* If neither PVi_1 or PVi_2 are available, use PROJP if PVi_0 is available. */ } else if( HasCard( this, FormatKey( "PV", axlon + 1, 0, ' ', status ), method, class, status ) ) { use_projp = 1; } } } /* Translate PROJP to PV if required. */ if( use_projp ) { for( i = lbnd[ 0 ]; i <= ubnd[ 0 ]; i++ ){ if( GetValue2( ret, this, FormatKey( "PROJP", i, -1, ' ', status ), AST__FLOAT, (void *) &dval, 0, method, class, status ) && ( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ) ){ SetValue( ret, FormatKey( "PV", axlat + 1, i, ' ', status ), (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } } } /* CmVALi keywords --------------- */ if( astKeyFields( this, "C%1dVAL%d", 2, ubnd, lbnd ) ){ ss = 'A'; for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){ for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){ sprintf( keyname, "C%dVAL%d", m, i ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) && ( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ) ){ sprintf( keyname, "CRVAL%d%c", i, ss ); SetValue( ret, keyname, (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } ss++; } } /* CmPIXi keywords --------------- */ if( astKeyFields( this, "C%1dPIX%d", 2, ubnd, lbnd ) ){ ss = 'A'; for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){ for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){ sprintf( keyname, "C%dPIX%d", m, i ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) && ( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ) ){ sprintf( keyname, "CRPIX%d%c", i, ss ); SetValue( ret, keyname, (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } ss++; } } /* CmYPEi keywords --------------- */ if( astKeyFields( this, "C%1dYPE%d", 2, ubnd, lbnd ) ){ ss = 'A'; for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){ for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){ sprintf( keyname, "C%dYPE%d", m, i ); if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) && ( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ) ){ sprintf( keyname, "CTYPE%d%c", i, ss ); SetValue( ret, keyname, (void *) &cval, AST__STRING, CardComm( this, status ), status ); } } ss++; } } /* CmNITi keywords --------------- */ if( astKeyFields( this, "C%1dNIT%d", 2, ubnd, lbnd ) ){ ss = 'A'; for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){ for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){ sprintf( keyname, "C%dNIT%d", m, i ); if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) && ( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ) ){ sprintf( keyname, "CUNIT%d%c", i, ss ); SetValue( ret, keyname, (void *) &cval, AST__STRING, CardComm( this, status ), status ); } } ss++; } } /* CmELTi keywords --------------- */ if( astKeyFields( this, "C%1dELT%d", 2, ubnd, lbnd ) ){ ss = 'A'; for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){ /* Create a PCj_is matrix by copying the PCjjjiii values and rename CmELTi as CDELTis. */ /* Do each row in the matrix. */ for( j = 0; j < naxis; j++ ){ /* Get the CDELT value for this row. Report an error if not present. */ sprintf( keyname, "C%dELT%d", m, j + 1 ); GetValue2( ret, this, keyname, AST__FLOAT, (void *) &cdeltj, 1, method, class, status ); /* If CDELT is zero, use one hundredth of the corresponding CRVAL value instead, or 1.0 if CRVAL is zero. Otherwise, the zeros could cause the matrix to be non-invertable. The Mapping could then not be simplified or used by a Plot. CDELT values of zero are usually used to indicate "redundant" axes. For instance, a 2D image may be stored as a 3D cube with a single plane with the "redundant" 3rd axis used to specify the wavelength of the filter. The actual value used for CDELT shouldn't matter since the axis only spans a single pixel anyway. */ if( cdeltj == 0.0 ){ GetValue2( ret, this, FormatKey( "CRVAL", j + 1, -1, ss, status ), AST__FLOAT, (void *) &dval, 1, method, class, status ); cdeltj = 0.01*dval; if( cdeltj == 0.0 ) cdeltj = 1.0; } /* Save it as CDELTis */ sprintf( keyname, "CDELT%d%c", j + 1, ss ); SetValue( ret, keyname, (void *) &cdeltj, AST__FLOAT, CardComm( this, status ), status ); /* Do each column in the matrix. */ for( i = 0; i < naxis; i++ ){ /* Get the PCiiijjj matrix element */ sprintf( keyname, "PC%.3d%.3d", j + 1, i + 1 ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ } else if( i == j ) { dval = 1.0; } else { dval = 0.0; } /* Store it as PCi_js. */ SetValue( ret, FormatKey( "PC", j + 1, i + 1, ss, status ), (void *) &dval, AST__FLOAT, NULL, status ); } } ss++; } } /* EPOCH keywords ------------ */ /* Get any EPOCH card, marking it as read. */ if( GetValue2( ret, this, "EPOCH", AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ /* Convert values of zero to B1950. */ if( dval == 0.0 ) dval = 1950.0; /* Save a new EQUINOX card in the FitsChan, so long as there is not already one there. */ if( !GetValue2( ret, this, "EQUINOX", AST__STRING, (void *) &cval, 0, method, class, status ) ){ SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT, "Reference equinox", status ); } } /* String EQUINOX values --------------------- If found, EQUINOX will be used in favour of any EPOCH value found above. */ if( GetValue2( ret, this, "EQUINOX", AST__STRING, (void *) &cval, 0, method, class, status ) ){ /* Note the first character. */ bj = cval[ 0 ]; /* If it is "B" or "J", read a floating value from the rest */ if( bj == 'B' || bj == 'J' ) { if( 1 == astSscanf( cval + 1, " %lf ", &dval ) ){ /* If it is a Besselian epoch, convert to Julian. */ if( bj == 'B' ) dval = palEpj( palEpb2d( dval ) ); /* Replace the original EQUINOX card. */ SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } } /* EQUINOX = 0.0 keywords ---------------------- */ if( GetValue2( ret, this, "EQUINOX", AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ if( dval == 0.0 ){ dval = 1950.0; SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } } /* DATE-OBS keywords ---------------- */ /* Read any DATE-OBS card. This prevents it being written out when the FitsChan is deleted. */ if( s == ' ' ) { strcpy( keyname, "DATE-OBS" ); if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) ){ /* Ignore DATE-OBS values if the header contains an MJD-OBS value */ strcpy( keyname, "MJD-OBS" ); if( !GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ /* Get the corresponding mjd-obs value, checking that DATE-OBS is valid. */ dval = DateObs( cval, status ); if( dval != AST__BAD ){ SetValue( ret, keyname, (void *) &dval, AST__FLOAT, "Date of observation", status ); } } } } /* Things specific to the CLASS encoding ------------------------------------- */ if( encoding == FITSCLASS_ENCODING ) ClassTrans( this, ret, axlat, axlon, method, class, status ); /* Convert SAO distorted TAN headers to TPN distorted TAN headers. -------------------------------------------------------------- */ if( s == ' ' && !Ustrcmp( prj, "-TAN", status ) ){ /* Translate the COi_m keywords into PV i+m keywords. */ if( SAOTrans( this, ret, method, class, status ) ) { /* Change the CTYPE projection form TAN to TPV. */ strcpy( prj, "-TPN" ); strcpy( lontype + 4, "-TPN" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-TPN" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); } } /* AIPS "NCP" projections --------------------- */ /* Compare the projection type with "-NCP" */ if( !Ustrcmp( prj, "-NCP", status ) ) { /* Get the latitude reference value, and take is cot. */ GetValue2( ret, this, FormatKey( "CRVAL", axlat + 1, -1, s, status ), AST__FLOAT, (void *) &dval, 1, method, class, status ); sinval = sin( dval*AST__DD2R ); if( sinval != 0.0 ) { dval = cos( dval*AST__DD2R )/sinval; /* Replace NCP with SIN in the CTYPE values. */ strcpy( lontype + 4, "-SIN" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-SIN" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); /* Store the new projection parameters using names suitable to FITS_WCS encoding. */ SetValue( ret, FormatKey( "PV", axlat + 1, 2, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); dval = 0.0; SetValue( ret, FormatKey( "PV", axlat + 1, 1, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); } } /* CLASS "ATF" projections ---------------------- */ /* Replace ATF with AIT in the CTYPE values. */ if( !Ustrcmp( prj, "-ATF", status ) ) { strcpy( lontype + 4, "-AIT" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-AIT" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); } /* AIPS "GLS" projections --------------------- */ /* Compare the projection type with "-GLS" */ if( !Ustrcmp( prj, "-GLS", status ) ) { /* Convert to "-SFL" */ strcpy( lontype + 4, "-SFL" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-SFL" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); /* FITS-WCS paper 2 (sec. 6.1.4) describes how to handle AIPS GLS projections, but requires that the axes are not rotated. Instead, we modify the native latitude at the fiducial point, theta_0, as is done in wcslib function celfix in file wcsfix.c (see also FITS-WCS paper II sec. 2.5). We only need to change theta_0 if the CRVAL position is not the celestial origin. */ shifted = 0; sprintf( keyname, "CRVAL%d", axlon + 1 ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ if( dval != 0.0 ) shifted = 1; } sprintf( keyname, "CRVAL%d", axlat + 1 ); if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ if( dval != 0.0 ) shifted = 1; } if( 0 && shifted ) { SetValue( ret, FormatKey( "PV", axlon + 1, 2, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); dval = 0.0; SetValue( ret, FormatKey( "PV", axlon + 1, 1, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); dval = 1.0; SetValue( ret, FormatKey( "PV", axlon + 1, 0, s, status ), (void *) &dval, AST__FLOAT, NULL, status ); } } /* Rename any "QV" projection parameters to "PV" (such as used by -TAB to indicate the interpolation method, or by the internal -TPN projection to indicate distortion coefficients). ------------------------------------------------------------ */ /* Rewind the FitsChan. */ astClearCard( this ); /* Search the FitsChan for QV cards. */ if( s != ' ' ) { sprintf( template, "QV%%d_%%d%c", s ); } else { strcpy( template, "QV%d_%d" ); } while( FindKeyCard( this, template, method, class, status ) && astOK ) { /* If the projection name is "TAN", replace TAN with TPN in the CTYPE values. */ if( !Ustrcmp( prj, "-TAN", status ) ){ strcpy( prj, "-TPN" ); strcpy( lontype + 4, "-TPN" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-TPN" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); } /* Indicate that the QV card has been consumed. */ MarkCard( this, status ); /* Get the keyword name and change it from QV to PV. */ strcpy( keyname, CardName( this, status ) ); keyname[ 0 ] ='P'; /* Store the new PV card so long as there it is not already present in the FitsChan. */ if( !GetValue2( ret, this, keyname, AST__FLOAT, (void *) &cval, 0, method, class, status ) ){ SetValue( ret, keyname, CardData( this, &size, status ), AST__FLOAT, CardComm( this, status ), status ); } /* Move on to the next card. */ MoveCard( this, 1, method, class, status ); } /* Change any TAN projection to TPN projection if the PolyTan attribute is non-zero. Also change any TPV projection to TPN projection. --------------------------------------------------- */ if( ( !Ustrcmp( prj, "-TAN", status ) && GetUsedPolyTan( this, ret, axlat + 1, axlon + 1, s, method, class, status ) ) || !Ustrcmp( prj, "-TPV", status ) ){ strcpy( prj, "-TPN" ); strcpy( lontype + 4, "-TPN" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-TPN" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); } /* IRAF "ZPX" projections --------------------- */ if( s == ' ' && !Ustrcmp( prj, "-ZPX", status ) ) { /* Replace "ZPX" with "ZPN-ZPX" (i.e. ZPN projection with ZPX distortion code) in the CTYPE values. */ strcpy( lontype + 4, "-ZPN-ZPX" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, ' ', status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-ZPN-ZPX" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, ' ', status ), (void *) &cval, AST__STRING, NULL, status ); /* Check latitude then longitude axes */ for( i = 0; i < 2; i++ ){ iaxis = i ? axlat : axlon; /* Concatenate all the IRAF "WAT" keywords together for this axis. These keywords are marked as having been used, so that they are not written out when the FitsChan is deleted. */ watmem = ConcatWAT( this, iaxis, method, class, status ); /* Search the total WAT string for any projp terms. */ if( watmem ){ for( iproj = 0; iproj < 10 && astOK; iproj++ ) { sprintf( format, "projp%d=", iproj ); start = strstr( watmem, format ); if( start ) { sprintf( format, "projp%d=%%lf", iproj ); if( astSscanf( start, format, &projp ) ){ SetValue( ret, FormatKey( "PV", axlat + 1, iproj, ' ', status ), (void *) &projp, AST__FLOAT, "ZPN projection parameter", status ); } } } /* Release the memory used to hold the concatenated WAT keywords. */ watmem = (char *) astFree( (void *) watmem ); } } /* IRAF "TNX" projections --------------------- */ } else if( s == ' ' && !Ustrcmp( prj, "-TNX", status ) ) { /* Replace TNX with TPN in the CTYPE values. */ strcpy( lontype + 4, "-TPN" ); cval = lontype; SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, ' ', status ), (void *) &cval, AST__STRING, NULL, status ); strcpy( lattype + 4, "-TPN" ); cval = lattype; SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, ' ', status ), (void *) &cval, AST__STRING, NULL, status ); /* Check latitude then longitude axes */ for( i = 0; i < 2; i++ ){ iaxis = i ? axlat : axlon; /* Concatenate all the IRAF "WAT" keywords together for this axis. These keywords are marked as having been used, so that they are not written out when the FitsChan is deleted. */ watmem = ConcatWAT( this, iaxis, method, class, status ); /* Extract the polynomial coefficients from the concatenated WAT string. These are returned in the form of a list of PVi_m values for a TPN projection. */ ncoeff = WATCoeffs( watmem, i, &cvals, &mvals, &ok, status ); /* If we can handle the TNX projection, store the PV values in the FitsChan. */ if( ok ) { for( icoeff = 0; icoeff < ncoeff; icoeff++ ) { SetValue( ret, FormatKey( "PV", iaxis + 1, mvals[ icoeff ], ' ', status ), (void *) (cvals + icoeff), AST__FLOAT, "TAN projection parameter", status ); } /* If the TNX cannot be represented in FITS-WCS (within our restrictions), add warning keywords to the FitsChan. */ } else { Warn( this, "tnx", "This FITS header includes, or was " "derived from, a TNX projection which requires " "unsupported IRAF-specific corrections. The WCS " "information may therefore be incorrect.", method, class, status ); } /* Release the memory used to hold the concatenated WAT keywords. */ watmem = (char *) astFree( (void *) watmem ); } } /* MSX CAR projections. ------------------- */ if( !Ustrcmp( prj, "-CAR", status ) ) { /* If the projection is a CAR projection, check that the CRPIX value for the longitude axis corresponds to a projection plane point which has valid native longitude. The CAR projection has valid projection plane points only for native longitudes in the range [-180,+180, so we modify the CRPIX value if necessary by the number of pixels corresponding to 360 degres of longitude in order to bring the refernce pixel into the valid domain of the projection. */ if( GetValue2( ret, this, FormatKey( "CDELT", axlon + 1, -1, s, status ), AST__FLOAT, (void *) &cdelti, 1, method, class, status ) && GetValue2( ret, this, FormatKey( "CRPIX", axlon + 1, -1, s, status ), AST__FLOAT, (void *) &dval, 0, method, class, status ) ) { if( cdelti != 0.0 ) { dval = 0.5 + AST__DR2D*palDrange( AST__DD2R*( dval - 0.5 )*cdelti )/cdelti; SetValue( ret, FormatKey( "CRPIX", axlon + 1, -1, s, status ), (void *) &dval, AST__FLOAT, CardComm( this, status ), status ); } } } /* Replace RESTFREQ by RESTFRQ. ---------------------------- */ /* Get any RESTFREQ card, marking it as read. */ if( s != ' ' ) { sprintf( keyname, "RESTFREQ%c", s ); } else { strcpy( keyname, "RESTFREQ" ); } if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method, class, status ) ){ /* Look for "MHz" and "GHz" within the comment. If found scale the value into Hz. */ comm = CardComm( this, status ); if( comm ) { if( strstr( comm, "GHz" ) ) { dval *= 1.0E9; comm = "[Hz] Rest Frequency"; } else if( strstr( comm, "MHz" ) ) { dval *= 1.0E6; comm = "[Hz] Rest Frequency"; } } /* Save a new RESTFRQ card in the FitsChan, so long as there is not already one there. */ if( s != ' ' ) { sprintf( keyname, "RESTFRQ%c", s ); } else { strcpy( keyname, "RESTFRQ" ); } if( !GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method, class, status ) ){ SetValue( ret, keyname, (void *) &dval, AST__FLOAT, comm, status ); } } /* Translate AIPS spectral CTYPE values to FITS-WCS paper III equivalents. These are of the form AAAA-BBB, where "AAAA" can be "FREQ", "VELO" (=VRAD!) or "FELO" (=VOPT-F2W), and BBB can be "LSR", "LSD", "HEL" (=*Bary*centric!) or "GEO". Also convert "LAMBDA" to "WAVE". */ for( j = 0; j < naxis; j++ ) { if( GetValue2( ret, this, FormatKey( "CTYPE", j + 1, -1, s, status ), AST__STRING, (void *) &cval, 0, method, class, status ) ){ if( IsAIPSSpectral( cval, &astype, &assys, status ) ) { SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ), (void *) &astype, AST__STRING, NULL, status ); SetValue( ret, "SPECSYS", (void *) &assys, AST__STRING, NULL, status ); break; } else if( !strcmp( cval, "LAMBDA " ) ) { cval = "WAVE"; SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ), (void *) &cval, AST__STRING, NULL, status ); break; } } } /* Common case insensitive CUNIT values: "Hz", "Angstrom", "km/s", "M/S" */ if( s != ' ' ) { sprintf( template, "CUNIT%%d%c", s ); } else { strcpy( template, "CUNIT%d" ); } if( astKeyFields( this, template, 1, &jhi, &jlo ) ){ /* Convert keyword indices from 1-based to 0-base, and loop round them all. */ jhi--; jlo--; for( j = jlo; j <= jhi; j++ ){ char *keynam; keynam = FormatKey( "CUNIT", j + 1, -1, s, status ); if( GetValue2( ret, this, keynam, AST__STRING, (void *) &cval, 0, method, class, status ) ){ size_t nc = astChrLen( cval ); if( nc == 0 ) { cval = NULL; } else if( !Ustrcmp( cval, "Hz", status ) ) { cval = "Hz"; } else if( !Ustrcmp( cval, "Angstrom", status ) ) { cval = "Angstrom"; } else if( !Ustrcmp( cval, "km/s", status ) ) { cval = "km/s"; } else if( !Ustrcmp( cval, "m/s", status ) ) { cval = "m/s"; } else { cval = NULL; } if( cval ) SetValue( ret, keynam, (void *) &cval, AST__STRING, NULL, status ); } } } /* After doing the primary axis descriptions, prepare to do the "A" description. */ if( s == ' ' ) s = 'A' - 1; } /* IRAF mini-WCS keywords ---------------------- */ /* Rewind the FitsChan to search from the first card. */ astClearCard( this ); /* Search forward through until all cards have been checked. */ while( !astFitsEof( this ) && astOK ){ /* Check to see if the keyword name from the current card matches any of the known mini-WCS keywords. If so, mark the card as read. */ if( Match( CardName( this, status ), "WAT%d_%d", 0, NULL, &m, method, class, status ) || Match( CardName( this, status ), "LTM%d_%d", 0, NULL, &m, method, class, status ) || Match( CardName( this, status ), "LTV%d", 0, NULL, &m, method, class, status ) || Match( CardName( this, status ), "WSV%d_LEN", 0, NULL, &m, method, class, status ) || Match( CardName( this, status ), "WSV%d_%d", 0, NULL, &m, method, class, status ) ){ MarkCard( this, status ); } /* Now move the current card on to the next card. */ MoveCard( this, 1, method, class, status ); } /* Delete the returned FitsChan if it is empty. */ if( ret && !astGetNcard( ret ) ) ret = (AstFitsChan *) astDelete( ret ); /* Return. */ return ret; } int Split( const char *card, char **name, char **value, char **comment, const char *method, const char *class, int *status ){ /* * Name: * Split * Purpose: * Extract the keyword name, value and comment from a FITS header card. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Split( const char *card, char **name, char **value, * char **comment, const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * The name, value and comment (if present) are extracted from the * supplied card text and returned. * Parameters: * card * Pointer to a string holding the FITS header card. * name * Pointer to a location at which to return the pointer to a string * holding the keyword name. * value * Pointer to a location at which to return the pointer to a string * holding the keyword value. * comment * Pointer to a location at which to return the pointer to a string * holding the keyword comment. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned value: * - An integer identifying the data type of the keyword value. This * will be one of the values AST__UNDEF, AST__COMMENT, AST__INT, * AST__STRING, AST__CONTINUE, AST__FLOAT, AST__COMPLEXI or AST__COMPLEXF * defined in fitschan.h. * Notes: * - If the keyword value is a string, then the returned value does not * include the delimiting quotes, and pairs of adjacent quotes within the * string are replaced by single quotes. * - A maximum of 80 characters are read from the supplied card, so the * string does not need to be null terminated unless less than 80 * characters are to be read. * - The memory holding the three strings "name", "value" and "comment" * should be released when no longer needed using astFree. * - NULL pointers and a data type of AST__COMMENT are returned if an * error has already occurred, or if this function fails for any reason. */ /* Local Variables: */ char *c; /* Pointer to returned comment string */ char *dd; /* Pointer to intermediate character */ char *slash; /* Pointer to comment character */ char *v; /* Pointer to returned value string */ const char *d; /* Pointer to first comment character */ const char *v0; /* Pointer to first non-blank value character */ double fi, fr; /* Values read from value string */ int blank_name; /* Is keyword name blank? */ int cont; /* Is this a continuation card? */ int i; /* Character index */ int ii, ir; /* Values read from value string */ int iopt; /* Index of option within list */ int lq; /* Was previous character an escaping quote? */ int len; /* Used length of value string */ int nch; /* No. of characters used */ int ndig; /* No. of digits in the formatted integer */ int type; /* Keyword data type */ size_t nc; /* Number of character in the supplied card */ size_t ncc; /* No. of characters in the comment string */ size_t ncv; /* No. of characters in the value string */ /* Initialise the returned pointers. */ *name = NULL; *value = NULL; *comment = NULL; type = AST__COMMENT; /* Check the global status. */ if( !astOK ) return type; /* Store the number of characters to be read from the supplied card. This is not allowed to be more than the length of a FITS header card. Trailing white space and non-printing characters such as new-line are ignored. */ nc = 0; while( nc < AST__FITSCHAN_FITSCARDLEN && card[ nc ] ) nc++; /* Allocate memory for a copy of the keyword name plus a terminating null character. */ *name = (char *) astMalloc( ( 1 + FITSNAMLEN )*sizeof(char) ); /* Check the pointer can be used. */ if( astOK ){ /* Initialise the name string by filling it with spaces, and terminating it. */ for( i = 0; i < FITSNAMLEN; i++ ) (*name)[ i ] = ' '; (*name)[ FITSNAMLEN ] = 0; /* Copy the the keyword name, ensuring that no more than FITSNAMLEN (8) characters are copied. */ strncpy( *name, card, ( nc > FITSNAMLEN ) ? FITSNAMLEN : nc ); /* If there is no keyword name, flag that we have a blank name which will be treated as a comment card. */ if( strspn( *name, " " ) == strlen( *name ) ){ blank_name = 1; /* If the card contains a keyword name, replace any white space with nulls. */ } else { blank_name = 0; dd = *name + strlen( *name ) - 1; while( isspace( *dd ) ) *(dd--) = 0; } /* Check the keyword name is legal. */ CheckFitsName( *name, method, class, status ); /* Allocate memory to hold the keyword value and comment strings. */ *value = (char *) astMalloc( sizeof(char)*( 2 + nc ) ); *comment = (char *) astMalloc( sizeof(char)*( 1 + nc ) ); /* Check the pointers can be used. */ if( astOK ){ /* Check for CONTINUE cards. These have keyword CONTINUE but have a space instead of an equals sign in column 9. They must also have a single quote in column 11. */ cont = ( !Ustrcmp( *name, "CONTINUE", status ) && nc > FITSNAMLEN + 3 && card[ FITSNAMLEN ] == ' ' && card[ FITSNAMLEN + 2 ] == '\'' ); /* If column 9 does not contain an equals sign (but is not a CONTINUE card), or if the keyword is "HISTORY", "COMMENT" or blank, then columns 9 to the end are comment characters, and the value string is null. */ if( ( nc <= FITSNAMLEN || card[ FITSNAMLEN ] != '=' || !Ustrcmp( *name, "HISTORY", status ) || !Ustrcmp( *name, "COMMENT", status ) || blank_name ) && !cont ){ (*value)[ 0 ] = 0; if( nc > FITSNAMLEN ){ (void) strncpy( *comment, card + FITSNAMLEN, nc - FITSNAMLEN ); (*comment)[ nc - FITSNAMLEN ] = 0; } else { (*comment)[ 0 ] = 0; } /* Otherwise there is a value field. */ } else { /* Find the first non-blank character in the value string. */ v0 = card + FITSNAMLEN + 1; while( (size_t)(v0 - card) < nc && isspace( (int) *v0 ) ) v0++; /* Store pointers to the start of the returned value and comment strings. */ v = *value; c = *comment; /* If the first character in the value string is a single quote, the value is a string. In this case the value ends at the first non-escaped single quote. */ if( *v0 == '\''){ type = cont ? AST__CONTINUE : AST__STRING; /* We want to copy the string value, without the delimiting quotes, to the returned value string. Single quotes within the string are represented by two adjacent quotes, so we also need to check for these and replace them by one quote in the returned string. First initialise a pointer to the first character after the opening quote, and set a flag indicating that (for the purposes of identifying pairs of adjacent quotes within the string) the previous character was not a quote. */ d = v0 + 1; lq = 0; /* Loop round each remaining character in the supplied card. */ while( (size_t)(d - card) < nc ){ /* If the current character is a single quote... */ if( *d == '\'' ){ /* If the previous character was also a single quote then the quote does not mark the end of the string, but is a quote to be included literally in the value. Copy the quote to the returned string and clear the flag to indicate that the pair of adjacent quotes is now complete. */ if( lq ){ *(v++) = '\''; lq = 0; /* If the last character was not a quote, then set the flag for the next pass through the loop, but do not copy the quote to the returned string since it will either be a quote escaping a following adjacent quote, or a quote to mark the end of the string. */ } else { lq = 1; } /* If the current character is not a quote... */ } else { /* If the previous character was a quote, then we have found a single isolated quote which therefore marks the end of the string value. The pointer "d" is left pointing to the first character after the terminating quote. */ if( lq ){ break; /* If the last character was not a quote, copy it to the returned string. */ } else { *(v++) = *d; } } d++; } /* Terminate the returned value string. */ *v = 0; /* Now deal with logical and numerical values. */ } else { /* The end of the value field is marked by the first "/". Find the number of characters in the value field. Pointer "d" is left pointing to the first character in the comment (if any). Only use "/" characters which occur within the first nc characters. */ d = strchr( card, '/' ); if( !d || ( d - card ) >= nc ){ ncv = nc - FITSNAMLEN - 1; d = NULL; } else { ncv = (size_t)( d - card ) - FITSNAMLEN - 1; } /* Copy the value string to the returned string. */ if( ncv == 0 ){ *v = 0; } else { strncpy( v, card + FITSNAMLEN + 1, ncv ); v[ ncv ] = ' '; v[ ncv + 1 ] = 0; } /* Find the first non-blank character in the value string. */ v0 = v; while( *v0 && isspace( (int) *v0 ) ) v0++; /* See if the value string is one of the following strings (optionally abbreviated and case insensitive): YES, NO, TRUE, FALSE. */ iopt = FullForm( "YES NO TRUE FALSE", v0, 1, status ); /* Return the single character "T" or "F" at the start of the value string if the value matches one of the above strings. */ if( iopt == 0 || iopt == 2 ) { type = AST__LOGICAL; strcpy ( v, "T" ); } else if( iopt == 1 || iopt == 3 ) { type = AST__LOGICAL; strcpy ( v, "F" ); /* If it does not match, see if the value is numerical. */ } else { /* Save the length of the value string excluding trailing blanks. */ len = ChrLen( v, status ); /* If the entire string is blank, the value type is UNDEF. */ if( len == 0 ) { type = AST__UNDEF; /* If there are no dots (decimal points) or exponents (D or E) in the value... */ } else if( !strpbrk( v, ".EeDd" ) ){ /* First attempt to read two integers from the string (separated by white space). */ if( nch = 0, ( 2 == astSscanf( v, " %d %d%n", &ir, &ii, &nch ) ) && ( nch >= len ) ) { type = AST__COMPLEXI; /* If that failed, attempt to read a single integer from the string. */ } else if( nch = 0, ( 1 == astSscanf( v, " %d%n", &ir, &nch ) ) && ( nch >= len ) ) { type = AST__INT; } /* If there are dots (decimal points) in the value... */ } else { /* First attempt to read two doubles from the string (separated by white space). */ if( nch = 0, ( 2 == astSscanf( v, " %lf %lf%n", &fr, &fi, &nch ) ) && ( nch >= len ) ) { type = AST__COMPLEXF; /* If that failed, attempt to read a single double from the string. */ } else if( nch = 0, ( 1 == astSscanf( v, " %lf%n", &fr, &nch ) ) && ( nch >= len ) ) { type = AST__FLOAT; } /* If both the above failed, it could be because the string contains a "D" exponent (which is probably valid FITS) instead of an "E" exponent. Replace any "D" in the string with "e" and try again. */ if( type == AST__COMMENT && astOK ) { /* Replace "d" and "D" by "e" (if this doesn't produce a readable floating point value then the value string will not be used, so it is safe to do the replacement in situ). */ for( i = 0; i < len; i++ ) { if( v[ i ] == 'd' || v[ i ] == 'D' ) v[ i ] = 'e'; } /* Attempt to read two doubles from the edited string (separated by white space). */ if( nch = 0, ( 2 == astSscanf( v, " %lf %lf%n", &fr, &fi, &nch ) ) && ( nch >= len ) ) { type = AST__COMPLEXF; /* If that failed, attempt to read a single double from the edited string. */ } else if( nch = 0, ( 1 == astSscanf( v, " %lf%n", &fr, &nch ) ) && ( nch >= len ) ) { type = AST__FLOAT; } } } } /* If the value type could not be determined report an error. */ if( type == AST__COMMENT && astOK ) { astError( AST__BDFTS, "%s(%s): Illegal keyword value " "supplied.", status, method, class ); } } /* Find the number of characters in the comment. Pointer "d" should point to the first character following the value string. */ if( d ){ ncc = nc - (size_t)( d - card ); } else { ncc = 0; } /* Copy the remainder of the card to the returned comment string. */ if( astOK && ncc > 0 ){ strncpy( c, d, ncc ); c[ ncc ] = 0; /* Find the start of the comment (indicated by the first "/" after the value string). */ slash = strchr( c, '/' ); /* Temporarily terminate the string at the slash. */ if( slash ) *slash = 0; /* Shuffle the characters following the slash down to the start of the returned string. */ if( slash ){ ncc -= (size_t)( slash - c ) + 1; d = slash + 1; for( i = 0; i < 1 + (int) ncc; i++ ) *(c++) = *(d++); } /* If there is no comment string, return a null string. */ } else { *c = 0; } } } } /* Truncate the returned string to avoid wasting space. */ if( *name ) *name = (char *) astRealloc( (void *) *name, strlen( *name ) + 1 ); if( *comment ) *comment = (char *) astRealloc( (void *) *comment, strlen( *comment ) + 1 ); if( *value ) *value = (char *) astRealloc( (void *) *value, strlen( *value ) + 1 ); /* If the value is deemed to be integer, check that the number of digits in the formatted value does not exceed the capacity of an int. This may be the case if there are too many digits in the integer for an "int" to hold. In this case, change the data type to float. */ if( *value && type == AST__INT ) { ndig = 0; c = *value; while( *c ) { if( isdigit( *(c++) ) ) ndig++; } if( ndig >= int_dig ) type = AST__FLOAT; } /* If an error occurred, free the returned strings and issue a context message. */ if( !astOK ){ *name = (char *) astFree( (void *) *name ); *value = (char *) astFree( (void *) *value ); *comment = (char *) astFree( (void *) *comment ); type = AST__COMMENT; astError( astStatus, "%s(%s): Unable to store the following FITS " "header card:\n%s\n", status, method, class, card ); } /* Return the data type. */ return type; } static int SplitMap( AstMapping *map, int invert, int ilon, int ilat, AstMapping **map1, AstWcsMap **map2, AstMapping **map3, int *status ){ /* * Name: * SplitMap * Purpose: * Locate a WCS projection within a Mapping. * Type: * Private function. * Synopsis: * int SplitMap( AstMapping *map, int invert, int ilon, int ilat, * AstMapping **map1, AstWcsMap **map2, AstMapping **map3, int *status ) * Class Membership: * FitsChan * Description: * If possible, the supplied Mapping is decomposed into three component * mappings to be compounded in series. To be acceptable, the second of * these three Mappings must be an inverted WcsMap with a non-zero * FITSProj attribute value, and there must not be such a WcsMap in * either of the other two Mappings. If it is not possible to produce * such a group of three Mappings, then a zero function value is returned, * together with three NULL Mapping pointers. All the mappings before the * WcsMap are compounded together and returned as "map1". The inverse of * the WcsMap itself is returned as "map2", and any remaining Mappings * are compounded together and returned as "map3". * * The search algorithm allows for an arbitrary combination of series and * parallel CmpMaps. * Parameters: * map * A pointer to the Mapping from pixel to physical coordinates. * invert * The value of the Invert attribute to use with "map" (the value * returned by astGetInvert is not used). * ilon * Index of mapping output which is connected to the longitude axis. * ilat * Index of mapping output which is connected to the latitude axis. * map1 * A location at which to return a pointer to the Mapping from pixel * to intermediate world coordinates. * map2 * A location at which to return a pointer to the Mapping from * intermediate world coordinates to native spherical coordinates. This * will be an inverted WcsMap with non-zero FITSProj attribute value. * map3 * A location at which to return a pointer to the Mapping from * native spherical coordinates to physical coordinates. * dep * The address of an integer holding the current depth of recursion * into this function. * status * Pointer to the inherited status variable. * Returned Value: * One if a suitable WcsMap was found, zero otherwise. * Notes: * - The returned Mappings contain independant copies of the relevant * components of the supplied Mapping and can be modified without * changing the supplied Mapping. * - NULL pointers will be returned for all Mappings if no WcsMap * can be found in the supplied Mapping. * - A pointer to a UnitMap will be returned for map1 if no mappings * exist before the WcsMap. * - A pointer to a UnitMap will be returned for map3 if no mappings * exist after the WcsMap. * - NULL pointers will be returned for all Mappings and a function * value of zero will be returned if an error has occurred, or if this * function should fail for any reason. */ /* Local Variables */ AstFitsChan *fc; /* Pointer to temporary FitsChan */ AstFrameSet *tfs; /* Temporary FrameSet */ AstMapping *mapa; /* Pre-wcs Mapping */ AstMapping *mapc; /* Post-wcs Mapping */ AstMapping *tmap1; /* Temporary Mapping */ AstMapping *tmap2; /* Temporary Mapping */ AstPointSet *pset1; /* Pixel positions */ AstPointSet *pset2; /* WCS positions */ AstWcsMap *mapb; /* WcsMap */ char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for header card */ double **ptr1; /* Pointer to pixel axis values */ double **ptr2; /* Pointer to WCS axis values */ double *iwc_origin; /* Array holding IWC at pixel origin */ double *pix_origin; /* Array holding pixel coords at pixel origin */ double *w1; /* Pointer to work space */ int i; /* Loop index */ int npix; /* Number of pixel axes */ int nwcs; /* Number of WCS axes */ int ret; /* Was a non-linear Mapping found? */ /* Initialise */ *map1 = NULL; *map2 = NULL; *map3 = NULL; ret = 0; /* Check the global status. */ if( !astOK ) return ret; /* Call SplitMap2 to do the work. SplitMap2 does not check that the WcsMap is an *inverted* WcsMap, neither does it check that there are no WcsMaps in either map1 or map3. */ if( SplitMap2( map, invert, map1, map2, map3, status ) ) { /* Check that the WcsMap is inverted. */ if( astGetInvert( *map2 ) ) { /* Check that map 1 does not contain a WcsMap with non-zero FITSProj attribute. */ if( !SplitMap2( *map1, astGetInvert( *map1 ), &mapa, &mapb, &mapc, status ) ) { /* Check that map 3 does not contain a WcsMap with non-zero FITSProj attribute. */ if( !SplitMap2( *map3, astGetInvert( *map3 ), &mapa, &mapb, &mapc, status ) ) { /* If so, the three Mappings are OK. */ ret = 1; } else { mapa = astAnnul( mapa ); mapb = astAnnul( mapb ); mapc = astAnnul( mapc ); } } else { mapa = astAnnul( mapa ); mapb = astAnnul( mapb ); mapc = astAnnul( mapc ); } } } /* If the above failed to find a suitable WcsMap, we now consider cases where the pixel->WCS mapping is linear. We can invent a CAR projection WcsMap for such cases. We use a ShiftMap to move the origin of the longitude IWC axis to a sensible value (it is left at zero otherwise). We cannot do this with the latitude axis since pre-FITS-WCS fits readers could not handle the resulting rotation from native to celestial coords. */ if( !ret && astGetIsLinear( map ) ) { nwcs = astGetNout( map ); npix = astGetNin( map ); iwc_origin = astMalloc( sizeof( double )*nwcs ); pix_origin = astMalloc( sizeof( double )*npix ); if( astOK ) { for( i = 0; i < npix; i++ ) pix_origin[ i ] = 0.0; astTranN( map, 1, npix, 1, pix_origin, 1, nwcs, 1, iwc_origin ); for( i = 0; i < nwcs; i++ ) { if( i != ilon ) { iwc_origin[ i ] = 0.0; } else { iwc_origin[ i ] *= -1; } } mapa = (AstMapping *) astShiftMap( nwcs, iwc_origin, "", status ); *map1 = (AstMapping *) astCmpMap( map, mapa, 1, "", status ); *map2 = astWcsMap( nwcs, AST__CAR, ilon + 1, ilat + 1, "Invert=1", status ); astInvert( mapa ); *map3 = astClone( mapa ); mapa = astAnnul( mapa ); ret = 1; } iwc_origin = astFree( iwc_origin ); pix_origin = astFree( pix_origin ); } /* If the above failed to find a suitable WcsMap, we now consider cases where the output (long,lat) values are constants supplied by a final PermMap. We can invent a WcsMap for such cases. */ if( !ret ) { /* Transform two arbitrary pixel positions into the WCS Frame. */ npix = astGetNin( map ); nwcs = astGetNout( map ); pset1 = astPointSet( 2, npix, "", status ); pset2 = astPointSet( 2, nwcs, "", status ); ptr1 = astGetPoints( pset1 ); ptr2 = astGetPoints( pset2 ); w1 = astMalloc( sizeof( double )*(size_t) nwcs ); if( astOK ) { for( i = 0; i < npix; i++ ) { ptr1[ i ][ 0 ] = 1.0; ptr1[ i ][ 1 ] = 1000.0; } (void) astTransform( map, pset1, 1, pset2 ); /* If the two wcs positions have equal longitude and latitude values, assume that the output longitude and latitude axes are assigned constant values by the Mapping. */ if( ptr2[ ilon ][ 0 ] == ptr2[ ilon ][ 1 ] && ptr2[ ilon ][ 0 ] != AST__BAD && ptr2[ ilat ][ 0 ] == ptr2[ ilat ][ 1 ] && ptr2[ ilat ][ 0 ] != AST__BAD ) { /* Create a set of Mappings to return, including a WcsMap, which result in these constant latitude and longitude values. We do this by creating a FITS-WCS header and reading the FrameSet from it. Keywords which are not important to the final mappings are given arbitrary values. */ fc = astFitsChan( NULL, NULL, "", status ); for( i = 0; i < nwcs; i++ ) { sprintf( card, "CRPIX%d = 0", i + 1 ); astPutFits( fc, card, 0 ); sprintf( card, "CDELT%d = 0.0003", i + 1 ); astPutFits( fc, card, 0 ); if( i == ilon ) { sprintf( card, "CTYPE%d = 'RA---TAN'", i + 1 ); } else if( i == ilat ) { sprintf( card, "CTYPE%d = 'DEC--TAN'", i + 1 ); } else { sprintf( card, "CTYPE%d = 'DUMMY'", i + 1 ); } astPutFits( fc, card, 0 ); if( i == ilon ) { sprintf( card, "CRVAL%d = %.*g", i + 1, DBL_DIG, AST__DR2D*ptr2[ ilon ][ 0 ] ); } else if( i == ilat ) { sprintf( card, "CRVAL%d = %.*g", i + 1, DBL_DIG, AST__DR2D*ptr2[ ilat ][ 0 ] ); } else { sprintf( card, "CRVAL%d = 0.0", i + 1 ); } astPutFits( fc, card, 0 ); } astClearCard( fc ); tfs = astRead( fc ); if( tfs ) { /* Use SplitMap to get the required Mapings from the FrameSet. */ tmap2 = astGetMapping( tfs, AST__BASE, AST__CURRENT ); SplitMap( tmap2, astGetInvert( tmap2 ), 0, 1, &tmap1, map2, map3, status ); tmap1 = astAnnul( tmap1 ); tmap2 = astAnnul( tmap2 ); /* Create a ShiftMap which subtract the constant longitude and latitude values off the inputs. */ for( i = 0; i < nwcs; i++ ) w1[ i ] = 0.0; w1[ ilon ] = -ptr2[ ilon ][ 0 ]; w1[ ilat ] = -ptr2[ ilat ][ 0 ]; tmap1 = (AstMapping *) astShiftMap( nwcs, w1, "", status ); /* Compose this with the supplied Mapping. This results in the celestial outputs being zero. This gives the required "map1". */ *map1 = (AstMapping *) astCmpMap( map, tmap1, 1, "", status ); /* Indicate success.*/ ret = 1; /* Free resources. */ tmap1 = astAnnul( tmap1 ); tfs = astAnnul( tfs ); } fc = astAnnul( fc ); } } /* Free resources */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); w1 = astFree( w1 ); } if( !ret ) { if( *map1 ) *map1 = astAnnul( *map1 ); if( *map2 ) *map2 = astAnnul( *map2 ); if( *map3 ) *map3 = astAnnul( *map3 ); } return ret; } static int SplitMap2( AstMapping *map, int invert, AstMapping **map1, AstWcsMap **map2, AstMapping **map3, int *status ){ /* * Name: * SplitMap2 * Purpose: * Locate a WCS projection within a Mapping. * Type: * Private function. * Synopsis: * int SplitMap2( AstMapping *map, int invert, AstMapping **map1, * AstWcsMap **map2, AstMapping **map3, int *status ) * Class Membership: * FitsChan * Description: * If possible, the supplied Mapping is decomposed into three component * mappings to be compounded in series. To be acceptable, the second of * these three Mappings must be a WcsMap with a non-zero FITSProj value. * If it is not possible to produce such a group of three Mappings, then a * zero function value is returned, together with three NULL Mapping * pointers. All the mappings before the WcsMap are compounded together * and returned as "map1". The WcsMap itself is returned as "map2", and * any remaining Mappings are compounded together and returned as "map3". * * The search algorithm allows for an arbitrary combination of series and * parallel CmpMaps. * Parameters: * map * A pointer to the Mapping from pixel to physical coordinates. * invert * The value of the Invert attribute to use with "map" (the value * returned by astGetInvert is not used). * map1 * A location at which to return a pointer to the Mapping from pixel * to intermediate world coordinates. * map2 * A location at which to return a pointer to the Mapping from relative * physical coordinates to native spherical coordinates. This will * be a WcsMap, and it will have a non-zero FITSProj value. * map3 * A location at which to return a pointer to the Mapping from * native spherical coordinates to physical coordinates. * dep * The address of an integer holding the current depth of recursion * into this function. * status * Pointer to the inherited status variable. * Returned Value: * One if a suitable WcsMap was found, zero otherwise. * Notes: * - The returned Mappings contain independant copies of the relevant * components of the supplied Mapping and can be modified without * changing the supplied Mapping. * - NULL pointers will be returned for all Mappings if no WcsMap * with anon-zero FITSProj value can be found in the supplied Mapping. * - A pointer to a UnitMap will be returned for map1 if no mappings * exist before the WcsMap. * - A pointer to a UnitMap will be returned for map3 if no mappings * exist after the WcsMap. * - NULL pointers will be returned for all Mappings and a function * value of zero will be returned if an error has occurred, or if this * function should fail for any reason. * - "*map1" and "*map3" may contain WcsMaps, but they will have zero * values for their FITSProj values. */ /* Local Variables */ AstMapping **map_list; /* Mapping array pointer */ AstMapping *mapa; /* Pre-wcs Mapping */ AstWcsMap *mapb; /* WcsMap */ AstMapping *mapc; /* Post-wcs Mapping */ AstMapping *temp; /* Intermediate Mapping */ const char *class; /* Pointer to class of supplied Mapping */ double pv; /* Projection parameter value */ int *invert_list; /* Invert array pointer */ int axis; /* No. of axes in whole Mapping */ int axlat; /* Index of latitude axis */ int axlon; /* Index of longitude axis */ int haswcs; /* Was a usable inverted WcsMap found? */ int imap; /* Index of current Mapping in list */ int i; /* axis index */ int m; /* Parameter index */ int nax; /* No. of axes in Mapping */ int nmap; /* Number of Mappings in the list */ int ret; /* Was a non-linear Mapping found? */ int wcsaxis; /* Index of first WcsMap axis */ /* Initialise */ *map1 = NULL; *map2 = NULL; *map3 = NULL; ret = 0; /* Check the global status. */ if( !astOK ) return ret; /* Get the class of the Mapping. */ class = astGetClass( map ); /* If the supplied Mapping is a CmpMap... */ wcsaxis = -1; if( !strcmp( class, "CmpMap" ) ){ /* Decompose the Mapping into a sequence of Mappings to be applied in series and an associated list of Invert flags. */ map_list = NULL; invert_list = NULL; nmap = 0; astMapList( map, 1, invert, &nmap, &map_list, &invert_list ); /* If there is more than one Mapping, this must be a series CmpMap. */ if( nmap > 1 && astOK ){ /* Initialise the returned pre-wcs Mapping to be a UnitMap. */ if( invert == astGetInvert( map ) ){ *map1 = (AstMapping *) astUnitMap( astGetNin( map ), "", status ); } else { *map1 = (AstMapping *) astUnitMap( astGetNout( map ), "", status ); } /* Indicate we have not yet found a WcsMap. */ ret = 0; /* Process each series Mapping. */ for( imap = 0; imap < nmap; imap++ ){ /* If we have not yet found a WcsMap... */ if( !ret ){ /* Search this Mapping for a WcsMap. */ ret = SplitMap2( map_list[ imap ], invert_list[ imap ], &mapa, map2, map3, status ); /* If no WcsMap was found, use the whole mapping as part of the pre-wcs Mapping. */ if( !ret ){ mapa = astCopy( map_list[ imap ] ); astSetInvert( mapa, invert_list[ imap ] ); } /* Add the pre-wcs mapping to the cumulative pre-wcs CmpMap. */ temp = (AstMapping *) astCmpMap( *map1, mapa, 1, "", status ); *map1 = astAnnul( *map1 ); mapa = astAnnul( mapa ); *map1 = temp; /* If we have previously found a WcsMap, use the whole mapping as part of the post-wcs mapping. */ } else { mapc = astCopy( map_list[ imap ] ); astSetInvert( mapc, invert_list[ imap ] ); temp = (AstMapping *) astCmpMap( *map3, mapc, 1, "", status ); *map3 = astAnnul( *map3 ); mapc = astAnnul( mapc ); *map3 = temp; } } /* If there is only one Mapping, this must be a parallel CmpMap. */ } else { /* Annul the Mapping pointer in the series list created above, and free the dynamic arrays. */ map_list[ 0 ] = astAnnul( map_list[ 0 ] ); map_list = astFree( map_list ); invert_list = astFree( invert_list ); nmap = 0; /* Decompose the Mapping into a sequence of Mappings to be applied in parallel and an associated list of Invert flags. */ astMapList( map, 0, invert, &nmap, &map_list, &invert_list ); /* Process each parallel Mapping. */ axis = 0; for( imap = 0; imap < nmap && astOK; imap++ ){ /* See if this Mapping contains a usable WcsMap. Only do the search if no such WcsMap has already been found, since only the first is usable. */ if( !ret ) { /* Search this Mapping for a WcsMap. */ haswcs = SplitMap2( map_list[ imap ], invert_list[ imap ], &mapa, &mapb, &mapc, status ); /* Note if we have found a usable WcsMap, and its first axis index. */ if( haswcs ){ ret = 1; wcsaxis = axis; } /* If a WcsMap has already been found, the mapping cannot contain a usable WcsMap. */ } else { haswcs = 0; } /* If the Mapping did not contain a usable WcsMap, use the whole mapping as part of the pre-wcs Mapping, and create a UnitMap as part of the post-wcs mapping. */ if( !haswcs ){ mapa = astCopy( map_list[ imap ] ); astSetInvert( mapa, invert_list[ imap ] ); nax = astGetNout( mapa ); mapc = (AstMapping *) astUnitMap( nax, "", status ); } /* Increment the index of the first axis in the next Mapping. */ axis += astGetNout( mapa ); /* Add the pre-wcs mapping in parallel with the cumulative pre-wcs CmpMap. */ if( *map1 ){ temp = (AstMapping *) astCmpMap( *map1, mapa, 0, "", status ); *map1 = astAnnul( *map1 ); mapa = astAnnul( mapa ); *map1 = temp; } else { *map1 = mapa; } /* Add the post-wcs mapping in parallel with the cumulative post-wcs CmpMap. */ if( *map3 ){ temp = (AstMapping *) astCmpMap( *map3, mapc, 0, "", status ); *map3 = astAnnul( *map3 ); mapc = astAnnul( mapc ); *map3 = temp; } else { *map3 = mapc; } } /* If a usable WcsMap was found, create a new one which has all the same properties, but with enough axes to join the pre and post wcs Mappings together. Ensure the correct axes are used for longitude and latitude, and copy the projection parameters. */ if( ret ){ axlat = astGetWcsAxis( mapb, 1 ); axlon = astGetWcsAxis( mapb, 0 ); *map2 = astWcsMap( axis, astGetWcsType( mapb ), axlon + wcsaxis + 1, axlat + wcsaxis + 1, "", status ); for( i = 0; i < astGetNin( mapb ); i++ ){ for( m = 0; m < WCSLIB_MXPAR; m++ ){ if( astTestPV( mapb, i, m ) ) { pv = astGetPV( mapb, i, m ); if( pv != AST__BAD ) astSetPV( *map2, i + wcsaxis, m, pv ); } } } astInvert( *map2 ); mapb = astAnnul( mapb ); } } /* Loop to annul all the Mapping pointers in the list. */ for ( imap = 0; imap < nmap; imap++ ) map_list[ imap ] = astAnnul( map_list[ imap ] ); /* Free the dynamic arrays. */ map_list = astFree( map_list ); invert_list = astFree( invert_list ); /* If the supplied Mapping is not a CmpMap, see if it is a WcsMap with a non-zero FITSProj value. If so, take a copy and set its invert attribute correctly. Also create UnitMaps for the pre and post wcs mappings. */ } else if( astOK && !strcmp( class, "WcsMap" ) && astGetFITSProj( map ) ){ ret = 1; nax = astGetNin( map ); *map1 = (AstMapping *) astUnitMap( nax, "", status ); *map2 = astCopy( map ); astSetInvert( *map2, invert ); *map3 = (AstMapping *) astUnitMap( nax, "", status ); } /* If an error has occurred, or if no suitable WcsMap was found, annul any Mappings. */ if( !astOK || !ret ){ ret = 0; if( *map1 ) *map1 = astAnnul( *map1 ); if( *map2 ) *map2 = astAnnul( *map2 ); if( *map3 ) *map3 = astAnnul( *map3 ); } /* Return the answer. */ return ret; } static int SplitMat( int naxis, double *matrix, double *cdelt, int *status ){ /* * Name: * SplitMat * Purpose: * Factorises a single "CD"-style matrix into a diagonal CDELT matrix * and a "PC"-style matrix. * Type: * Private function. * Synopsis: * int SplitMat( int naxis, double *matrix, double *cdelt, int *status ) * Class Membership: * FitsChan * Description: * This function splits up the supplied CD matrix into separate PC and * CDELT matrices. The product of the returned matrices (CDELT.PC) * equals the supplied CD matrix. The CDELT values are chosen so that * the corresponding row of the PC matrix represents a unit vector. * The signs of the CDELT values are chosen so that the diagonal terms * of the PC matrix are all positive. * * Parameters: * naxis * The number of axes. * matrix * A pointer to an array of naxis*naxis elements. On entry this holds * the "CD" matrix. On exit, it is modified to represent the "PC" * matrix. * cdelt * A pointer to an array of naxis elements. On exit this holds the CDELT * values for each axis (i.e. the diagonal terms of the CDELT matrix). * status * Pointer to the inherited status variable. * Returned Value: * Zero is returned if any bad values are found in the supplied * matrix, or if an error has already occurred. One is returned otherwise. */ /* Local Variables: */ int i; int j; int ok; double *a; int dineg; double s2; double cdlt; /* Check the inherited status. */ if( !astOK ) return 0; /* Assume success. */ ok = 1; /* Loop round every row in the matrix. Get a pointer to the first element in the row. */ for( i = 0; i < naxis; i++ ){ a = matrix + i*naxis; /* Note the sign of the diagonal term (i.e. the i'th element) of this row. */ dineg = ( a[ i ] < 0.0 ); /* Get the magnitude of the vector represented by this row. This is the CDELT value for the row. BAD values cause the whole function to return. */ s2 = 0.0; for( j = 0; j < naxis; j++ ){ if( *a == AST__BAD ) { ok = 0; break; } s2 += (*a)*(*a); a++; } if( !ok ) break; cdlt = sqrt( MAX( 0.0, s2 ) ); /* If the diagonal term for this row of the matrix is negative, make the CDELT value negative instead. This means that the diagonal term in the final PC matrix will be positive. */ if( dineg ) cdlt = -cdlt; /* Store the CDELT value. */ cdelt[ i ] = cdlt; /* The row of the PC matrix is obtained by dividing the original row by the CDELT value. Set to zero any PC values which are less than 1.0E-7 (such values may be produced by rounding errors). */ a = matrix + i*naxis; for( j = 0; j < naxis; j++ ) { if( cdlt != 0.0 ){ *a /= cdlt; if( fabs( *a ) < 1.E-7 ) *a = 0.0; } else { *a = 0.0; } a++; } } return ok; } static void TableSource( AstFitsChan *this, void (* tabsource)( AstFitsChan *, const char *, int, int, int * ), int *status ){ /* *++ * Name: c astTableSource f AST_TABLESOURCE * Purpose: c Register a source function for accessing tables in FITS files. f Register a source routine for accessing tables in FITS files. * Type: * Public function. * Synopsis: c #include "fitschan.h" c void astTableSource( AstFitsChan *this, c void (* tabsource)( AstFitsChan *, const char *, c int, int, int * ) ) f CALL AST_TABLESOURCE( THIS, TABSOURCE, STATUS ) * Class Membership: * FitsChan member function. * Description: c This function can be used to register a call-back function f This routine can be used to register a call-back routine * with a FitsChan. The registered c function f routine * is called when-ever the FitsChan needs to read information from a * binary table contained within a FITS file. This occurs if the c astRead f AST_READ * function is invoked to read a FrameSet from a set of FITS headers * that use the "-TAB" algorithm to describe one or more axes. Such * axes use a FITS binary table to store a look-up table of axis values. * The FitsChan will fail to read such axes unless the "TabOK" attribute * is set to a non-zero positive integer value. The table containing the * axis values must be made available to the FitsChan either by storing * the table contents in the FitsChan (using c astPutTables or astPutTable) prior to invoking astRead f AST_PUTTABLES or AST_PUTTABLE) prior to invoking AST_READ * or by registering a call-back c function using astTableSource. f routine using AST_TABLESOURCE. * The first method is possibly simpler, but requires that the name of * the extension containing the table be known in advance. Since the * table name is embedded in the FITS headers, the name is often not * known in advance. If a call-back is registered, the FitsChan will * determine the name of the required table and invoke the call-back c function f routine * to supply the table at the point where it is needed (i.e. within c the astRead method). f the AST_READ method). * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c tabsource f TABSOURCE = SUBROUTINE (Given) c Pointer to the table source function to use. f The table source routine to use. * It takes five arguments - the first is a pointer to the * FitsChan, the second is a string holding the name of the * FITS extension containing the required binary table ("EXTNAME"), * the third is the integer FITS "EXTVER" header value for the * required extension, the fourth is the integer FITS "EXTLEVEL" * header value for the required extension, and the fifth is c a pointer to * the inherited integer status value. * * The call-back should read the entire contents (header and data) * of the binary table in the named extension of the external FITS * file, storing the contents in a newly created FitsTable object. It * should then store this FitsTable in the FitsChan using the c astPutTables or astPutTable f AST_PUTTABLES or AST_PUTTABLE * method, and finally annull its local copy of the FitsTable pointer. * If the table cannot be read for any reason, or if any other * error occurs, it should return a non-zero integer for the final * (third) argument. * c If "tabsource" is NULL, f If TABSOURCE is AST_NULL, * any registered call-back function will be removed. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: c - Application code can pass arbitrary data (such as file c descriptors, etc) to the table source function using the c astPutChannelData function. The source function should use c the astChannelData macro to retrieve this data. f - The name of the routine supplied for the TABSOURCE f argument should appear in an EXTERNAL statement in the Fortran f routine which invokes AST_TABLESOURCE. However, this is not generally f necessary for the null routine AST_NULL (so long as the AST_PAR f include file has been used). f - Note that the null routine AST_NULL (one underscore) is f different to AST__NULL (two underscores), which is the null Object f pointer. *-- */ /* Check the global error status. */ if ( !astOK ) return; /* Register the supplied source function, using the wrapper function appropriate for calling C table source functions. */ astSetTableSource( this, (void (*)( void )) tabsource, TabSourceWrap ); } static AstMapping *TabMapping( AstFitsChan *this, FitsStore *store, char s, int **tabaxis, const char *method, const char *class, int *status ) { /* * Name: * TabMapping * Purpose: * Create a Mapping that performs any -TAB look-ups for all WCS axes. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstMapping *TabMapping( AstFitsChan *this, FitsStore *store, char s, * int **tabaxis, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * This function returns a Mapping that has "nwcs" inputs and outputs, * where "nwcs" is the number of FITS WCS axes defined in the supplied * FitsStore. The inputs and outputs are in the same order as the * CTYPEi keywords in the FitsStore. The forward transformation of the * Mapping converts positions from the axes defined by the CRVALi keywords * to the WCS axes. This transformation will be a UnitMap except for * any axes that are described using the "-TAB" algorithm. For "-TAB" * axes, the transformation will implement the relevant coordinate * look-up function. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore structure holding the values to use for * the WCS keywords. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * tabaxis * Address of a location at which to store a pointer to an array of * flags, one for each output of the returned Mapping. A flag will * be non-zero if the corresponding output of the returned Mapping * corresponds to a -TAB axis. A NULL pointer is returned if the * returned Mapping is NULL. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to a Mapping. A NULL pointer is returned if the FitsChan does * not support the -TAB algorithm (i.e. if the value of the TabOK * attribute is zero or negative), or if no axes use the "-TAB" algorithm. */ /* Local Variables: */ AstFitsTable *table; AstKeyMap *used_tables; AstMapping *tmap1; AstMapping *tmap2; AstMapping *indexmap; AstMapping *tmap0; AstMapping *ret; AstPermMap *pm; char name[21]; const char *indexcol; const char *extname; const char *cval; const char *ctype; const char *coordscol; double dval; int *marray; int *permin; int *permout; int extlevel; int extver; int iaxis; int iiaxis; int ikey; int interp; int ival; int maxis; int mdim; int nkey; int nperm; int unit; int wcsaxes; /* Initialise */ ret = NULL; *tabaxis = NULL; extname = NULL; tmap0 = NULL; tmap2 = NULL; /* Check the global status. */ if( !astOK ) return ret; /* Obtain the number of physical axes in the header. If the WCSAXES header was specified, use it. Otherwise assume it is the same as the number of pixel axes. */ dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) { wcsaxes = (int) dval + 0.5; } else { wcsaxes = store->naxis; } /* If the FitsChan does not support the -TAB algorithm, return a NULL pointer. */ if( astGetTabOK( this ) > 0 ) { /* Create a KeyMap to hold a list of the used extension names. */ used_tables = astKeyMap( " ", status ); /* Allocate memory to indicate if each WCS axis is described by a -TAB algorithm or not. Initialiss it to zero. */ *tabaxis = astCalloc( wcsaxes, sizeof( int ) ); /* Allocate memory to hold the FITS-WCS axis index corresponding to each input of the "tmap0" Mapping. Indicate that as yet, not values are stored in this array. Also allocate memory for the inverse of this permutation array. */ permout = astMalloc( wcsaxes*sizeof( int ) ); permin = astMalloc( wcsaxes*sizeof( int ) ); nperm = 0; if( astOK ) { /* Initialise the permutation arrays. */ for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) { permout[ iaxis ] = permin[ iaxis ] = -1; } /* Otherwise, loop round all FITS WCS axis indices present in the FitsStore. */ for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) { /* If the current FITS WCS axis is already included in the returned Mapping, skip it. This will be the case if the axis uses the same coordinate array as an earlier axis since all FITS WCS axes associated with a coordinate array are processed together. */ if( permin[ iaxis ] == -1 ) { /* See if this WCS axis uses the -TAB algorithm. */ ctype = GetItemC( &(store->ctype), iaxis, 0, s, NULL, method, class, status ); if( ctype && !strncmp( ctype + 4, "-TAB", 4 ) ) { /* Get the name of the FITS binary table extension holding the coordinate info. No default, so report an error if not present. */ sprintf( name, "PS%d_0%c", iaxis + 1, s ); extname = GetItemC( &(store->ps), iaxis, 0, s, name, method, class, status ); /* Get the extension version and level. */ dval = GetItem( &(store->pv), iaxis, 1, s, NULL, method, class, status ); extver = ( dval != AST__BAD ) ? (int) dval : 1; dval = GetItem( &(store->pv), iaxis, 2, s, NULL, method, class, status ); extlevel = ( dval != AST__BAD ) ? (int) dval : 1; /* Get the FITS binary table. This will invoke any supplied table source function, and put a copy of the table into the FitsChan structure. Report an error if the table can not be obtained. */ table = GetNamedTable( this, extname, extver, extlevel, 1, method, status ); /* Add this extension name to a list of used extensions. */ astMapPut0I( used_tables, extname, 1, NULL ); /* Get the name of the table column containing the main coords array. No default so report error if not present. Report an error if the column is not present in the table. */ sprintf( name, "PS%d_1%c", iaxis + 1, s ); coordscol = GetItemC( &(store->ps), iaxis, 1, s, name, method, class, status ); if( !astHasColumn( table, coordscol ) && astOK ) { astError( AST__BADTAB, "%s(%s): Unable to find the " "coordinate array for FITS-WCS axis %d (type %s): " "column '%s' cannot be found in table '%s'.", status, method, class, iaxis + 1, ctype, coordscol, extname ); } /* Get the number of dimensions spanned by the coordinate array. Report an error if the coordinate array has only one axis (FITS-WCS paper III requires it to have at leats two axes). */ mdim = astGetColumnNdim( table, coordscol ); if( mdim == 1 && astOK ) { astError( AST__BADTAB, "%s(%s): Unable to use the " "coordinate array for FITS-WCS axis %d (type %s): " "column '%s' in table '%s' has one axis but at " "least two are required.", status, method, class, iaxis + 1, ctype, coordscol, extname ); } /* Allocate memory to hold the FITS-WCS axis corresponding to each dimension of the coordinate array. Initialise it to hold -1 (i.e. "no matching FITS-WCS axis yet found") at every element. */ marray = astMalloc( mdim*sizeof( int ) ); if( astOK ) { for( maxis = 0; maxis < mdim; maxis++ ) { marray[ maxis ] = -1; } /* Loop round each dimension of the coordinate array, storing the index of the corresponding FITS-WCS axis in "marray". We omit the first axis (axis 0) since FITS-WCS Paper III defines it is a "conventional" axis used to enumerate the planes of coordinate values. */ for( maxis = 1; maxis < mdim && astOK ; maxis++ ) { /* Each axis of the coordinate array (except axis 0) must have one, and only one, corresponding FITS-WCS axis. Check each FITS-WCS axis to find one that uses the same table and column as the "iaxis" axis, and which corresponds to axis "maxis" of the coordinate array. */ for( iiaxis = 0; iiaxis < wcsaxes; iiaxis++ ) { cval = GetItemC( &(store->ps), iiaxis, 0, s, NULL, method, class, status ); if( cval && !strcmp( cval, extname ) ) { cval= GetItemC( &(store->ps), iiaxis, 1, s, NULL, method, class, status ); if( cval && !strcmp( cval, coordscol ) ) { dval = GetItem( &(store->pv), iiaxis, 3, s, NULL, method, class, status ); if( dval != AST__BAD ) { ival = (int)( dval + 0.5 ); } else { ival = 1; } if( ival == maxis ) { /* Arrive here if the "iiaxis" FITS-WCS axis uses the same table and column as "iaxis", and corresponds to the "maxis" axis in the coordinate array. If this is the first matching FITS-WCS axis, store its index. */ if( marray[ maxis ] == -1 ) { marray[ maxis ] = iiaxis; /* If a matching FITS-WCS axis has already been found, report an error. */ } else if( astOK ) { astError( AST__BADTAB, "%s(%s): Unable to use " "the coordinate array for FITS-WCS " "axis %d (type %s): more than one " "intermediate WCS axis is mapped onto " " dimension %d of the coordinate " "array in column '%s' of table '%s'.", status, method, class, iaxis + 1, ctype, maxis, coordscol, extname ); } } } } } } /* Check that every dimension of the coordinate array (except the first) has a corresponding FITS-WCS axis. */ for( maxis = 1; maxis < mdim && astOK ; maxis++ ) { if( marray[ maxis ] == -1 ) { astError( AST__BADTAB, "%s(%s): Unable to use the " "coordinate array for FITS-WCS axis %d (type " "%s): no intermediate WCS axis is mapped onto " " dimension %d of the coordinate array in column " " '%s' of table '%s'.", status, method, class, iaxis + 1, ctype, maxis, coordscol, extname ); } } /* Now we know which FITS-WCS axis corresponds to each dimension of the coordinate array. We now need to form a parallel CmpMap (compound Mapping) by gathering together the indexing vectors for each dimension of the coordinates array. Each indexing vector is represented by an inverted 1D LutMap - dimensions that do not have an indexing vector are represented using a UnitMap. */ indexmap = NULL; unit = 1; for( maxis = 1; maxis < mdim && astOK ; maxis++ ) { /* Get the name of the column containing the index array. Defaults is to use a unit index, so do not report an error if not present. */ indexcol = GetItemC( &(store->ps), marray[ maxis ], 2, s, NULL, method, class, status ); /* If the table contains an index vector, create a LutMap from it, then invert it. */ if( indexcol ) { tmap1 = MakeColumnMap( table, indexcol, 1, 0, method, class, status ); astInvert( tmap1 ); unit = 0; /* If the table does not contain an index vector, use a UnitMap. */ } else { tmap1 = (AstMapping *) astUnitMap( 1, " ", status ); } /* Combine the index Mapping for this dimension in parallel with the Mapping for all earlier dimensions. */ if( indexmap ) { tmap2 = (AstMapping *) astCmpMap( indexmap, tmap1, 0, " ", status ); indexmap = astAnnul( indexmap ); tmap1 = astAnnul( tmap1 ); indexmap = tmap2; } else { indexmap = tmap1; } } /* Get the interpolation method to use for the main coordinate array. This is an extension to the published -TAB algorithm in which the QVi_4a keyword is assumed to hold zero for linear interpolation (the default) and non-zero for nearest neighbour interpolation. The QVi_4a keyword will be translated to PVi_4a by the SpecTrans function. */ dval = GetItem( &(store->pv), iaxis, 4, s, NULL, method, class, status ); if( dval != AST__BAD ) { interp = (int)( dval + 0.5 ); } else { interp = 0; } /* Make a Mapping from the main coordinate array, and then if required append it in series to the end of the index Mapping created above. */ tmap1 = MakeColumnMap( table, coordscol, 0, interp, method, class, status ); if( ! unit ) { tmap2 = (AstMapping *) astCmpMap( indexmap, tmap1, 1, " ", status ); } else { tmap2 = astClone( tmap1 ); } indexmap = astAnnul( indexmap ); tmap1 = astAnnul( tmap1 ); /* Extend the array that holds the zero-based FITS-WCS axis index corresponding to each input of the extended "tmap0" mapping. Also create the inverse permutation (i.e. zero-based "tmap0" input indexed by zero-based FITS-WCS axis index). */ for( maxis = 1; maxis < mdim; maxis++ ) { permout[ nperm ] = marray[ maxis ]; permin[ marray[ maxis ] ] = nperm++; } /* Free resources. */ marray = astFree( marray ); } /* Annul the table pointer. */ table = astAnnul( table ); /* Clear the CTYPE algorithm code to indicate that the axis should be considered to be linear from now on. This means that the following functions will create a Mapping from pixel to psi (the system in which the CRVAL values are defined when using -TAB). The psi axes will then be mapping into the CS axes using the Mappign returned by this function. */ strncpy( name, ctype, 4 ); strcpy( name + 4, ctype + 8 ); SetItemC( &(store->ctype), iaxis, 0, s, name, status ); /* Set the returned flag for this axis. */ (*tabaxis)[ iaxis ] = 1; /* If the FITS WCS axis "iaxis" does not use a -TAB algorithm, describe it in the returned Mapping using a 1D UnitMap. */ } else { tmap2 = (AstMapping *) astUnitMap( 1, " ", status ); /* Extend the array that holds the zero-based FITS-WCS axis index corresponding to each input of the extended "tmap0" mapping. Also create the inverse permutation (i.e. zero-based "tmap0" input indexed by zero-based FITS-WCS axis index). */ permout[ nperm ] = iaxis; permin[ iaxis ] = nperm++; } /* Append the Mapping describing the FITS WCS axis "iaxis" in parallel to any Mappings created for earlier "iaxis" axes. */ if( tmap0 ) { tmap1 = (AstMapping *) astCmpMap( tmap0, tmap2, 0, " ", status ); tmap0 = astAnnul( tmap0 ); tmap2 = astAnnul( tmap2 ); tmap0 = tmap1; } else { tmap0 = tmap2; } } } /* If no -TAB axes were found, just return a NULL pointer. */ if( extname && astOK ) { /* Do a sanity check on the permutation arrays. */ for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) { if( permin[ iaxis ] < 0 || permin[ iaxis ] >= wcsaxes || permout[ permin[ iaxis ] ] != iaxis ) { astError( AST__INTER, "%s(%s): Invalid permutation " "arrays in function TabMapping (internal AST " "progranmming error).", status, method, class ); break; } } /* Sandwich the "tmap0" Mapping in series between two PermMaps to create a Mapping in which the inputs and outputs correspond to FITS WCS axis numbering. */ pm = astPermMap( wcsaxes, permin, wcsaxes, permout, NULL, " ", status ); tmap1 = (AstMapping *) astCmpMap( pm, tmap0, 1, " ", status ); astInvert( pm ); tmap2 = (AstMapping *) astCmpMap( tmap1, pm, 1, " ", status ); pm = astAnnul( pm ); tmap1 = astAnnul( tmap1 ); /* Simplify the returned Mapping. */ ret = astSimplify( tmap2 ); tmap2 = astAnnul( tmap2 ); } /* Free remaining resources */ tmap0 = astAnnul( tmap0 ); } permout = astFree( permout ); permin = astFree( permin ); /* Remove all used tables from the FitsChan now that they have been used. */ nkey = astMapSize( used_tables ); for( ikey = 0; ikey < nkey; ikey++ ) { astRemoveTables( this, astMapKey( used_tables, ikey ) ); } /* Delete the KeyMap holding the used table names. */ used_tables = astAnnul( used_tables ); /* If we are not returning a Mapping, ensure we do not return any axis flags either. */ if( !ret ) *tabaxis = astFree( *tabaxis ); } /* Return the result */ return ret; } static void TabSourceWrap( void (*tabsource)( void ), AstFitsChan *this, const char *extname, int extver, int extlevel, int *status ){ /* * Name: * TabSourceWrap * Purpose: * Wrapper function to invoke the C table source function. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void TabSourceWrap( void (*tabsource)( void ), * AstFitsChan *this, const char *extname, * int extver, int extlevel, int *status ) * Class Membership: * Channel member function. * Description: * This function invokes the table source function whose pointer is * supplied in order to read a named FITS binary table from an external * FITS file. * Parameters: * tabsource * Pointer to the C tab source function. * this * Pointer to the FitsChan. The reference count for the FitsChan is * decremented by this function (this behaviour is imposed by * restrictions in the equivalent Fortran wrapper function). * extname * Pointer to the string holding the name of the FITS extension * from which a table is to be read. * extver * The integer "EXTVER" value for the required extension. * extlevel * The integer "EXTLEVEL" value for the required extension. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFitsChan *this_id; int lstat; /* Check the global error status. */ if ( !astOK ) return; /* Get an external identifier for the FitsChan. Could use astClone here to avoid this function anulling the supplied pointer, but the F77 wrapper cannot use the protected version of astClone, so for consistency we do not use it here either. */ this_id = astMakeId( this ); /* Invoke the table source function (casting it to the C API first) to read the table, and store it in the FitsChan. */ ( *( void (*)( struct AstFitsChan *, const char *, int, int, int * ) )tabsource )( this_id, extname, extver, extlevel, &lstat ); /* Free the FitsChan identifier (this annuls the supplied "this" pointer). */ this_id = astAnnulId( this_id ); /* Report an error if the source function failed. */ if( !lstat ) { astError( AST__NOTAB, "astRead(%s): The table source function failed to read " "a binary table from extension %s in an external FITS file.", status, astGetClass( this ), extname ); } } static double TDBConv( double mjd, int timescale, int fromTDB, const char *method, const char *class, int *status ){ /* * Name: * TDBConv * Purpose: * Convert an MJD between the TDB time scale and another timescale. * Type: * Private function. * Synopsis: * double TDBConv( double mjd, int timescale, int fromTDB, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function converts the supplied mjd value to or from the TDB * timescale. * Parameters: * mjd * The input MJD value. * timescale * The other timescale. * fromTDB * Indicates the direction of the required conversion. If non-zero, * the supplied "mjd" value should be in the TDB timescale, and the * returned value will be in the timescale specified by "timescale". * If zero, the supplied "mjd" value should be in the timescale * specified by "timescale", and the returned value will be in the * TDB timescale. * method * The calling method. Used only in error messages. * class * The object class. Used only in error messages. * status * Pointer to the inherited status variable. * Returned Value: * The converted MJD value, or AST__BAD if an error occurs. */ /* Local Variables: */ AstFrameSet *fs; /* Mapping from supplied timescale to TDB */ double ret; /* The returned value */ /* Initialise */ ret = AST__BAD; /* Check inherited status and supplied TDB value. */ if( !astOK || mjd == AST__BAD ) return ret; /* Return the supplied value if no conversion is needed. */ if( timescale == AST__TDB ) { ret = mjd; /* Otherwise, do the conversion. */ } else { /* Lock the timeframes for use by the current thread, waiting if they are currently locked by another thread. */ astManageLock( timeframe, AST__LOCK, 1, NULL ); astManageLock( tdbframe, AST__LOCK, 1, NULL ); /* Set the required timescale. */ astSetTimeScale( timeframe, timescale ); /* Get the Mapping between the two timescales, and use it to convert the suipplied value. */ fs = astConvert( tdbframe, timeframe, "" ); astTran1( fs, 1, &mjd, fromTDB, &ret ); fs = astAnnul( fs ); /* Unlock the timeframes. */ astManageLock( timeframe, AST__UNLOCK, 1, NULL ); astManageLock( tdbframe, AST__UNLOCK, 1, NULL ); } /* Return the result */ return ret; } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int TestAttrib( AstObject *this, const char *attrib, int *status ) * Class Membership: * FitsChan member function (over-rides the astTestAttrib protected * method inherited from the Channel class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a FitsChan's attributes. * Parameters: * this * Pointer to the FitsChan. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Card. */ /* ----- */ if ( !strcmp( attrib, "card" ) ) { result = astTestCard( this ); /* Encoding. */ /* --------- */ } else if ( !strcmp( attrib, "encoding" ) ) { result = astTestEncoding( this ); /* FitsDigits. */ /* ----------- */ } else if ( !strcmp( attrib, "fitsdigits" ) ) { result = astTestFitsDigits( this ); /* DefB1950. */ /* --------- */ } else if ( !strcmp( attrib, "defb1950" ) ) { result = astTestDefB1950( this ); /* TabOK. */ /* ------ */ } else if ( !strcmp( attrib, "tabok" ) ) { result = astTestTabOK( this ); /* CDMatrix. */ /* --------- */ } else if ( !strcmp( attrib, "cdmatrix" ) ) { result = astTestCDMatrix( this ); /* CarLin. */ /* --------- */ } else if ( !strcmp( attrib, "carlin" ) ) { result = astTestCarLin( this ); /* PolyTan */ /* ------- */ } else if ( !strcmp( attrib, "polytan" ) ) { result = astTestPolyTan( this ); /* Iwc. */ /* ---- */ } else if ( !strcmp( attrib, "iwc" ) ) { result = astTestIwc( this ); /* Clean. */ /* ------ */ } else if ( !strcmp( attrib, "clean" ) ) { result = astTestClean( this ); /* Warnings. */ /* -------- */ } else if ( !strcmp( attrib, "warnings" ) ) { result = astTestWarnings( this ); /* If the name is not recognised, test if it matches any of the read-only attributes of this class. If it does, then return zero. */ } else if ( !strcmp( attrib, "ncard" ) || !strcmp( attrib, "nkey" ) || !strcmp( attrib, "cardtype" ) || !strcmp( attrib, "cardcomm" ) || !strcmp( attrib, "cardname" ) || !strcmp( attrib, "allwarnings" ) ){ result = 0; /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static int TestCard( AstFitsChan *this, int *status ){ /* *+ * Name: * astTestCard * Purpose: * Test the Card attribute. * Type: * Protected virtual function. * Synopsis: * #include "fitschan.h" * int astTestCard( AstFitsChan *this ) * Class Membership: * FitsChan method. * Description: * This function tests the Card attribute for the supplied FitsChan. * Parameters: * this * Pointer to the FitsChan. * Returned Value: * If the Card attribute has its "cleared" value (i.e. if the first card * in the FitsChan will be the next one to be read), then zero is returned, * otherwise 1 is returned. *- */ /* Local Variables: */ int card; /* The original value of Card */ int ret; /* The returned flag */ /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Get the current value of Card. */ card = astGetCard( this ); /* Temporarily clear Card. */ astClearCard( this ); /* See if the original Card is equal to the cleared card, and set the returned flag appropriately. Re-instate the original value of card is required.*/ if( astGetCard( this ) == card ) { ret = 0; } else { astSetCard( this, card ); ret = 1; } /* Return the flag. */ return ret; } static int TestFits( AstFitsChan *this, const char *name, int *there, int *status ){ /* *++ * Name: c astTestFits f AST_TESTFITS * Purpose: * See if a named keyword has a defined value in a FitsChan. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c int astTestFits( AstFitsChan *this, const char *name, int *there ) f RESULT = AST_TESTFITS( THIS, NAME, THERE, STATUS ) * Class Membership: * FitsChan method. * Description: * This function serches for a named keyword in a FitsChan. If found, * and if the keyword has a value associated with it, a c non-zero f .TRUE. * value is returned. If the keyword is not found, or if it does not * have an associated value, a c zero f .FALSE. * value is returned. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. c name f NAME = CHARACTER * ( * ) (Given) c Pointer to a null-terminated character string f A character string * containing the FITS keyword name. This may be a complete FITS * header card, in which case the keyword to use is extracted from * it. No more than 80 characters are read from this string. c there f THERE = LOGICAL (Returned) c Pointer to an integer which will be returned holding a non-zero c value if the keyword was found in the header, and zero otherwise. f A value of .TRUE. will be returned if the keyword was found in the f header, and .FALSE. otherwise. * This parameter allows a distinction to be made between the case * where a keyword is not present, and the case where a keyword is * present but has no associated value. c A NULL pointer may be supplied if this information is not c required. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astTestFits() f AST_TESTFITS = LOGICAL * A value of zero f .FALSE. * is returned if the keyword was not found in the FitsChan or has * no associated value. Otherwise, a value of c one f .TRUE. * is returned. * Notes: * - The current card is left unchanged by this function. * - The card following the current card is checked first. If this is * not the required card, then the rest of the FitsChan is searched, * starting with the first card added to the FitsChan. Therefore cards * should be accessed in the order they are stored in the FitsChan (if * possible) as this will minimise the time spent searching for cards. * - An error will be reported if the keyword name does not conform * to FITS requirements. c - Zero f - .FALSE. * is returned as the function value if an error has already occurred, * or if this function should fail for any reason. *-- */ /* Local Variables: */ const char *class; /* Object class */ const char *method; /* Calling method */ char *lcom; /* Supplied keyword comment */ char *lname; /* Supplied keyword name */ char *lvalue; /* Supplied keyword value */ int icard; /* Current card index on entry */ int ret; /* The returned value */ /* Initialise */ if( there ) *there = 0; /* Check the global error status. */ if ( !astOK ) return 0; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the calling method and object class. */ method = "astTestFits"; class = astGetClass( this ); /* Initialise the returned value. */ ret = 0; /* Extract the keyword name from the supplied string. */ (void) Split( name, &lname, &lvalue, &lcom, method, class, status ); /* Store the current card index. */ icard = astGetCard( this ); /* Attempt to find a card in the FitsChan refering to this keyword, and make it the current card. Only proceed if a card was found. */ if( SearchCard( this, lname, method, class, status ) ){ /* Indicate the card has been found. */ if( there ) *there = 1; /* If the cards data type is no undefined, return 1. */ if( CardType( this, status ) != AST__UNDEF ) ret = 1; } /* Re-instate the original current card index. */ astSetCard( this, icard ); /* Release the memory used to hold keyword name, value and comment strings. */ lname = (char *) astFree( (void *) lname ); lvalue = (char *) astFree( (void *) lvalue ); lcom = (char *) astFree( (void *) lcom ); /* Return the answer. */ return ret; } static void TidyOffsets( AstFrameSet *fset, int *status ) { /* * Name: * TidyOffsets * Purpose: * Remove un-needed offset coordinate Frames. * Type: * Private function. * Synopsis: * void TidyOffsets( AstFrameSet *fset, int *status ) * Class Membership: * FitsChan * Description: * A FITS header stores offset sky coordinates as two alternaive axis * descriptions - one giving the offset axes and one giving the absolute * axes. But AST can hold both forms in a single SkyFrame. This function * removes the FITS Frames describing offset axes from the FrameSet. * The remaining absolute Frame is then used to describe both absolute * and offset. * Parameters: * fset * A FrameSet holding the Frames read from a FITS-WCS Header. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstFrame *frm; AstFrame *pfrm; const char *dom; const char *skyrefis; int hasabs; int hasoff; int iax; int icurr; int icurr_is_offset; int ifrm; int nax; int nfrm; int pax; int remove; /* Check the inherited status. */ if( !astOK ) return; /* Note the original current Frame index. */ icurr = astGetCurrent( fset ); /* Assume the current Frame is not an offset frame until proven otherwise. */ icurr_is_offset = 0; /* Does the FrameSet contain any Frames holding sky offsets? Such Frames should have been given a Domain of SKY_OFFSETS within function WcsSkyFrame. Loop round all Frames, checking each one. Also note if the FrameSet contains any (absolute) SKY frames. Also set the SkyRefIs attribute for any absolute SkyFrames that were marked with domains SKY_POLE or SKY_OFFSET in WcsSkyFrame. */ hasabs = 0; hasoff = 0; nfrm = astGetNframe( fset ); for( ifrm = 1; ifrm <= nfrm; ifrm++ ){ skyrefis = NULL; frm = astGetFrame( fset, ifrm ); nax = astGetNaxes( frm ); for( iax = 0; iax < nax; iax++ ) { astPrimaryFrame( frm, iax, &pfrm, &pax ); if( astIsASkyFrame( pfrm ) ) { dom = astGetDomain( pfrm ); if( dom ) { if( !strcmp( dom, "SKY_OFFSETS" ) ){ hasoff = 1; if( ifrm == icurr ) icurr_is_offset = 1; iax = nax; } else if( !strcmp( dom, "SKY" ) ){ hasabs = 1; iax = nax; } else if( !strcmp( dom, "SKY_POLE" ) ){ hasabs = 1; skyrefis = "POLE"; iax = nax; } else if( !strcmp( dom, "SKY_ORIGIN" ) ){ hasabs = 1; skyrefis = "ORIGIN"; iax = nax; } } } pfrm = astAnnul( pfrm ); } frm = astAnnul( frm ); if( skyrefis ) { astSetI( fset, "Current", ifrm); astSetC( fset, "SkyRefIs", skyrefis ); astSetI( fset, "Current", icurr ); } } /* If one or more absolute sky frames were found, then remove any offset sky frames. Clear the Ident attribute (that holds the FITS-WCS alternate axis description character) for any absoute Frames. */ if( hasabs && hasoff ) { for( ifrm = nfrm; ifrm > 0; ifrm-- ) { remove = 0; frm = astGetFrame( fset, ifrm ); nax = astGetNaxes( frm ); for( iax = 0; iax < nax; iax++ ) { astPrimaryFrame( frm, iax, &pfrm, &pax ); if( astIsASkyFrame( pfrm ) ) { dom = astGetDomain( pfrm ); if( dom ) { if( !strcmp( dom, "SKY_OFFSETS" ) ){ remove = 1; iax = nax; } else if( !strcmp( dom, "SKY_POLE" ) || !strcmp( dom, "SKY_ORIGIN" ) ){ astClearIdent( frm ); astClearDomain( pfrm ); /* If we will be deleting the original current Frame (because it is an offset Frame), then mark the first absolute Frame as the new current Frame. */ if( icurr_is_offset ) { astSetCurrent( fset, ifrm ); icurr_is_offset = 0; } iax = nax; } } } pfrm = astAnnul( pfrm ); } frm = astAnnul( frm ); if( remove ) astRemoveFrame( fset, ifrm ); } } } static AstTimeScaleType TimeSysToAst( AstFitsChan *this, const char *timesys, const char *method, const char *class, int *status ){ /* * Name: * TimeSysToAst * Purpose: * Convert a FITS TIMESYS value to an AST TimeFrame timescale value. * Type: * Private function. * Synopsis: * AstTimeScaleType TimeSysToAst( AstFitsChan *this, const char *timesys, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function returns the value used by the AST TimeFrame class to * represent the timescale specified by the "timesys" parameter, which * should hold the value of a FITS TIMESYS keyword. The TIMESYS * convention was introduced as part of the Y2K DATE-OBS changes, and * is not currently part of the published FITS-WCS conventions. * * If the requested timescale is not supported by AST, then a warning is * added to the FitsChan and a value of AST__UTC is returned (but no * error is reported). * Parameters: * this * Pointer to the FitsChan. * timesys * Pointer to the string holding the TIMESYS value. A NULL pointer * returns the default timescale of UTC. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * The equivalent AstTimeScaleType value. */ /* Local Variables: */ AstTimeScaleType result; /* The returned timescale */ char buf[ 200 ]; /* Buffer for warning message */ /* Initialise */ result = AST__UTC; /* Check the inherited status. */ if( !astOK ) return result; if( !timesys ) { result = AST__UTC; } else if( !strcmp( timesys, "UTC" ) ) { result = AST__UTC; } else if( !strcmp( timesys, "UT" ) ) { result = AST__UTC; Warn( this, "badval", "The original FITS header contained a value of UT " "for keyword TIMESYS which is being interpreted as UTC.", method, class, status ); } else if( !strcmp( timesys, "TAI" ) ) { result = AST__TAI; } else if( !strcmp( timesys, "IAT" ) ) { result = AST__TAI; } else if( !strcmp( timesys, "ET" ) ) { result = AST__TT; Warn( this, "badval", "The original FITS header contained a value of ET " "for keyword TIMESYS. TT will be used instead.", method, class, status ); } else if( !strcmp( timesys, "TT" ) ) { result = AST__TT; } else if( !strcmp( timesys, "TDT" ) ) { result = AST__TT; } else if( !strcmp( timesys, "TDB" ) ) { result = AST__TDB; } else if( !strcmp( timesys, "TCG" ) ) { result = AST__TCG; } else if( !strcmp( timesys, "TCB" ) ) { result = AST__TCB; } else { result = AST__UTC; sprintf( buf, "The original FITS header contained a value of %s for " "keyword TIMESYS. AST does not support this timescale so " "UTC will be used instead.", timesys ); Warn( this, "badval", buf, method, class, status ); } /* Return the result */ return result; } static char *UnPreQuote( const char *string, int *status ) { /* * Name: * UnPreQuote * Purpose: * Reverse the pre-quoting of FITS character data. * Type: * Private function. * Synopsis: * #include "fitschan.h" * char *UnPreQuote( const char *string, int *status ) * Class Membership: * FitsChan member function. * Description: * This function reverses the effect of the PreQuote function on a * string (apart from any loss of data due to truncation). It * should be used to recover the original character data from the * pre-quoted version of a string retrieved from a FITS character * value associated with a keyword. * Parameters: * string * Pointer to a constant null-terminated string containing the * pre-quoted character data. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to a dynamically allocated null-terminated string * containing the un-quoted character data. The memory holding this * string should be freed by the caller (using astFree) when no * longer required. * Notes: * - A NULL pointer value will be returned if this function is * invoked wth the global error status set, or if it should fail * for any reason. */ /* Local Variables: */ char *result; /* Pointer value to return */ int i1; /* Offset of first useful character */ int i2; /* Offest of last useful character */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Initialise to use the first and last characters in the input string. */ i1 = 0; i2 = strlen( string ) - 1; /* If the string contains at least 2 characters, check if the first and last characters are double quotes ("). If so, adjust the offsets to exclude them. */ if ( ( i2 > i1 ) && ( string[ i1 ] == '"' ) && ( string[ i2 ] == '"' ) ) { i1++; i2--; } /* Make a dynamically allocated copy of the useful part of the string. */ result = astString( string + i1, i2 - i1 + 1 ); /* Return the answer. */ return result; } static int Use( AstFitsChan *this, int set, int helpful, int *status ) { /* * Name: * Use * Purpose: * Decide whether to write a value to a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Use( AstFitsChan *this, int set, int helpful, int *status ) * Class Membership: * FitsChan member function. * Description: * This function decides whether a value supplied by a class "Dump" * function, via a call to one of the astWrite... protected * methods, should actually be written to a FitsChan. * * This decision is based on the settings of the "set" and * "helpful" flags supplied to the astWrite... method, plus the * attribute settings of the FitsChan. * Parameters: * this * A pointer to the FitsChan. * set * The "set" flag supplied. * helpful * The "helpful" value supplied. * status * Pointer to the inherited status variable. * Returned Value: * One if the value should be written out, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global error status set or if it should fail for any * reason. */ /* Local Variables: */ int full; /* Full attribute value */ int result; /* Result value to be returned */ /* Check the global error status. */ if ( !astOK ) return 0; /* If "set" is non-zero, then so is the result ("set" values must always be written out). */ result = ( set != 0 ); /* Otherwise, obtain the value of the FitsChan's Full attribute. */ if ( !set ) { full = astGetFull( this ); /* If Full is positive, display all values, if zero, display only "helpful" values, if negative, display no (un-"set") values. */ if ( astOK ) result = ( ( helpful && ( full > -1 ) ) || ( full > 0 ) ); } /* Return the result. */ return result; } static int Ustrcmp( const char *a, const char *b, int *status ){ /* * Name: * Ustrcmp * Purpose: * A case blind version of strcmp. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Ustrcmp( const char *a, const char *b, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns 0 if there are no differences between the two strings, and 1 * otherwise. Comparisons are case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference between * the two strings, whereas "strcmp" does. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Loop round each character. */ while( 1 ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } static int Ustrncmp( const char *a, const char *b, size_t n, int *status ){ /* * Name: * Ustrncmp * Purpose: * A case blind version of strncmp. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Ustrncmp( const char *a, const char *b, size_t n, int *status ) * Class Membership: * FitsChan member function. * Description: * Returns 0 if there are no differences between the first "n" * characters of the two strings, and 1 otherwise. Comparisons are * case blind. * Parameters: * a * Pointer to first string. * b * Pointer to second string. * n * The maximum number of characters to compare. * status * Pointer to the inherited status variable. * Returned Value: * Zero if the strings match, otherwise one. * Notes: * - This function does not consider the sign of the difference between * the two strings, whereas "strncmp" does. * - This function attempts to execute even if an error has occurred. */ /* Local Variables: */ const char *aa; /* Pointer to next "a" character */ const char *bb; /* Pointer to next "b" character */ int i; /* Character index */ int ret; /* Returned value */ /* Initialise the returned value to indicate that the strings match. */ ret = 0; /* Initialise pointers to the start of each string. */ aa = a; bb = b; /* Compare up to "n" characters. */ for( i = 0; i < (int) n; i++ ){ /* We leave the loop if either of the strings has been exhausted. */ if( !(*aa ) || !(*bb) ){ /* If one of the strings has not been exhausted, indicate that the strings are different. */ if( *aa || *bb ) ret = 1; /* Break out of the loop. */ break; /* If neither string has been exhausted, convert the next characters to upper case and compare them, incrementing the pointers to the next characters at the same time. If they are different, break out of the loop. */ } else { if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ ret = 1; break; } } } /* Return the result. */ return ret; } static void Warn( AstFitsChan *this, const char *condition, const char *text, const char*method, const char *class, int *status ){ /* * Name: * Warn * Purpose: * Store warning cards in a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Warn( AstFitsChan *this, const char *condition, const char *text, * const char*method, const char *class, int *status ); * Class Membership: * FitsChan member function. * Description: * If the Warnings attribute indicates that occurences of the specified * condition should be reported, the supplied text is split into lines * and stored in the FitsChan as a series of ASTWARN cards, in front * of the current card. If the specified condition is not being reported, * this function returns without action. * Parameters: * this * The FitsChan. If NULL, this function returns without action. * condition * Pointer to a string holding a lower case condition name. * text * Pointer to a string holding the text of the warning. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char buff[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for new card text */ const char *a; /* Pointer to 1st character in next card */ const char *b; /* Pointer to terminating null character */ const char *c; /* Pointer to last character in next card */ int exists; /* Has the supplied warning already been issued? */ int icard; /* Index of original card */ int nc; /* No. of characters in next card */ /* Check the inherited status, warning text, FitsChan and Clean attribute. */ if( !astOK || !text || !text[0] || !this || astGetClean( this ) ) return; /* Ignore the warning if the supplied condition is not contained within the list of conditions to be reported in this way (given by the Warnings attribute). */ if( FullForm( astGetWarnings( this ), condition, 0, status ) >= 0 ){ /* If found, store the warning in the parent Channel structure. */ astAddWarning( this, 1, "%s", method, status, text ); /* For historical reasons, warnings are also stored in the FitsChan as a set of FITS cards... First save the current card index, and rewind the FitsChan. */ icard = astGetCard( this ); astClearCard( this ); /* Break the supplied text into lines and check the FitsChan to see if a block of adjacent ASTWARN cards with these lines already exist within the FitsChan. Assume they do until proven otherwise. */ exists = 1; a = text; b = a + strlen( text ); while( a < b ){ /* Each card contains about 60 characters of the text. Get a pointer to the nominal last character in the next card. */ c = a + 60; /* If this puts the last character beyond the end of the text, use the last character before the null as the last character in the card. */ if( c >= b ) { c = b - 1; /* Otherwise, if the last character is not a space, move the last character backwards to the first space. This avoids breaking words across cards. */ } else { while( !isspace( *c ) && c > a ) c--; } /* Copy the text into a null terminated buffer. */ nc = c - a + 1; strncpy( buff, a, nc ); buff[ nc ] = 0; /* If this is the first line, search the entire FitsChan for an ASTWARN card with this text. If not, indiate that the supplied text needs to be stored in the FitsChan, and break out of the loop. */ if( a == text ) { exists = 0; while( !exists && FindKeyCard( this, "ASTWARN", method, class, status ) ) { if( !strcmp( (const char *) CardData( this, NULL, status ), buff ) ) { exists = 1; } MoveCard( this, 1, method, class, status ); } if( !exists ) break; /* If this is not the first line, see if the next card in the FitsChan is an ASTWARN card with this text. If not, indiate that the supplied text needs to be stored in the FitsChan, and break out of the loop. */ } else { if( !strcmp( CardName( this, status ), "ASTWARN" ) && !strcmp( (const char *) CardData( this, NULL, status ), buff ) ) { MoveCard( this, 1, method, class, status ); } else { exists = 0; break; } } /* Set the start of the next bit of the text. */ a = c + 1; } /* Reinstate the original current card index. */ astSetCard( this, icard ); /* We only add new cards to the FitsChan if they do not already exist. */ if( !exists ) { /* Break the text into lines using the same algorithm as above, and store each line as a new ASTWARN card. Start with a blank ASTWARN card. */ astSetFitsS( this, "ASTWARN", " ", NULL, 0 ); /* Loop until the entire text has been written out. */ a = text; b = a + strlen( text ); while( a < b ){ /* Each card contains about 60 characters of the text. Get a pointer to the nominal last character in the next card. */ c = a + 60; /* If this puts the last character beyond the end of the text, use the last character before the null as the last character in the card. */ if( c >= b ) { c = b - 1; /* Otherwise, if the last character is not a space, move the last character backwards to the first space. This avoids breaking words across cards. */ } else { while( !isspace( *c ) && c > a ) c--; } /* Copy the text into a null terminated buffer. */ nc = c - a + 1; strncpy( buff, a, nc ); buff[ nc ] = 0; /* Store the buffer as the next card. */ astSetFitsS( this, "ASTWARN", buff, NULL, 0 ); /* Set the start of the next bit of the text. */ a = c + 1; } /* Include a final blank card. */ astSetFitsS( this, "ASTWARN", " ", NULL, 0 ); } } } static int WATCoeffs( const char *watstr, int iaxis, double **cvals, int **mvals, int *ok, int *status ){ /* * Name: * WATCoeffs * Purpose: * Get the polynomial coefficients from the lngcor or latcor component * of an IRAF WAT string. * Type: * Private function. * Synopsis: * int WATCoeffs( const char *watstr, int iaxis, double **cvals, * int **mvals, int *ok, int *status ) * Class Membership: * FitsChan * Description: * This function extracts the polynomial coefficients from a supplied * string containing the concatenated values of a set of IRAF "WAT" * keywords, such as used for the IRAF-specific TNX and ZPX projections. * The coefficients are returned in the form of a set of PVi_m values * for a TPN projection. * Parameters: * watstr * The concatentated WAT keyword values. * iaxis * Zero based index of the axis to which the WAT keywords refer (0 * or 1). * cvals * Location at which to return a pointer to a dynamically allocated * list of coefficient values, or NULL if no lngcor/latcor values * were found in the WAT string. Free using astFree. * mvals * Location at which to return a pointer to a dynamically allocated * list of coefficient indices, or NULL if no lngcor/latcor values * were found in the WAT string. Free using astFree. * ok * Pointer to an in which is returned set to zero if the polynomial * in the supplied WAT string cannot be represented using TPN form. * Non-zero otherwise. * status * Pointer to the inherited status variable. * Returned Value: * The size of the returned cvals and mvals arrays. */ /* Local Variables: */ char **w1; char **w2; double *coeff; double *pc; int result; double dval; double etamax; double etamin; double ximax; double ximin; int cheb; int etaorder; int iword; int m; int mn; int nword; int order; int porder; int xiorder; int ires; /* The number of lngcor/latcor values needed for each order. */ static const int nab[] = {1,3,6,10,15,21,28,36}; /* Initialise the pointer to the returned Mapping. */ result = 0; *mvals = NULL; *cvals = NULL; *ok = 1; /* Other initialisation to avoid compiler warnings. */ etamin = 0.0; etamax = 0.0; ximax = 0.0; ximin = 0.0; order = 0; /* Check the global status. */ if ( !astOK || !watstr ) return result; /* Look for cor = "..." and extract the "..." string. */ w1 = astChrSplitRE( watstr, "cor *= *\"(.*)\"", &nword, NULL ); if( w1 ) { /* Split the "..." string into words. */ w2 = astChrSplit( w1[ 0 ], &nword ); if( w2 ) { /* Initialise flags. */ cheb = 0; xiorder = 0; etaorder = 0; coeff = NULL; porder = -1; /* Loop round each word. Break early if we find that the projection cannot be represented as a TPN projection. */ for( iword = 0; iword < nword && *ok; iword++ ) { /* Convert the word to double. */ dval = astChr2Double( w2[ iword ] ); if( dval == AST__BAD ) { astError( AST__BDFTS, "astRead(FitsChan): Failed to read a " "numerical value from sub-string \"%s\" found in " "an IRAF \"WAT...\" keyword.", status, w2[ iword ] ); break; } /* The first value gives the correction surface type. We can only handle type 1 (chebyshev) or 3 (simple polynomial). */ if( iword == 0 ){ if( dval == 1.0 ) { cheb = 1; } else if( dval == 2.0 ) { *ok = 0; } /* The second and third numbers gives the orders of the polynomial in X and Y. We can only handle cases in which the orders are the same on both axes, and greater than 0 and less than 8. Store a pointer to the first TAN projection parameter index to use. */ } else if( iword == 1 ){ order = dval; porder = order - 1; } else if( iword == 2 ){ if( dval - 1 != porder || dval < 0 || dval > 7 ) *ok = 0; /* The fourth number defines the type of cross-terms. We can only handle type 2 (half-cross terms). */ } else if( iword == 3 ){ if( dval != 2.0 ) *ok = 0; /* We now know the maximum number of co-efficients that may be needed. Allocate memory to hold them, and fill it with zeros. They are stored in this array as if full cross-terms have been supplied (the unspecified coefficients retain their initialised value of zero). */ coeff = astCalloc( order*order, sizeof( double ) ); if( !astOK ) break; /* The next 4 numbers describe the region of validity of the fits in IRAF's xi and eta space, e.g. ximin, ximax, etamin, etamax. We only uses these if we have a chebyshev polynomial. */ } else if( iword == 4 ) { ximin = dval; } else if( iword == 5 ) { ximax = dval; } else if( iword == 6 ) { etamin = dval; } else if( iword == 7 ) { etamax = dval; /* The remaining terms are the coefficients of the polynomial terms. */ } else if( iword > 7 ){ /* Store the coefficient in the array. They are stored so that power of xi increases fastest. */ coeff[ xiorder + order*etaorder ] = dval; /* Increment the powers of the next coefficient. We know we only have half cross-terms, so the maximum power of xi decreases from order to zero as we move through the list of coefficients. */ if( ++xiorder == order - etaorder ) { xiorder = 0; etaorder++; } } } /* Check that all the required co-efficients were found */ if( porder == -1 || nword != 8 + nab[ porder ] ) *ok = 0; /* If we can handle the projection, proceed. */ if( *ok && astOK ) { /* If the coefficients were supplied in chebyshev form, convert to simple form. */ if( cheb ) { double *tcoeff = coeff; coeff = Cheb2Poly( tcoeff, order, order, ximin, ximax, etamin, etamax, status ); tcoeff = astFree( tcoeff ); } /* The polynomials provide a "correction* to be added to the supplied X and Y values. Therefore increase the linear co-efficients by 1 on the axis that is being calculated. */ coeff[ iaxis ? order : 1 ] += 1.0; /* Loop round all coefficients, keeping track of the power of xi and eta for the current coefficient. */ pc = coeff; for( etaorder = 0; etaorder < order; etaorder++ ) { for( xiorder = 0; xiorder < order; xiorder++,pc++ ) { /* Skip coefficients that have their default values (zero, except for the linear coefficients which default to 1.0). */ mn = xiorder + etaorder; if( *pc != ( mn == 1 ? 1.0 : 0.0 ) ) { /* Find the "m" index of the PVi_m FITS keyword for the current coefficient. */ m = mn*( 1 + mn )/2 + mn/2; m += iaxis ? xiorder : etaorder; /* Append the PV and m values to the ends of the returned arrays. */ ires = result++; *cvals = astGrow( *cvals, sizeof( double ), result ); *mvals = astGrow( *mvals, sizeof( int ), result ); if( astOK ) { (*cvals)[ ires ] = *pc; (*mvals)[ ires ] = m; } } } } /* Free coefficients arrays */ coeff = astFree( coeff ); } /* Free resources */ w2 = astFree( w2 ); } w1 = astFree( w1 ); } /* Return the result. */ return result; } static AstMatrixMap *WcsCDeltMatrix( FitsStore *store, char s, int naxes, const char *method, const char *class, int *status ){ /* * Name: * WcsCDeltMatrix * Purpose: * Create a MatrixMap representing the CDELT scaling. * Type: * Private function. * Synopsis: * AstMatrixMap *WcsCDeltMatrix( FitsStore *store, char s, int naxes, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A diagonal MatrixMap representing the FITS "CDELT" keywords is * returned. * Parameters: * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character s identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the created MatrixMap or a NULL pointer if an * error occurred. */ /* Local Variables: */ AstMatrixMap *new; /* The created MatrixMap */ double *el; /* Pointer to next matrix element */ double *mat; /* Pointer to matrix array */ int i; /* Pixel axis index */ /* Initialise/ */ new = NULL; /* Check the global status. */ if ( !astOK ) return new; /* Allocate memory for the diagonal matrix elements. */ mat = (double *) astMalloc( sizeof(double)*naxes ); if( astOK ){ /* Fill the matrix diagonal with values from the FitsStore. */ el = mat; for( i = 0; i < naxes; i++ ){ /* Get the CDELTi value for this axis. Missing terms can be defaulted so do not report an error if the required value is not present in the FitsStore. */ *el = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); /* Missing terms default to to 1.0. */ if( *el == AST__BAD ) *el = 1.0; /* Move on to the next matrix element. */ el++; } /* Create the diagional matrix. */ new = astMatrixMap( naxes, naxes, 1, mat, "", status ); /* Report an error if the inverse transformation is undefined. */ if( !astGetTranInverse( new ) && astOK ) { astError( AST__BDFTS, "%s(%s): Unusable CDELT values found " "in the FITS-WCS header - one or more values are zero.", status, method, class ); } /* Release the memory used to hold the matrix. */ mat = (double *) astFree( (void *) mat ); } /* If an error has occurred, attempt to annul the returned MatrixMap. */ if( !astOK ) new = astAnnul( new ); /* Return the MatrixMap. */ return new; } static AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s, AstFrame **frm, AstFrame *iwcfrm, double *reflon, double *reflat, AstSkyFrame **reffrm, AstMapping **tabmap, int *tabaxis, const char *method, const char *class, int *status ){ /* * Name: * WcsCelestial * Purpose: * Create a Mapping from intermediate world coords to celestial coords * as described in a FITS header. * Type: * Private function. * Synopsis: * AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s, * AstFrame **frm, AstFrame *iwcfrm, double *reflon, double *reflat, * AstSkyFrame **reffrm, , AstMapping **tabmap, * int *tabaxis, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function interprets the contents of the supplied FitsStore * structure, looking for world coordinate axes which describe positions * on the sky. If a pair of such longitude/latitude axes is found, a * Mapping is returned which transforms the corresponding intermediate * world coordinates to celestial world coordinates (this mapping leaves * any other axes unchanged). It also, modifies the supplied Frame to * describe the axes (again, other axes are left unchanged). If no * pair of celestial axes is found, a UnitMap is returned, and the * supplied Frame is left unchanged. * Parameters: * this * The FitsChan. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * frm * The address of a location at which to store a pointer to the * Frame describing the world coordinate axes. * iwcfrm * A pointer to the Frame describing the intermediate world coordinate * axes. The properties of this Frame may be changed on exit. * reflon * Address of a location at which to return the celestial longitude * at the reference point. It is returned as AST__BAD if no * celestial coordinate frame is found. * reflat * Address of a location at which to return the celestial latitude * at the reference point. It is returned as AST__BAD if no * celestial coordinate frame is found. * reffrm * Address of a location at which to return a pointer to a SkyFrame * which define the reference values returned in reflon and reflat. * It is returned as NULL if no celestial coordinate frame is found. * tabmap * Address of a pointer to a Mapping describing any -TAB * transformations to be applied to the results of the Mapping returned * by this function. If any celestial axes are found, the supplied * Mapping is modified so that the celestial axes produce values in * radians rather than degrees. NULL if no axes are described by -TAB. * tabaxis * Pointer to an array of flags, one for each WCS axis, indicating * if the corresponding WCS axis is described by the -TAB algorithm. * NULL if no axes are described by -TAB. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFrame *ofrm; /* Pointer to a Frame */ AstMapping *map1; /* Pointer to a Mapping */ AstMapping *map2; /* Pointer to a Mapping */ AstMapping *map3; /* Pointer to a Mapping */ AstMapping *map4; /* Pointer to a Mapping */ AstMapping *ret; /* Pointer to the returned Mapping */ AstMapping *newmap; /* Modified PIXEL->IWC Mapping */ AstMapping *shiftmap; /* ShiftMap from IWC to PPC */ AstSkyFrame *sfrm; /* Pointer to a SkyFrame */ char *ctype; /* Pointer to CTYPE string */ char *keyname; /* Pointer to keyword name string */ char buf[300]; /* Text buffer */ char latctype[MXCTYPELEN];/* Latitude CTYPE keyword value */ char latkey[10]; /* Latitude CTYPE keyword name */ char lattype[4]; /* Buffer for celestial system */ char lonctype[MXCTYPELEN];/* Longitude CTYPE keyword value */ char lonkey[10]; /* Longitude CTYPE keyword name */ char lontype[4]; /* Buffer for celestial system */ double *shifts; /* Array holding axis shifts */ double *ina; /* Pointer to memory holding input position A */ double *inb; /* Pointer to memory holding input position B */ double *mat; /* Pointer to data for deg->rad scaling matrix */ double *outa; /* Pointer to memory holding output position A */ double *outb; /* Pointer to memory holding output position B */ double latval; /* CRVAL for latitude axis */ double lonval; /* CRVAL for longitude axis */ double pv; /* Projection parameter value */ double x0; /* IWC X at the projection fiducial point */ double y0; /* IWC Y at the projection fiducial point */ int *axes; /* Point to a list of axis indices */ int axlat; /* Index of latitude physical axis */ int axlon; /* Index of longitude physical axis */ int carlin; /* Assume native and WCS axes are the same? */ int ctlen; /* Length of CTYPE string */ int gotax; /* Celestial axis found? */ int i; /* Loop count */ int j; /* Axis index */ int latprj; /* Latitude projection type identifier */ int lonprj; /* Longitude projection type identifier */ int m; /* Parameter index */ int mxpar_lat; /* Max. projection parameter index on lat axis */ int mxpar_lon; /* Max. projection parameter index on lon axis */ int naxes; /* Number of axes */ int np; /* Max parameter index */ int prj; /* Projection type identifier */ /* Initialise the returned values. */ ret = NULL; *reflon = AST__BAD; *reflat = AST__BAD; *reffrm = NULL; /* Other initialisation to avoid compiler warnings. */ map1 = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* Get the number of physical axes. */ naxes = astGetNaxes( *frm ); /* See if CAR projections should be interpreted in the old fashioned way (i.e native coords are always the same as WCS coords, so no need for any rotation). */ carlin = astGetCarLin( this ); /* The first major section sees if the physical axes include a pair of longitude/latitude celestial axes. ================================================================= */ /* We have not yet found any celestial axes. */ axlon = -1; axlat = -1; latprj = AST__WCSBAD; lonprj = AST__WCSBAD; prj = AST__WCSBAD; /* First, we examine the CTYPE values in the FitsStore to determine which axes are the longitude and latitude axes, and what the celestial co-ordinate system and projection are. Loop round the physical axes, getting each CTYPE value. */ for( i = 0; i < naxes && astOK; i++ ){ keyname = FormatKey( "CTYPE", i + 1, -1, s, status ); ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); /* Issue a warning if no CTYPE value was found. */ if( !ctype ) { sprintf( buf, "Axis type keywords (CTYPE, etc) were not found " "for one or more axes in the original FITS header. These " "axes will be assumed to be linear." ); Warn( this, "noctype", buf, method, class, status ); } else { /* See if this is a longitude axis (e.g. if the first 4 characters of CTYPE are "RA--" or "xLON" or "yzLN" ). If so, store the value of "x" or "yz" (or "EQU" for equatorial coordinates) in variable "type" to indicate which coordinate system is being used. */ gotax = 0; if( !strcmp( ctype, "RA" ) || !strncmp( ctype, "RA--", 4 ) ){ strcpy( wcscelestial_type, "EQU" ); gotax = 1; } else if( !strcmp( ctype, "AZ" ) || !strncmp( ctype, "AZ--", 4 ) ){ strcpy( wcscelestial_type, "AZL" ); gotax = 1; } else if( !strcmp( ctype + 1, "LON" ) || !strncmp( ctype + 1, "LON-", 4 ) ){ wcscelestial_type[ 0 ] = ctype[ 0 ]; wcscelestial_type[ 1 ] = 0; gotax = 1; } else if( !strcmp( ctype + 2, "LN" ) || !strncmp( ctype + 2, "LN-", 3 ) ){ wcscelestial_type[ 0 ] = ctype[ 0 ]; wcscelestial_type[ 1 ] = ctype[ 1 ]; wcscelestial_type[ 2 ] = 0; gotax = 1; } /* If this is a longitude axis... */ if( gotax ){ /* Check that this is the first longitude axis to be found. */ if( axlon == -1 ){ /* Find the projection type as specified by the last 4 characters in the CTYPE keyword value. AST__WCSBAD is stored in "prj" if the last 4 characters do not specify a known WCS projection, but no error is reported. Assume simple linear axes if no projection code is supplied. Note, AST__WCSBAD is used to indicate a TAB header. */ ctlen = strlen( ctype ); if( ctlen > 4 ) { prj = astWcsPrjType( ctype + ctlen - 4 ); } else if( tabmap && *tabmap ) { prj = AST__WCSBAD; } else { prj = AST__CAR; carlin = 1; } /* Report an error if the projection is unknown. */ if( prj == AST__WCSBAD && ctlen > 4 ){ astError( AST__BDFTS, "%s(%s): FITS keyword '%s' refers to " "an unknown projection type '%s'.", status, method, class, keyname, ctype + ctlen - 4 ); break; } /* Store the index of the longitude axis, type of longitude, etc. */ axlon = i; strcpy( lontype, wcscelestial_type ); strcpy( lonkey, keyname ); strcpy( lonctype, ctype ); lonprj = prj; /* If another longitude axis has already been found, report an error. */ } else { astError( AST__BDFTS, "%s(%s): FITS keywords '%s' (='%s') " "and '%s' (='%s') both describe celestial longitude axes.", status, method, class, keyname, ctype, lonkey, lonctype ); break; } } /* Do the same for the latitude axis, checking for "DEC-" and "xLAT" and "yzLT". */ gotax = 0; if( !strcmp( ctype, "DEC" ) || !strncmp( ctype, "DEC-", 4 ) ){ strcpy( wcscelestial_type, "EQU" ); gotax = 1; } else if( !strcmp( ctype, "EL" ) || !strncmp( ctype, "EL--", 4 ) ){ strcpy( wcscelestial_type, "AZL" ); gotax = 1; } else if( !strcmp( ctype + 1, "LAT" ) || !strncmp( ctype + 1, "LAT-", 4 ) ){ wcscelestial_type[ 0 ] = ctype[ 0 ]; wcscelestial_type[ 1 ] = 0; gotax = 1; } else if( !strcmp( ctype + 2, "LT" ) || !strncmp( ctype + 2, "LT-", 3 ) ){ wcscelestial_type[ 0 ] = ctype[ 0 ]; wcscelestial_type[ 1 ] = ctype[ 1 ]; wcscelestial_type[ 2 ] = 0; gotax = 1; } if( gotax ){ if( axlat == -1 ){ ctlen = strlen( ctype ); if( ctlen > 4 ) { prj = astWcsPrjType( ctype + ctlen - 4 ); } else if( tabmap && *tabmap ) { prj = AST__WCSBAD; } else { prj = AST__CAR; carlin = 1; } if( prj == AST__WCSBAD && ctlen > 4 ){ astError( AST__BDFTS, "%s(%s): FITS keyword '%s' refers to " "an unknown projection type '%s'.", status, method, class, keyname, ctype + ctlen - 4 ); break; } axlat = i; strcpy( lattype, wcscelestial_type ); strcpy( latkey, keyname ); strcpy( latctype, ctype ); latprj = prj; } else { astError( AST__BDFTS, "%s(%s): FITS keywords '%s' (='%s') " "and '%s' (='%s') both describe celestial latitude axes.", status, method, class, keyname, ctype, latkey, latctype ); break; } } } } /* Check the above went OK */ if( astOK ){ /* If both longitude and latitude axes were found... */ if( axlat != -1 && axlon != -1 ){ /* Report an error if they refer to different celestial coordinate systems. */ if( strcmp( lattype, lontype ) ){ astError( AST__BDFTS, "%s(%s): FITS keywords '%s' and '%s' " "indicate different celestial coordinate systems " "('%s' and '%s').", status, method, class, latkey, lonkey, latctype, lonctype ); /* Otherwise report an error if longitude and latitude axes use different projections. */ } else if( lonprj != latprj ){ astError( AST__BDFTS, "%s(%s): FITS keywords '%s' and '%s' " "indicate different projections ('%s' and '%s').", status, method, class, latkey, lonkey, latctype, lonctype ); } /* If only one axis has been provided without the other (e.g. longitude but no latitude), report an error. */ } else if( axlat != -1 && prj != AST__WCSBAD ){ astError( AST__BDFTS, "%s(%s): A latitude axis ('%s') was found " "without a corresponding longitude axis.", status, method, class, latctype ); } else if( axlon != -1 && prj != AST__WCSBAD ){ astError( AST__BDFTS, "%s(%s): A longitude axis ('%s') was found " "without a corresponding latitude axis.", status, method, class, lonctype ); } } /* If a pair of matching celestial axes was not found, return a UnitMap and leave the Frame unchanged. ===================================================================== */ if( axlat == -1 || axlon == -1 ) { ret = (AstMapping *) astUnitMap( naxes, "", status ); /* The rest of this function deals with creating a Mapping from intermediate world coords to celestial coords, and modifying the Frame appropriately. ===================================================================== */ } else if( astOK ) { /* Create a MatrixMap which scales the intermediate world coordinate axes corresponding to the longitude and latitude axes from degrees to radians. Only do this if a projection was supplied. */ if( latprj != AST__WCSBAD ) { mat = (double *) astMalloc( sizeof(double)*naxes ); if( mat ){ for( i = 0; i < naxes; i++ ){ if( i == axlat || i == axlon ){ mat[ i ] = AST__DD2R; } else { mat[ i ] = 1.0; } } map1 = (AstMapping *) astMatrixMap( naxes, naxes, 1, mat, "", status ); mat = (double *) astFree( (void *) mat ); } } else { map1 = (AstMapping *) astUnitMap( naxes, " ", status ); } /* If the projection is a CAR projection, but the CarLin attribute is set, then we consider the CAR projection to be a simple linear mapping of pixel coords to celestial coords. Do this by using a WcsMap with no projection. All axes will then be treated as linear and non-celestial. If no projection was specified (i.e. if prj == AST__WCSBAD, as is the case when using -TAB for instance) then do the same but use a UnitMap instead of a WcsMap. */ map3 = NULL; if( ( latprj == AST__CAR && carlin ) || latprj == AST__WCSBAD ) { if( latprj == AST__CAR ) { map2 = (AstMapping *) astWcsMap( naxes, AST__WCSBAD, axlon + 1, axlat + 1, "", status ); } else { map2 = (AstMapping *) astUnitMap( naxes, "", status ); } /* Now create a WinMap which adds on the CRVAL values to each axis. */ ina = astMalloc( sizeof(double)*naxes ); inb = astMalloc( sizeof(double)*naxes ); outa = astMalloc( sizeof(double)*naxes ); outb = astMalloc( sizeof(double)*naxes ); if( astOK ) { for( i = 0; i < naxes; i++ ) { ina[ i ] = 0.0; inb[ i ] = 1.0; outa[ i ] = 0.0; outb[ i ] = 1.0; } lonval = GetItem( &(store->crval), axlon, 0, s, NULL, method, class, status ); if( lonval != AST__BAD ) { /* For recognised projections the CRVAL value is required to be degrees, so convert to radians. For other algorithms (e.g. -TAB) the CRVAL values are in unknown units so retain their original scaling. */ *reflon = ( latprj == AST__CAR ) ? lonval*AST__DD2R : lonval; outa[ axlon ] += *reflon; outb[ axlon ] += *reflon; } else { outa[ axlon ] = AST__BAD; outb[ axlon ] = AST__BAD; } latval = GetItem( &(store->crval), axlat, 0, s, NULL, method, class, status ); if( latval != AST__BAD ) { *reflat = ( latprj == AST__CAR ) ? latval*AST__DD2R : latval; outa[ axlat ] += *reflat; outb[ axlat ] += *reflat; } else { outa[ axlat ] = AST__BAD; outb[ axlat ] = AST__BAD; } map3 = (AstMapping *) astWinMap( naxes, ina, inb, outa, outb, "", status ); } ina = astFree( ina ); inb = astFree( inb ); outa = astFree( outa ); outb = astFree( outb ); /* Otherwise, create a WcsMap with the specified projection. The WcsMap is equivalent to a unit mapping for all axes other than "axlat" and "axlon". */ } else { /* Get the highest index ("m" value) of any supplied PVi_m projection parameters (on any axes). */ np = GetMaxJM( &(store->pv), s, status ); /* Create the WcsMap */ map2 = (AstMapping *) astWcsMap( naxes, latprj, axlon + 1, axlat + 1, "", status ); /* If the FITS header contains any projection parameters, store them in the WcsMap. */ mxpar_lat = astGetPVMax( map2, axlat ); mxpar_lon = astGetPVMax( map2, axlon ); for( m = 0; m <= np; m++ ){ pv = GetItem( &(store->pv), axlat, m, s, NULL, method, class, status ); if( pv != AST__BAD ) { if( m <= mxpar_lat ) { astSetPV( map2, axlat, m, pv ); } else { sprintf( buf, "Projection parameter PV%d_%d found, " "but is not used by %s projections.", axlat + 1, m, astWcsPrjName( astGetWcsType( map2 ) ) ); Warn( this, "badpv", buf, method, class, status ); } } pv = GetItem( &(store->pv), axlon, m, s, NULL, method, class, status ); if( pv != AST__BAD ) { if( m <= mxpar_lon ) { astSetPV( map2, axlon, m, pv ); } else { sprintf( buf, "Projection parameter PV%d_%d found, " "but is not used by %s projections.", axlon + 1, m, astWcsPrjName( astGetWcsType( map2 ) ) ); Warn( this, "badpv", buf, method, class, status ); } } } /* Invert the WcsMap to get a DEprojection. */ astInvert( map2 ); /* Now produce a Mapping which converts the axes holding "Native Spherical Coords" into "Celestial Coords", leaving all other axes unchanged. */ map3 = WcsNative( this, store, s, (AstWcsMap *) map2, -1, -1, method, class, status ); /* Retrieve and store the reference longitude and latitude. */ *reflon = GetItem( &(store->crval), axlon, 0, s, NULL, method, class, status ); if( *reflon != AST__BAD ) *reflon *= AST__DD2R; *reflat = GetItem( &(store->crval), axlat, 0, s, NULL, method, class, status ); if( *reflat != AST__BAD ) *reflat *= AST__DD2R; } /* If projection parameter PVi_0a for the longitude axis "i" is non-zero, then there is a shift of origin between Intermediate World Coords, IWC, (the CRPIXi values correspond to the origin of IWC), and Projection Plane Coords, PPC (these are the cartesian coordinates used by the WcsMap). This shift of origin results in the fiducial point specified by the CRVALi values mapping onto the pixel reference point specified by the CRPIXj values. In this case we need to add a Mapping which implements the shift of origin. Note, the AST-specific "TPN" projection cannot use this convention since it uses PVi_0 to hold a polynomial correction term. */ if( latprj != AST__WCSBAD && astGetWcsType( map2 ) != AST__TPN && astGetPV( map2, axlon, 0 ) != 0.0 ) { /* Find the projection plane coords corresponding to the fiducial point of the projection. This is done by using the inverse WcsMap to convert the native spherical coords at the fiducial point into PPC (x,y), which are returned in units of radians (not degrees). */ GetFiducialPPC( (AstWcsMap *) map2, &x0, &y0, status ); if( x0 != AST__BAD && y0 != AST__BAD ) { /* Allocate resources. */ shifts = astMalloc( sizeof( double )*(size_t) naxes ); /* Check pointers can be used safely. */ if( astOK ) { /* Create a Mapping (a ShiftMap) from IWC to PPC. */ for( i = 0; i < naxes; i++ ) shifts[ i ] = 0.0; shifts[ axlon ] = x0; shifts[ axlat ] = y0; shiftmap = (AstMapping *) astShiftMap( naxes, shifts, "", status ); /* Produce a CmpMap which combines "map1" (which converts degrees to radians on the celestial axes) with the above ShiftMap. */ newmap = (AstMapping *) astCmpMap( map1, shiftmap, 1, "", status ); /* Annul the component Mappings and use the new one in place of map1. */ shiftmap = astAnnul( shiftmap ); map1 = astAnnul( map1 ); map1 = newmap; } /* Free resources. */ shifts = astFree( shifts ); } } /* Now concatenate the Mappings to produce the returned Mapping. */ map4 = (AstMapping *) astCmpMap( map1, map2, 1, "", status ); ret = (AstMapping *) astCmpMap( map4, map3, 1, "", status ); /* Annul the component Mappings. */ map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); map4 = astAnnul( map4 ); /* We now make changes to the supplied Frame so that the longitude and latitude axes are described by a SkyFrame. First create an appropriate SkyFrame. */ sfrm = WcsSkyFrame( this, store, s, prj, wcscelestial_type, axlon, axlat, method, class, status ); /* The values currently stored in *reflat and *reflon are the CRVAL values. In some circumstances, these may not be the original values in the supplied header but may have been translated within the SpecTrans function as part of the process of translating an old unsupported projection into a new supported projection. Since the returned RefLat and RefLon values may be used to set the reference position for a SpecFrame, we should return the original values rather than the translated values. The original values will have been stored (within SpecTrans) in the FitsChan as keywords RFVALi. If such keywords can be found, use their values in preference to the currently stored CRVAL values.*/ if( GetValue( this, FormatKey( "RFVAL", axlon + 1, -1, s, status ), AST__FLOAT, (void *) &lonval, 0, 0, method, class, status ) && GetValue( this, FormatKey( "RFVAL", axlat + 1, -1, s, status ), AST__FLOAT, (void *) &latval, 0, 0, method, class, status ) ) { *reflon = lonval*AST__DD2R; *reflat = latval*AST__DD2R; } /* Store the reflon and reflat values as the SkyRef position in the SkyFrame, and set SkyRefIs to "ignore" so that the SkyFrame continues to represent absolute celestial coords. Do not change the SkyFrame if it already had a set reference posiiton. */ if( ! astTestSkyRef( sfrm, 0 ) ) { if( *reflon != AST__BAD && *reflat != AST__BAD ) { astSetSkyRef( sfrm, 0, *reflon ); astSetSkyRef( sfrm, 1, *reflat ); astSet( sfrm, "SkyRefIs=Ignored", status ); } } /* Return a clone of this SkyFrame as the reference Frame. */ *reffrm = astClone( sfrm ); /* Create a Frame by picking all the other (non-celestial) axes from the supplied Frame. */ axes = astMalloc( naxes*sizeof( int ) ); if( axes ) { j = 0; for( i = 0; i < naxes; i++ ) { if( i != axlat && i != axlon ) axes[ j++ ] = i; } /* If there were no other axes, replace the supplied Frame with the skyframe. */ if( j == 0 ) { (void) astAnnul( *frm ); *frm = (AstFrame *) astClone( sfrm ); /* Otherwise pick the other axes from the supplied Frame */ } else { ofrm = astPickAxes( *frm, j, axes, NULL ); /* Replace the supplied Frame with a CmpFrame made up of this Frame and the SkyFrame. */ (void) astAnnul( *frm ); *frm = (AstFrame *) astCmpFrame( ofrm, sfrm, "", status ); ofrm = astAnnul( ofrm ); } /* Permute the axis order to put the longitude and latitude axes back in their original position. The SkyFrame will have the default axis ordering (lon=axis 0, lat = axis 1). */ j = 0; for( i = 0; i < naxes; i++ ) { if( i == axlat ) { axes[ i ] = naxes - 1; } else if( i == axlon ) { axes[ i ] = naxes - 2; } else { axes[ i ] = j++; } } astPermAxes( *frm, axes ); /* Free the axes array. */ axes= astFree( axes ); } /* Set the units in the supplied IWC Frame for the longitude and latitude axes. Unless using -TAB, these are degrees (the conversion from degs to rads is part of the Mapping from IWC to WCS). If using -TAB the units are unknown. */ if( !tabaxis || !tabaxis[ axlon ] ) astSetUnit( iwcfrm, axlon, "deg" ); if( !tabaxis || !tabaxis[ axlat ] ) astSetUnit( iwcfrm, axlat, "deg" ); /* Modify any supplied tabmap so that the celestial outputs create radians rather than degrees (but only if the celestial axes are generated by the -TAB algorithm). */ if( tabaxis && tabaxis[ axlon ] && tabaxis[ axlat ] ) { mat = (double *) astMalloc( sizeof(double)*naxes ); if( mat ){ for( i = 0; i < naxes; i++ ){ if( i == axlat || i == axlon ){ mat[ i ] = AST__DD2R; } else { mat[ i ] = 1.0; } } map1 = (AstMapping *) astMatrixMap( naxes, naxes, 1, mat, "", status ); mat = (double *) astFree( (void *) mat ); map2 = (AstMapping *) astCmpMap( *tabmap, map1, 1, " ", status ); map1 = astAnnul( map1 ); (void) astAnnul( *tabmap ); *tabmap = map2; } /* Also modify the returned reflon and reflat values to transform them using the tabmap. Also transform the reference position in the SkyFrame. */ if( *reflon != AST__BAD && *reflat != AST__BAD ) { ina = astMalloc( sizeof(double)*naxes ); outa = astMalloc( sizeof(double)*naxes ); if( astOK ) { for( i = 0; i < naxes; i++ ) ina[ i ] = 0.0; ina[ axlat ] = *reflat; ina[ axlon ] = *reflon; astTranN( *tabmap, 1, naxes, 1, ina, 1, naxes, 1, outa ); *reflon = outa[ axlon ]; *reflat = outa[ axlat ]; } ina = astFree( ina ); outa = astFree( outa ); /* Store this transformed reference position in the SkyFrame. */ astSetSkyRef( sfrm, 0, *reflon ); astSetSkyRef( sfrm, 1, *reflat ); astSet( sfrm, "SkyRefIs=Ignored", status ); } } /* If the header contains AXREF values for both lon and lat axes, use them as the sky reference position in preferences to the values derived form the CRVAL values. AXREF keywords are created by the astWrite method for axes described by -TAB algorithm that have no inverse transformation. */ if( GetValue( this, FormatKey( "AXREF", axlon + 1, -1, s, status ), AST__FLOAT, (void *) &lonval, 0, 0, method, class, status ) && GetValue( this, FormatKey( "AXREF", axlat + 1, -1, s, status ), AST__FLOAT, (void *) &latval, 0, 0, method, class, status ) ) { *reflon = lonval*AST__DD2R; *reflat = latval*AST__DD2R; astSetSkyRef( sfrm, 0, *reflon ); astSetSkyRef( sfrm, 1, *reflat ); astSet( sfrm, "SkyRefIs=Ignored", status ); } /* Free resources. */ sfrm = astAnnul( sfrm ); } /* Return the result. */ return ret; } static void WcsFcRead( AstFitsChan *fc, AstFitsChan *fc2, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * WcsFcRead * Purpose: * Extract WCS information from a supplied FitsChan using a FITSWCS * encoding, and store it in the supplied FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WcsFcRead( AstFitsChan *fc, AstFitsChan *fc2, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function extracts FITSWCS keywords from the supplied FitsChan, * and stores the corresponding WCS information in the supplied FitsStore. * Parameters: * fc * Pointer to the FitsChan containing the cards read from the * original FITS header. This should not include any un-used * non-standard keywords. * fc2 * Pointer to a second FitsChan. If a card read from "fc" fails to * be converted to its correct data type, a warning is only issued * if there is no card for this keyword in "fc2". "fc2" may be NULL * in which case a warning is always issued. * store * Pointer to the FitsStore structure. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Local Variables: */ char buf[200]; /* Buffer for warning message */ char *cval; /* String keyword value */ char *keynam; /* Pointer to current keyword name */ char s; /* Co-ordinate version character */ double dval; /* Floating point keyword value */ int fld[2]; /* Integer field values from keyword name */ int jm; /* Pixel axis or projection parameter index */ int i; /* Intermediate axis index */ int mark; /* Non-zero if card should be removed once used */ int nfld; /* Number of integer fields in test string */ int ok; /* Was value converted succesfully? */ int type; /* Keyword data type */ int undef; /* Is an undefined keyword value acceptable? */ void *item; /* Pointer to item to get/put */ /* Check the global error status. */ if ( !astOK ) return; /* Ensure the FitsChan is re-wound. */ astClearCard( fc ); /* Loop round all the cards in the FitsChan obtaining the keyword name for each card. Note, the single "=" is correct in the following "while" statement. */ s = 0; jm = -1; i = -1; type = AST__NOTYPE; while( (keynam = CardName( fc, status )) ){ item = NULL; /* Assume the card is to be consumed by the reading process. This means the card will be marked as used and effectively excluded from the header. Keywords which supply observation details that do not depend on the mapping from pixel to WCS axes, or on the nature of the WCS axes, are not removed as they may be needed for other, non-WCS related, purposes. */ mark = 1; /* For most keywords, if the keyword is present in the header it must have a definded value. However, some keywords are read from the header but not actually used for anything. This is done to ensure that the keyword is stripped from the header. It is acceptable for such keywords to have an undefined value. Initialise a flag indicating that the next keyword read is not allowed to have an undefined value. */ undef = 0; /* Is this a primary CRVAL keyword? */ if( Match( keynam, "CRVAL%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->crval); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary CRVAL keyword? */ } else if( Match( keynam, "CRVAL%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->crval); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary CRPIX keyword? */ } else if( Match( keynam, "CRPIX%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->crpix); type = AST__FLOAT; i = 0; jm = fld[ 0 ] - 1; s = ' '; /* Is this a secondary CRPIX keyword? */ } else if( Match( keynam, "CRPIX%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->crpix); type = AST__FLOAT; i = 0; jm = fld[ 0 ] - 1; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary CDELT keyword? */ } else if( Match( keynam, "CDELT%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->cdelt); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary CDELT keyword? */ } else if( Match( keynam, "CDELT%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->cdelt); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary CTYPE keyword? If so, store the associated comment. */ } else if( Match( keynam, "CTYPE%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->ctype); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = ' '; SetItemC( &(store->ctype_com), i, 0, ' ', CardComm( fc, status ), status ); /* Is this a secondary CTYPE keyword? If so, store the associated comment. */ } else if( Match( keynam, "CTYPE%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->ctype); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; SetItemC( &(store->ctype_com), i, 0, s, CardComm( fc, status ), status ); /* Is this a primary CNAME keyword? */ } else if( Match( keynam, "CNAME%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->cname); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary CNAME keyword? */ } else if( Match( keynam, "CNAME%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->cname); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary CUNIT keyword? */ } else if( Match( keynam, "CUNIT%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->cunit); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary CUNIT keyword? */ } else if( Match( keynam, "CUNIT%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->cunit); type = AST__STRING; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary PC keyword? */ } else if( Match( keynam, "PC%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->pc); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = fld[ 1 ] - 1; s = ' '; /* Is this a secondary PC keyword? */ } else if( Match( keynam, "PC%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->pc); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = fld[ 1 ] - 1; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary PV keyword? */ } else if( Match( keynam, "PV%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->pv); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = fld[ 1 ]; s = ' '; /* Is this a secondary PV keyword? */ } else if( Match( keynam, "PV%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->pv); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary PS keyword? */ } else if( Match( keynam, "PS%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->ps); type = AST__STRING; i = fld[ 0 ] - 1; jm = fld[ 1 ]; s = ' '; /* Is this a secondary PS keyword? */ } else if( Match( keynam, "PS%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->ps); type = AST__STRING; i = fld[ 0 ] - 1; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary RADESYS keyword? */ } else if( Match( keynam, "RADESYS", 0, fld, &nfld, method, class, status ) ){ item = &(store->radesys); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Is this a secondary RADESYS keyword? */ } else if( Match( keynam, "RADESYS%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->radesys); type = AST__STRING; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary EQUINOX keyword? */ } else if( Match( keynam, "EQUINOX", 0, fld, &nfld, method, class, status ) ){ item = &(store->equinox); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary EQUINOX keyword? */ } else if( Match( keynam, "EQUINOX%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->equinox); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary LATPOLE keyword? */ } else if( Match( keynam, "LATPOLE", 0, fld, &nfld, method, class, status ) ){ item = &(store->latpole); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary LATPOLE keyword? */ } else if( Match( keynam, "LATPOLE%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->latpole); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary LONPOLE keyword? */ } else if( Match( keynam, "LONPOLE", 0, fld, &nfld, method, class, status ) ){ item = &(store->lonpole); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary LONPOLE keyword? */ } else if( Match( keynam, "LONPOLE%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->lonpole); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary WXSAXES keyword? */ } else if( Match( keynam, "WCSAXES", 0, fld, &nfld, method, class, status ) ){ item = &(store->wcsaxes); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary WCSAXES keyword? */ } else if( Match( keynam, "WCSAXES%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->wcsaxes); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary DUT1 keyword? */ } else if( Match( keynam, "DUT1", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->dut1); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a primary MJD-OBS keyword? */ } else if( Match( keynam, "MJD-OBS", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->mjdobs); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a primary WCSNAME keyword? */ } else if( Match( keynam, "WCSNAME", 0, fld, &nfld, method, class, status ) ){ item = &(store->wcsname); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Is this a secondary WCSNAME keyword? */ } else if( Match( keynam, "WCSNAME%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->wcsname); type = AST__STRING; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary SPECSYS keyword? */ } else if( Match( keynam, "SPECSYS", 0, fld, &nfld, method, class, status ) ){ item = &(store->specsys); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Is this a secondary SPECSYS keyword? */ } else if( Match( keynam, "SPECSYS%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->specsys); type = AST__STRING; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary SSYSSRC keyword? */ } else if( Match( keynam, "SSYSSRC", 0, fld, &nfld, method, class, status ) ){ item = &(store->ssyssrc); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Is this a secondary SSYSSRC keyword? */ } else if( Match( keynam, "SSYSSRC%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->ssyssrc); type = AST__STRING; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary ZSOURCE keyword? */ } else if( Match( keynam, "ZSOURCE", 0, fld, &nfld, method, class, status ) ){ item = &(store->zsource); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary ZSOURCE keyword? */ } else if( Match( keynam, "ZSOURCE%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->zsource); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary VELOSYS keyword? */ } else if( Match( keynam, "VELOSYS", 0, fld, &nfld, method, class, status ) ){ item = &(store->velosys); type = AST__FLOAT; undef = 1; i = 0; jm = 0; s = ' '; /* Is this a secondary VELOSYS keyword? */ } else if( Match( keynam, "VELOSYS%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->velosys); type = AST__FLOAT; undef = 1; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary RESTFRQ keyword? */ } else if( Match( keynam, "RESTFRQ", 0, fld, &nfld, method, class, status ) ){ item = &(store->restfrq); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary RESTFRQ keyword? */ } else if( Match( keynam, "RESTFRQ%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->restfrq); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary RESTWAV keyword? */ } else if( Match( keynam, "RESTWAV", 0, fld, &nfld, method, class, status ) ){ item = &(store->restwav); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a secondary RESTWAV keyword? */ } else if( Match( keynam, "RESTWAV%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->restwav); type = AST__FLOAT; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary IMAGFREQ keyword? */ } else if( Match( keynam, "IMAGFREQ", 0, fld, &nfld, method, class, status ) ){ item = &(store->imagfreq); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a primary SKYREF keyword? */ } else if( Match( keynam, "SREF%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->skyref); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary SKYREF keyword? */ } else if( Match( keynam, "SREF%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->skyref); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary SKYREFP keyword? */ } else if( Match( keynam, "SREFP%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->skyrefp); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary SKYREFP keyword? */ } else if( Match( keynam, "SREFP%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->skyrefp); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary SKYREFIS keyword? */ } else if( Match( keynam, "SREFIS", 0, fld, &nfld, method, class, status ) ){ item = &(store->skyrefis); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Is this a secondary SKYREFIS keyword? */ } else if( Match( keynam, "SREFIS%1c", 0, fld, &nfld, method, class, status ) ){ item = &(store->skyrefis); type = AST__STRING; i = 0; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary AXREF keyword? */ } else if( Match( keynam, "AXREF%d", 1, fld, &nfld, method, class, status ) ){ item = &(store->axref); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = ' '; /* Is this a secondary AXREF keyword? */ } else if( Match( keynam, "AXREF%d%1c", 1, fld, &nfld, method, class, status ) ){ item = &(store->axref); type = AST__FLOAT; i = fld[ 0 ] - 1; jm = 0; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a MJD-AVG keyword? */ } else if( Match( keynam, "MJD-AVG", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->mjdavg); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a OBSGEO-X keyword? */ } else if( Match( keynam, "OBSGEO-X", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->obsgeox); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a OBSGEO-Y keyword? */ } else if( Match( keynam, "OBSGEO-Y", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->obsgeoy); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a OBSGEO-Z keyword? */ } else if( Match( keynam, "OBSGEO-Z", 0, fld, &nfld, method, class, status ) ){ mark = 0; item = &(store->obsgeoz); type = AST__FLOAT; i = 0; jm = 0; s = ' '; /* Is this a TIMESYS keyword? */ } else if( Match( keynam, "TIMESYS", 0, fld, &nfld, method, class, status ) ){ item = &(store->timesys); type = AST__STRING; i = 0; jm = 0; s = ' '; /* Following keywords are used to describe "-SIP" distortion as used by the Spitzer project... */ /* Is this a primary A keyword? */ } else if( Match( keynam, "A_%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->asip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = ' '; /* Is this a secondary A keyword? */ } else if( Match( keynam, "A_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->asip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary B keyword? */ } else if( Match( keynam, "B_%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->bsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = ' '; /* Is this a secondary B keyword? */ } else if( Match( keynam, "B_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->bsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary AP keyword? */ } else if( Match( keynam, "AP_%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->apsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = ' '; /* Is this a secondary AP keyword? */ } else if( Match( keynam, "AP_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->apsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; /* Is this a primary BP keyword? */ } else if( Match( keynam, "BP_%d_%d", 2, fld, &nfld, method, class, status ) ){ item = &(store->bpsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = ' '; /* Is this a secondary BP keyword? */ } else if( Match( keynam, "BP_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){ item = &(store->bpsip); type = AST__FLOAT; i = fld[ 0 ]; jm = fld[ 1 ]; s = keynam[ strlen( keynam ) - 1 ]; } /* If this keyword was recognized, store it in the FitsStore, and mark it as having been read. */ if( item ){ ok = 1; if( type == AST__FLOAT ){ if( CnvValue( fc, AST__FLOAT, undef, &dval, method, status ) ) { SetItem( (double ****) item, i, jm, s, dval, status ); if( mark ) MarkCard( fc, status ); } else { ok = 0; } } else { if( CnvValue( fc, AST__STRING, undef, &cval, method, status ) ) { cval[ astChrLen( cval ) ] = 0; /* Exclude trailing spaces */ SetItemC( (char *****) item, i, jm, s, cval, status ); if( mark ) MarkCard( fc, status ); } else { ok = 0; } } /* Issue a warning if the value could not be converted to the expected type. */ if( !ok ) { /* First check that the keyword is not included in "fc2". */ if( !HasCard( fc2, keynam, method, class, status ) ) { sprintf( buf, "The original FITS header contained a value for " "keyword %s which could not be converted to a %s.", keynam, ( type==AST__FLOAT ? "floating point number": "character string" ) ); Warn( fc, "badval", buf, "astRead", "FitsChan", status ); } } } /* Move on to the next card. */ MoveCard( fc, 1, method, class, status ); } } static int WcsFromStore( AstFitsChan *this, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * WcsFromStore * Purpose: * Store WCS keywords in a FitsChan using FITS-WCS encoding. * Type: * Private function. * Synopsis: * int WcsFromStore( AstFitsChan *this, FitsStore *store, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function copies the WCS information stored in the supplied * FitsStore into the supplied FitsChan, using FITS-WCS encoding. * Parameters: * this * Pointer to the FitsChan. * store * Pointer to the FitsStore. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. * Returned Value: * A value of 1 is returned if succesfull, and zero is returned * otherwise. */ /* Local Variables: */ char *comm; /* Pointer to comment string */ char *cval; /* Pointer to string keyword value */ char parprefix[3]; /* Prefix for projection parameter keywords */ char combuf[80]; /* Buffer for FITS card comment */ char s; /* Co-ordinate version character */ char sign[2]; /* Fraction's sign character */ char sup; /* Upper limit on s */ char type[MXCTYPELEN];/* Buffer for CTYPE value */ double cdl; /* CDELT value */ double fd; /* Fraction of a day */ double mjd99; /* MJD at start of 1999 */ double val; /* General purpose value */ int *tabaxis; /* Flags WCS axes that use -TAB algorithm */ int i; /* Axis index */ int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */ int iymdf[ 4 ]; /* Year, month, date, fractional day */ int j; /* Axis index */ int jj; /* SlaLib status */ int m; /* Parameter index */ int maxm; /* Upper limit on m */ int naxis; /* Value of NAXIS keyword */ int nc; /* Length of STYPE string */ int nwcs; /* No. of WCS axes */ int ok; /* Frame created succesfully? */ int prj; /* Projection type */ int ret; /* Returned value */ /* Initialise */ ret = 0; /* Other initialisation to avoid compiler warnings. */ tabaxis = NULL; /* Check the inherited status. */ if( !astOK ) return ret; /* If the FitsChan contains a value for the NAXIS keyword, note it. Otherwise store -1. */ if( !astGetFitsI( this, "NAXIS", &naxis ) ) naxis = -1; /* Find the last WCS related card. */ FindWcs( this, 1, 1, 0, method, class, status ); /* Loop round all co-ordinate versions */ sup = GetMaxS( &(store->crval), status ); for( s = ' '; s <= sup && astOK; s++ ){ /* For alternate axes, skip this axis description if there is no CRPIX1 or CRVAL1 value. This avoids partial axis descriptions being written out. */ if( s != ' ' ) { if( GetItem( &(store->crpix), 0, 0, s, NULL, method, class, status ) == AST__BAD || GetItem( &(store->crval), 0, 0, s, NULL, method, class, status ) == AST__BAD ) { ok = 0; goto next; } } /* Assume the Frame can be created succesfully. */ ok = 1; /* Save the number of wcs axes. If a value for WCSAXES has been set, or if the number of axes is not the same as specified in the NAXIS keyword, store a WCSAXES keyword. */ val = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { nwcs = (int) ( val + 0.5 ); } else { nwcs = GetMaxJM( &(store->crpix), s, status ) + 1; if( nwcs != 0 && nwcs != naxis ) val = (double) nwcs; } if( val != AST__BAD ) { SetValue( this, FormatKey( "WCSAXES", -1, -1, s, status ), &nwcs, AST__INT, "Number of WCS axes", status ); } /* Get and save WCSNAME. This is NOT required, so do not return if it is not available. If the WCS is 1-d, only store WCSNAME if its value is different to the CTYPE1 value. */ cval = GetItemC( &(store->wcsname), 0, 0, s, NULL, method, class, status ); if( cval && nwcs == 1 ) { comm = GetItemC( &(store->ctype), 0, 0, s, NULL, method, class, status ); if( comm && Similar( comm, cval, status ) ) cval = NULL; } if( cval ) SetValue( this, FormatKey( "WCSNAME", -1, -1, s, status ), &cval, AST__STRING, "Reference name for the coord. frame", status ); /* The prefix for numerical projection parameters is usually "PV". */ strcpy( parprefix, "PV" ); /* Keywords common to all axis types... */ /* Get and save CRPIX for all pixel axes. These are required, so pass on if they are not available. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->crpix), 0, i, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Reference pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRPIX", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } /* Get and save CRVAL for all WCS axes. These are required, so pass on if they are not available. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 ); SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } /* Allocate memory to indicate if each WCS axis is described by a -TAB algorithm or not. Initialiss it to zero. */ tabaxis = astCalloc( nwcs, sizeof( int ) ); /* Get and save CTYPE for all WCS axes. These are required, so pass on if they are not available. */ for( i = 0; i < nwcs; i++ ) { cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( !cval ) { ok = 0; goto next; } comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm ) { sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 ); comm = combuf; } /* Extract the projection type as specified by the last 4 characters in the CTYPE keyword value. This will be AST__WCSBAD for non-celestial axes. Note, CTYPE can be more than 8 characters long. */ nc = strlen( cval ); prj = ( nc > 4 ) ? astWcsPrjType( cval + nc - 4 ) : AST__WCSBAD; /* If the projection type is "TPN" (an AST-specific code) convert it to standard FITS-WCS code "TAN" and change the prefix for projection parameters from "PV" to "QV". AST will do the inverse conversions when reading such a header. Non-AST software will simply ignore the QV terms and interpret the header as a simple TAN projection. */ if( prj == AST__TPN ) { strcpy( parprefix, "QV" ); strcpy( type, cval ); (void) strcpy( type + nc - 4, "-TAN" ); cval = type; } /* Note if the axis is described by the -TAB algorithm. */ tabaxis[ i ] = ( prj == AST__WCSBAD && strlen( cval ) >= 8 && !strncmp( cval + 4, "-TAB", 4 ) ); /* Store the (potentially modified) CTYPE value. */ SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING, comm, status ); } /* Get and save CNAME for all WCS axes. These are NOT required, so do not pass on if they are not available. Do not include a CNAME keyword if its value equals the commen or value of the corresponding CTYPE keyword. */ for( i = 0; i < nwcs; i++ ) { cval = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status ); if( cval ) { comm = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( !comm || strcmp( comm, cval ) ) { comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !comm || strcmp( comm, cval ) ) { sprintf( combuf, "Description of axis %d", i + 1 ); SetValue( this, FormatKey( "CNAME", i + 1, -1, s, status ), &cval, AST__STRING, combuf, status ); } } } } /* Now choose whether to produce CDi_j or CDELT/PCi_j keywords. */ if( astGetCDMatrix( this ) ) { /* CD matrix. Multiply the row of the PC matrix by the CDELT value. */ for( i = 0; i < nwcs; i++ ) { cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( cdl == AST__BAD ) cdl = 1.0; for( j = 0; j < nwcs; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0; val *= cdl; if( val != 0.0 ) { SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val, AST__FLOAT, "Transformation matrix element", status ); } } } /* If producing PC/CDELT keywords... */ } else { /* CDELT keywords. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status ); if( val == AST__BAD ) { ok = 0; goto next; } sprintf( combuf, "Pixel size on axis %d", i + 1 ); SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } /* PC matrix. */ for( i = 0; i < nwcs; i++ ) { for( j = 0; j < nwcs; j++ ){ val = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); if( val != AST__BAD ) { if( i == j ) { if( EQUAL( val, 1.0 ) ) val = AST__BAD; } else { if( EQUAL( val, 0.0 ) ) val = AST__BAD; } } if( val != AST__BAD ) { SetValue( this, FormatKey( "PC", i + 1, j + 1, s, status ), &val, AST__FLOAT, "Transformation matrix element", status ); } } } } /* Get and save CUNIT for all WCS axes. These are NOT required, so do not pass on if they are not available. */ for( i = 0; i < nwcs; i++ ) { cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( cval ) { sprintf( combuf, "Units for axis %d", i + 1 ); SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING, combuf, status ); } } /* Get and save AXREF for all WCS axes. These are NOT required, so do not pass on if they are not available. Note, AXREF is a non-standard keyword used by AST to communicate the reference position on any axes described by the -TAB algorithm and which has no inverse transformation. For all other cases, the reference position corresponds to the values of CRVAL. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->axref), i, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { sprintf( combuf, "Reference WCS value on axis %d", i + 1 ); SetValue( this, FormatKey( "AXREF", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save SREFIS. This is NOT required, so do not return if it is not available. Note, SREFIS is a non-standard keyword used by AST to communicate the SkyRefIs attribute in the original SkyFrame. */ cval = GetItemC( &(store->skyrefis), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, FormatKey( "SREFIS", -1, -1, s, status ), &cval, AST__STRING, "Is SkyRef used as pole or origin?", status ); /* Get and save SREF for all WCS axes. These are NOT required, so do not pass on if they are not available. Note, SREF is a non-standard keyword used by AST to communicate the SkyRef position on any axes described by a offset SkyFrame. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->skyref), i, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { sprintf( combuf, "Sky reference position on axis %d", i + 1 ); SetValue( this, FormatKey( "SREF", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Get and save SREFP for all WCS axes. These are NOT required, so do not pass on if they are not available. Note, SREFP is a non-standard keyword used by AST to communicate the SkyRefP position on any axes described by a offset SkyFrame. */ for( i = 0; i < nwcs; i++ ) { val = GetItem( &(store->skyrefp), i, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { sprintf( combuf, "Sky primary meridian position on axis %d", i + 1 ); SetValue( this, FormatKey( "SREFP", i + 1, -1, s, status ), &val, AST__FLOAT, combuf, status ); } } /* Date of observation (only allowed for primary axis descriptions). */ if( s == ' ' ) { val = GetItem( &(store->mjdobs), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { SetValue( this, FormatKey( "MJD-OBS", -1, -1, s, status ), &val, AST__FLOAT, "Modified Julian Date of observation", status ); /* The format used for the DATE-OBS keyword depends on the value of the keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format. Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */ palCaldj( 99, 1, 1, &mjd99, &jj ); if( val < mjd99 ) { palDjcal( 0, val, iymdf, &jj ); sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ], iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) ); } else { palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj ); palDd2tf( 3, fd, sign, ihmsf ); sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d", iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1], ihmsf[2], ihmsf[3] ); } /* Now store the formatted string in the FitsChan. */ cval = combuf; SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING, "Date of observation", status ); } val = GetItem( &(store->mjdavg), 0, 0, ' ', NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "MJD-AVG", &val, AST__FLOAT, "Average Modified Julian Date of observation", status ); /* Store the timescale in TIMESYS. */ cval = GetItemC( &(store->timesys), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, "TIMESYS", &cval, AST__STRING, "Timescale for MJD-OBS/MJD-AVG values", status ); } /* Numerical projection parameters */ maxm = GetMaxJM( &(store->pv), s, status ); for( i = 0; i < nwcs; i++ ){ for( m = 0; m <= maxm; m++ ){ val = GetItem( &(store->pv), i, m, s, NULL, method, class, status ); if( val != AST__BAD ) { /* If the axis uses the "TAB" algorithm, there may be a PVi_4a parameter in the FitsStore. This is an AST extension to the published -TAB algorithm, and is used to hold the interpolation method. To avoid clashing with any standard use of PV1_4a, rename it to QVi_4a. The default is zero (linear interpolation) so do not write the QV value if it zero. */ if( m == 4 && tabaxis[ i ] ) { if( val != 0.0 ) { SetValue( this, FormatKey( "QV", i + 1, m, s, status ), &val, AST__FLOAT, "Use nearest neighbour " "interpolation", status ); } /* Just store the parameters for other type of axes. */ } else { SetValue( this, FormatKey( parprefix, i + 1, m, s, status ), &val, AST__FLOAT, "Projection parameter", status ); } } } } /* String projection parameters */ maxm = GetMaxJMC( &(store->ps), s, status ); for( i = 0; i < nwcs; i++ ){ for( m = 0; m <= maxm; m++ ){ cval = GetItemC( &(store->ps), i, m, s, NULL, method, class, status ); if( cval ) { SetValue( this, FormatKey( "PS", i + 1, m, s, status ), &cval, AST__STRING, "Projection parameter", status ); } } } /* Keywords specific to celestial axes... */ /* Get and save RADESYS. This is NOT required, so do not return if it is not available. */ cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, FormatKey( "RADESYS", -1, -1, s, status ), &cval, AST__STRING, "Reference frame for RA/DEC values", status ); /* Reference equinox */ val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "EQUINOX", -1, -1, s, status ), &val, AST__FLOAT, "[yr] Epoch of reference equinox", status ); /* Latitude of native north pole */ val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "LATPOLE", -1, -1, s, status ), &val, AST__FLOAT, "[deg] Latitude of native north pole", status ); /* Longitude of native north pole */ val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "LONPOLE", -1, -1, s, status ), &val, AST__FLOAT, "[deg] Longitude of native north pole", status ); /* Keywords specific to spectral axes... */ /* SPECSYS - the standard of rest for the spectral axis */ cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, FormatKey( "SPECSYS", -1, -1, s, status ), &cval, AST__STRING, "Standard of rest for spectral axis", status ); /* SSYSSRC - the standard of rest in which ZSOURCE is stored. */ cval = GetItemC( &(store->ssyssrc), 0, 0, s, NULL, method, class, status ); if( cval ) SetValue( this, FormatKey( "SSYSSRC", -1, -1, s, status ), &cval, AST__STRING, "Standard of rest for source redshift", status ); /* ZSOURCE - topocentric optical velocity of source */ val = GetItem( &(store->zsource), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "ZSOURCE", -1, -1, s, status ), &val, AST__FLOAT, "[] Redshift of source", status ); /* VELOSYS - topocentric apparent radial velocity of the standard of rest. */ val = GetItem( &(store->velosys), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "VELOSYS", -1, -1, s, status ), &val, AST__FLOAT, "[m/s] Topo. apparent velocity of rest frame", status ); /* RESTFRQ - rest frequency */ val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFRQ", -1, -1, s, status ), &val, AST__FLOAT, "[Hz] Rest frequency", status ); /* RESTWAV - rest wavelength */ val = GetItem( &(store->restwav), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, FormatKey( "RESTWAV", -1, -1, s, status ), &val, AST__FLOAT, "[m] Rest wavelength", status ); /* The image frequency corresponding to the rest frequency (only used for double sideband data). This is not part of the FITS-WCS standard but is added for the benefit of JACH. */ val = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) { SetValue( this, "IMAGFREQ", &val, AST__FLOAT, "[Hz] Image frequency", status ); } /* OBSGEO-X/Y/Z - observer's geocentric coords. Note, these always refer to the primary axes. */ if( s == ' ' ) { val = GetItem( &(store->obsgeox), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "OBSGEO-X", &val, AST__FLOAT, "[m] Observatory geocentric X", status ); val = GetItem( &(store->obsgeoy), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "OBSGEO-Y", &val, AST__FLOAT, "[m] Observatory geocentric Y", status ); val = GetItem( &(store->obsgeoz), 0, 0, s, NULL, method, class, status ); if( val != AST__BAD ) SetValue( this, "OBSGEO-Z", &val, AST__FLOAT, "[m] Observatory geocentric Z", status ); } /* See if a Frame was sucessfully written to the FitsChan. */ next: ok = ok && astOK; /* If so, indicate we have something to return. */ if( ok ) ret = 1; /* If we are producing secondary axes, clear any error status so we can continue to produce the next Frame. Retain the error if the primary axes could not be produced. After the primary axes, do the A axes. */ if( s != ' ' ) { astClearStatus; } else { s = 'A' - 1; } /* Remove the secondary "new" flags from the FitsChan. This flag is associated with cards which have been added to the FitsChan during this pass through the main loop in this function. If the Frame was written out succesfully, just clear the flags. If anything went wrong with this Frame, remove the flagged cards from the FitsChan. */ FixNew( this, NEW2, !ok, method, class, status ); /* Set the current card so that it points to the last WCS-related keyword in the FitsChan (whether previously read or not). */ FindWcs( this, 1, 1, 0, method, class, status ); /* Free resources. */ tabaxis = astFree( tabaxis ); } /* Return zero or ret depending on whether an error has occurred. */ return astOK ? ret : 0; } static AstMapping *WcsIntWorld( AstFitsChan *this, FitsStore *store, char s, int naxes, const char *method, const char *class, int *status ){ /* * Name: * WcsIntWorld * Purpose: * Create a Mapping from pixel coords to intermediate world coords. * Type: * Private function. * Synopsis: * AstMapping *WcsIntWorld( AstFitsChan *this, FitsStore *store, char s, * int naxes, const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function interprets the contents of the supplied FitsStore * structure, and creates a Mapping which describes the transformation * from pixel coordinates to intermediate world coordinates, using the * FITS World Coordinate System conventions. This is a general linear * transformation described by the CRPIXj, PCi_j and CDELTi keywords. * Parameters: * this * The FitsChan. ASTWARN cards may be added to this FitsChan if any * anomalies are found in the keyword values in the FitsStore. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstMapping *mapd1; /* Pointer to first distortion Mapping */ AstMapping *mapd2; /* Pointer to second distortion Mapping */ AstMapping *mapd3; /* Pointer to third distortion Mapping */ AstMapping *mapd4; /* Pointer to fourth distortion Mapping */ AstMapping *map0; /* Pointer to a Mapping */ AstMapping *map1; /* Pointer to a Mapping */ AstMapping *ret; /* Pointer to the returned Mapping */ /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* First of all, check the CTYPE keywords to see if they contain any known distortion codes (following the syntax described in FITS-WCS paper IV). If so, Mappings are returned which represents the distortions to be applied at each point in the chain of Mappings produced by this function. Any distortion codes are removed from the CTYPE values in the FitsStore. */ DistortMaps( this, store, s, naxes, &mapd1, &mapd2, &mapd3, &mapd4, method, class, status ); /* If distortion is to be applied now, initialise the returned Mapping to be the distortion. */ if( mapd1 ) ret = mapd1; /* Try to create a WinMap which translates the pixel coordinates so that they are refered to an origin at the reference pixel. This subtracts the value of CRPIXi from axis i. */ map1 = (AstMapping *) WcsShift( store, s, naxes, method, class, status ); /* Combine this with any previous Mapping. */ if( ret ) { map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status ); ret = astAnnul( ret ); map1 = astAnnul( map1 ); ret = map0; } else { ret = map1; } /* If distortion is to be applied now, combine the two Mappings. */ if( mapd2 ) { map0 = (AstMapping *) astCmpMap( ret, mapd2, 1, "", status ); ret = astAnnul( ret ); mapd2 = astAnnul( mapd2 ); ret = map0; } /* Now try to create a MatrixMap to implement the PC matrix. Combine it with the above Mapping. Add a Warning if this mapping cannot be inverted. */ map1 = (AstMapping *) WcsPCMatrix( store, s, naxes, method, class, status ); if( !astGetTranInverse( map1 ) ) { Warn( this, "badmat", "The pixel rotation matrix in the original FITS " "header (specified by CD or PC keywords) could not be inverted. " "This may be because the matrix contains rows or columns which " "are entirely zero.", method, class, status ); } map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status ); ret = astAnnul( ret ); map1 = astAnnul( map1 ); ret = map0; /* If distortion is to be applied now, combine the two Mappings. */ if( mapd3 ) { map0 = (AstMapping *) astCmpMap( ret, mapd3, 1, "", status ); ret = astAnnul( ret ); mapd3 = astAnnul( mapd3 ); ret = map0; } /* Now try to create a diagonal MatrixMap to implement the CDELT scaling. Combine it with the above Mapping. */ map1 = (AstMapping *) WcsCDeltMatrix( store, s, naxes, method, class, status ); map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status ); ret = astAnnul( ret ); map1 = astAnnul( map1 ); ret = map0; /* If distortion is to be applied now, combine the two Mappings. */ if( mapd4 ) { map0 = (AstMapping *) astCmpMap( ret, mapd4, 1, "", status ); ret = astAnnul( ret ); mapd4 = astAnnul( mapd4 ); ret = map0; } /* Return the result. */ return ret; } static AstMapping *WcsMapFrm( AstFitsChan *this, FitsStore *store, char s, AstFrame **frm, const char *method, const char *class, int *status ){ /* * Name: * WcsMapFrm * Purpose: * Create a Mapping and Frame for the WCS transformations described in a * FITS header. * Type: * Private function. * Synopsis: * AstMapping *WcsMapFrm( AstFitsChan *this, FitsStore *store, char s, * AstFrame **frm, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function interprets the contents of the supplied FitsStore * structure, and creates a Mapping which describes the transformation * from pixel coordinates to world coordinates, using the FITS World * Coordinate System conventions. It also creates a Frame describing * the world coordinate axes. * Parameters: * this * The FitsChan. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * frm * The address of a location at which to store a pointer to the * Frame describing the world coordinate axes. If the Iwc attribute * is non-zero, then this is actually a FrameSet in which the current * Frame is the required WCS system. The FrameSet also contains one * other Frame which defines the FITS IWC system. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstFrame *iwcfrm; /* Frame defining IWC system */ AstFrameSet *fs; /* Pointer to returned FrameSet */ AstMapping *map10; /* Pointer to a Mapping */ AstMapping *map1; /* Pointer to a Mapping */ AstMapping *map2; /* Pointer to a Mapping */ AstMapping *map3; /* Pointer to a Mapping */ AstMapping *map4; /* Pointer to a Mapping */ AstMapping *map5; /* Pointer to a Mapping */ AstMapping *map6; /* Pointer to a Mapping */ AstMapping *map7; /* Pointer to a Mapping */ AstMapping *map8; /* Pointer to a Mapping */ AstMapping *map9; /* Pointer to a Mapping */ AstMapping *ret; /* Pointer to the returned Mapping */ AstMapping *tabmap; /* Mapping from psi to WCS (paper III - 6.1.2) */ AstSkyFrame *reffrm; /* SkyFrame defining reflon and reflat */ char id[2]; /* ID string for returned Frame */ char iwc[5]; /* Domain name for IWC Frame */ const char *cc; /* Pointer to Domain */ double dut1; /* UT1-UTC correction in days */ double dval; /* Temporary double value */ double reflat; /* Reference celestial latitude */ double reflon; /* Reference celestial longitude */ int *tabaxis; /* Flags indicating -TAB axes */ int wcsaxes; /* Number of physical axes */ /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Identify any axes that use the -TAB algoritm code described in FITS-WCS paper III, and convert their CTYPE values to describe linear axes (i.e. just remove "-TAB" from the CTYPE value). This also returns a Mapping (which includes one or more LutMaps) that should be applied to the resulting linear axis values in order to generate the final WCS axis values. A NULL pointer is returned if no axes use -TAB. */ tabmap = TabMapping( this, store, s, &tabaxis, method, class, status ); /* Obtain the number of physical axes in the header. If the WCSAXES header was specified, use it. Otherwise assume it is the same as the number of pixel axes. */ dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) { wcsaxes = (int) dval + 0.5; } else { wcsaxes = store->naxis; } /* Create a simple Frame to represent IWC coords. */ iwcfrm = astFrame( wcsaxes, "Title=FITS Intermediate World Coordinates", status ); strcpy( iwc, "IWC" ); iwc[ 3 ]= s; iwc[ 4 ]= 0; astSetDomain( iwcfrm, iwc ); /* Create a simple Frame which will be used as the initial representation for the physical axes. This Frame will be changed later (or possibly replaced by a Frame of another class) when we know what type of physical axes we are dealing with. Set its Domain to "AST_FITSCHAN" This value is used to identify axes which have not been changed, and will be replaced before returning the final FrameSet. */ *frm = astFrame( wcsaxes, "Domain=AST_FITSCHAN", status ); /* Store the coordinate version character as the Ident attribute for the returned Frame. */ id[ 0 ] = s; id[ 1 ] = 0; astSetIdent( *frm, id ); /* Create a Mapping which goes from pixel coordinates to what FITS-WCS paper I calls "intermediate world coordinates". This stage is the same for all axes. It uses the CRPIXj, PCi_j and CDELTi headers (and distortion codes from the CTYPE keywords). */ map1 = WcsIntWorld( this, store, s, wcsaxes, method, class, status ); /* The conversion from intermediate world coordinates to the final world coordinates depends on the type of axis being converted (as specified by its CTYPE keyword). Check for each type of axis for which known conventions exist... */ /* Celestial coordinate axes. The following call returns a Mapping which transforms any celestial coordinate axes from intermediate world coordinates to the final celestial coordinates. Other axes are left unchanged by the Mapping. It also modifies the Frame so that a SkyFrame is used to describe the celestial axes. */ map2 = WcsCelestial( this, store, s, frm, iwcfrm, &reflon, &reflat, &reffrm, &tabmap, tabaxis, method, class, status ); /* Spectral coordinate axes. The following call returns a Mapping which transforms any spectral coordinate axes from intermediate world coordinates to the final spectral coordinates. Other axes are left unchanged by the Mapping. It also modifies the Frame so that a SpecFrame is used to describe the spectral axes. */ map3 = WcsSpectral( this, store, s, frm, iwcfrm, reflon, reflat, reffrm, method, class, status ); /* Any axes which were not recognized by the above calls are assumed to be linear. Create a Mapping which adds on the reference value for such axes, and modify the Frame to desribe the axes. */ map4 = WcsOthers( this, store, s, frm, iwcfrm, method, class, status ); /* If the Frame still has the Domain "AST_FITSCHAN", clear it. */ cc = astGetDomain( *frm ); if( cc && !strcmp( cc, "AST_FITSCHAN" ) ) astClearDomain( *frm ); /* Concatenate the Mappings and simplify the result. */ map5 = (AstMapping *) astCmpMap( map1, map2, 1, "", status ); map6 = (AstMapping *) astCmpMap( map5, map3, 1, "", status ); map7 = (AstMapping *) astCmpMap( map6, map4, 1, "", status ); if( tabmap ) { map8 = (AstMapping *) astCmpMap( map7, tabmap, 1, "", status ); } else { map8 = astClone( map7 ); } ret = astSimplify( map8 ); /* Ensure that the coordinate version character is stored as the Ident attribute for the returned Frame (the above calls may have changed it). */ astSetIdent( *frm, id ); /* Set the DUT1 value. Note, the JACH store DUT1 in units of days in their FITS headers, so convert from days to seconds. May need to do somthing about this if the forthcoming FITS-WCS paper 5 (time axes) defines DUT1 to be in seconds. */ dut1 = GetItem( &(store->dut1), 0, 0, s, NULL, method, class, status ); if( dut1 != AST__BAD ) astSetDut1( *frm, dut1*SPD ); /* The returned Frame is actually a FrameSet in which the current Frame is the required WCS Frame. The FrameSet contains one other Frame, which is the Frame representing IWC. Create a FrameSet containing these two Frames. */ if( astGetIwc( this ) ) { fs = astFrameSet( iwcfrm, "", status ); astInvert( map1 ); map9 = (AstMapping *) astCmpMap( map1, ret, 1, "", status ); astInvert( map1 ); map10 = astSimplify( map9 ); astAddFrame( fs, AST__BASE, map10, *frm ); /* Return this FrameSet instead of the Frame. */ *frm = astAnnul( *frm ); *frm = (AstFrame *) fs; /* Free resources */ map9 = astAnnul( map9 ); map10 = astAnnul( map10 ); } /* Annull temporary resources. */ if( reffrm ) reffrm = astAnnul( reffrm ); if( tabmap ) tabmap = astAnnul( tabmap ); tabaxis = astFree( tabaxis ); iwcfrm = astAnnul( iwcfrm ); map1 = astAnnul( map1 ); map2 = astAnnul( map2 ); map3 = astAnnul( map3 ); map4 = astAnnul( map4 ); map5 = astAnnul( map5 ); map6 = astAnnul( map6 ); map7 = astAnnul( map7 ); map8 = astAnnul( map8 ); /* Annul thre returned objects if an error has occurred. */ if( !astOK ) { ret = astAnnul( ret ); *frm = astAnnul( *frm ); } /* Return the result. */ return ret; } static AstMatrixMap *WcsPCMatrix( FitsStore *store, char s, int naxes, const char *method, const char *class, int *status ){ /* * Name: * WcsPCMatrix * Purpose: * Create a MatrixMap representing the PC matrix. * Type: * Private function. * Synopsis: * AstMatrixMap *WcsPCMatrix( FitsStore *store, char s, int naxes, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A MatrixMap representing the FITS "PC" matrix is returned. * Parameters: * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character s identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the created MatrixMap or a NULL pointer if an * error occurred. */ /* Local Variables: */ AstMatrixMap *new; /* The created MatrixMap */ double *el; /* Pointer to next matrix element */ double *mat; /* Pointer to matrix array */ int i; /* Pixel axis index */ int j; /* Intermediate axis index. */ /* Initialise/ */ new = NULL; /* Check the global status. */ if ( !astOK ) return new; /* Allocate memory for the matrix. */ mat = (double *) astMalloc( sizeof(double)*naxes*naxes ); if( astOK ){ /* Fill the matrix with values from the FitsStore. */ el = mat; for( i = 0; i < naxes; i++ ){ for( j = 0; j < naxes; j++ ){ /* Get the PCj_i value for this axis. Missing terms can be defaulted so do not report an error if the required value is not present in the FitsStore. */ *el = GetItem( &(store->pc), i, j, s, NULL, method, class, status ); /* Diagonal terms default to to 1.0, off-diagonal to zero. */ if( *el == AST__BAD ) *el = ( i == j ) ? 1.0: 0.0; /* Move on to the next matrix element. */ el++; } } /* Create the matrix. */ new = astMatrixMap( naxes, naxes, 0, mat, "", status ); /* Report an error if the inverse transformation is undefined. */ if( !astGetTranInverse( new ) && astOK ) { astError( AST__BDFTS, "%s(%s): Unusable rotation matrix (PC or CD) found " "in the FITS-WCS header - the matrix cannot be inverted.", status, method, class ); } /* Release the memory used to hold the matrix. */ mat = (double *) astFree( (void *) mat ); } /* If an error has occurred, attempt to annul the returned MatrixMap. */ if( !astOK ) new = astAnnul( new ); /* Return the MatrixMap. */ return new; } static AstMapping *WcsNative( AstFitsChan *this, FitsStore *store, char s, AstWcsMap *wcsmap, int fits_ilon, int fits_ilat, const char *method, const char *class, int *status ){ /* * Name: * WcsNative * Purpose: * Create a CmpMap which transforms Native Spherical Coords to * Celestial Coords. * Type: * Private function. * Synopsis: * AstMapping *WcsNative( AstFitsChan *this, FitsStore *store, char s, * AstWcsMap *wcsmap, int fits_ilon, int fits_ilat, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A CmpMap is created which rotates the supplied Native Spherical Coords * into Celestial Coords in the standard system specified by the CTYPE * keywords. Any non-celestial axes are left unchanged. * * At the highest level, the returned CmpMap is made up of the following * Mappings in series (if celestial long/lat axes are present): * 1 - A PermMap which rearranges the axes so that the longitude axis is * axis 0, the latitude axis is axis 1, and all other axes are * stored at higher indices, starting at axis 2. * 2 - A CmpMap which converts the values on axes 0 and 1 from Native * Spherical to Celestial coordinates, leaving all other axes * unchanged. * 3 - A PermMap which rearranges the axes to put the longitude and * latitude axes back in their original places. This is just the * inverse of the PermMap used at stage 1 above. * * The CmpMap used at stage 2 above, is made up of two Mappings in * parallel: * 4 - A CmpMap which maps axes 0 and 1 from Native Spherical to * Celestial coordinates. * 5 - A UnitMap which passes on the values to axes 2, 3, etc, * without change. * * The CmpMap used at stage 4 above, is made up of the following Mappings * in series: * 6 - A SphMap which converts the supplied spherical coordinates into * Cartesian Coordinates. * 7 - A MatrixMap which rotates the Cartesian coordinates from the * Native to the Celestial system. * 8 - A SphMap which converts the resulting Cartesian coordinates back * to spherical coordinates. * Parameters: * this * The FitsChan in which to store any warning cards. If NULL, no * warnings are stored. * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * Co-ordinate version character to use (space means primary axes). * wcsmap * A mapping describing the deprojection which is being used. This is * needed in order to be able to locate the fiducial point within the * Native Speherical Coordinate system, since it varies from projection * to projection. * fits_ilon * The zero-based FITS WCS axis index corresponding to celestial * longitude (i.e. one less than the value of "i" in the keyword * names "CTYPEi", "CRVALi", etc). If -1 is supplied, the index of * the longitude axis in the supplied WcsMap is used. * fits_ilat * The zero-based FITS WCS axis index corresponding to celestial * latitude (i.e. one less than the value of "i" in the keyword * names "CTYPEi", "CRVALi", etc). If -1 is supplied, the index of * the latitude axis in the supplied WcsMap is used. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the created CmpMap or a NULL pointer if an error occurred. * Notes: * - The local variable names correspond to the notation in the papers * by Greisen & Calabretta describing the FITS WCS system. */ /* Local Variables: */ AstCmpMap *cmpmap; /* A CmpMap */ AstMapping *new; /* The returned CmpMap */ AstMatrixMap *matmap2; /* Another MatrixMap */ AstMatrixMap *matmap; /* A MatrixMap */ AstPermMap *permmap; /* A PermMap */ AstSphMap *sphmap; /* A SphMap */ AstUnitMap *unitmap; /* A UnitMap */ char buf[150]; /* Message buffer */ double alpha0; /* Long. of fiduaicl point in standard system */ double alphap; /* Long. of native nth pole in standard system */ double axis[3]; /* Vector giving the axis of rotation */ double delta0; /* Lat. of fiducial point in standard system */ double deltap; /* Lat. of native nth pole in standard system */ double latpole; /* Lat. of native nth pole in standard system if deltap undefined */ double phip; /* Long. of standard nth pole in native system */ double phi0; /* Native longitude at fiducial point */ double theta0; /* Native latitude at fiducial point */ int *inperm; /* Pointer to array of output axis indices */ int *outperm; /* Pointer to array of input axis indices */ int axlat; /* Index of latitude physical axis */ int axlon; /* Index of longitude physical axis */ int i; /* Loop count */ int nax_rem; /* No. of non-astrometric axes */ int naxis; /* No. of axes. */ int new_axlat; /* Index of lat. physical axis after perming */ int tpn; /* Is this a TPN projection? */ /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the returned CmpMap pointer. */ new = NULL; /* Store the number of axes in a local variable. */ naxis = astGetNin( wcsmap ); /* Get the indices of the celestial axes. */ axlon = astGetWcsAxis( wcsmap, 0 ); axlat = astGetWcsAxis( wcsmap, 1 ); /* If the corresponding FITS axis indices were not supplied, use the WcsMap axes found above. */ if( fits_ilon == -1 ) fits_ilon = axlon; if( fits_ilat == -1 ) fits_ilat = axlat; /* If there is no longitude or latitude axis, or if we have a non-celestial projection, just return a UnitMap. */ if( axlon == axlat || astGetWcsType( wcsmap ) == AST__WCSBAD ){ new = (AstMapping *) astUnitMap( naxis, "", status ); /* If there is a lon/lat axis pair, create the inperm and outperm arrays which will be needed later to create the PermMap which reorganises the axes so that axis zero is the longitude axis and axis 1 is the latitude axis. */ } else { /* Get storage for the two arrays. */ inperm = (int *) astMalloc( sizeof( int )*(size_t)naxis ); outperm = (int *) astMalloc( sizeof( int )*(size_t)naxis ); if( astOK ){ /* Initialise an array holding the indices of the input axes which are copied to each output axis. Initially assume that there is no re-arranging of the axes. */ for( i = 0; i < naxis; i++ ) outperm[ i ] = i; /* Swap the longitude axis and axis 0. */ i = outperm[ axlon ]; outperm[ axlon ] = outperm[ 0 ]; outperm[ 0 ] = i; /* If axis 0 was originally the latitude axis, the latitude axis will now be where the longitude axis was originally (because of the above axis swap). */ if( axlat == 0 ) { new_axlat = axlon; } else { new_axlat = axlat; } /* Swap the latitude axis and axis 1. */ i = outperm[ new_axlat ]; outperm[ new_axlat ] = outperm[ 1 ]; outperm[ 1 ] = i; /* Create the array holding the output axis index corresponding to each input axis. */ for( i = 0; i < naxis; i++ ) inperm[ outperm[ i ] ] = i; } /* Store the latitude and longitude (in the standard system) of the fiducial point, in radians. */ delta0 = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status ); if( delta0 == AST__BAD ) delta0 = 0.0; delta0 *= AST__DD2R; alpha0 = GetItem( &(store->crval), fits_ilon, 0, s, NULL, method, class, status ); if( alpha0 == AST__BAD ) alpha0 = 0.0; alpha0 *= AST__DD2R; /* Limit the latitude to the range +/- PI/2, issuing a warning if the supplied CRVAL value is outside this range. The "alphap" variable is used as workspace here. */ alphap = palDrange( delta0 ); delta0 = alphap; if ( delta0 > AST__DPIBY2 ){ delta0 = AST__DPIBY2; } else if ( delta0 < -AST__DPIBY2 ){ delta0 = -AST__DPIBY2; } if( alphap != delta0 ) { sprintf( buf, "The original FITS header specified a fiducial " "point with latitude %.*g. A value of %.*g is being used " "instead. ", DBL_DIG, alphap*AST__DR2D, DBL_DIG, delta0*AST__DR2D ); Warn( this, "badlat", buf, method, class, status ); } /* Set a flag indicating if we have a TPN projection. The handling or projection parameters is different for TPN projections. */ tpn = ( astGetWcsType( wcsmap ) == AST__TPN ); /* Store the radian values of the FITS keywords LONPOLE and LATPOLE. Defaults will be used if either of these items was not supplied. These keyword values may be stored in projection parameters PVi_3a and PVi_4a for longitude axis "i" - in which case the "PV" values take precedence over the "LONPOLE" and "LATPOLE" values. Do not do this for TPN projections since they use these projection parameters to specify correcton terms. */ if( astTestPV( wcsmap, axlon, 3 ) && !tpn ) { phip = astGetPV( wcsmap, axlon, 3 ); } else { phip = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status ); if( phip != AST__BAD && !tpn ) astSetPV( wcsmap, axlon, 3, phip ); } if( phip != AST__BAD ) phip *= AST__DD2R; if( astTestPV( wcsmap, axlon, 4 ) && !tpn ) { latpole = astGetPV( wcsmap, axlon, 4 ); } else { latpole = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status ); if( latpole != AST__BAD && !tpn ) astSetPV( wcsmap, axlon, 4, latpole ); } if( latpole != AST__BAD ) latpole *= AST__DD2R; /* Find the standard Celestial Coordinates of the north pole of the Native Spherical Coordinate system. Report an error if the position was not defined. */ if( !WcsNatPole( this, wcsmap, alpha0, delta0, latpole, &phip, &alphap, &deltap, status ) && astOK ){ astError( AST__BDFTS, "%s(%s): Conversion from FITS WCS native " "coordinates to celestial coordinates is ill-conditioned.", status, method, class ); } /* Create the SphMap which converts spherical coordinates to Cartesian coordinates (stage 6 in the prologue). This asumes that axis 0 is the longitude axis, and axis 1 is the latitude axis. This will be ensured by a PermMap created later. Indicate that the SphMap will only be used to transform points on a unit sphere. This enables a forward SphMap to be combined with an inverse SphMap into a UnitMap, and thus aids simplification. */ sphmap = astSphMap( "UnitRadius=1", status ); astInvert( sphmap ); /* Set the PolarLong attribute of the SphMap so that a longitude of phi0 (the native longitude of the fiducial point) is returned by the inverse transformation (cartesian->spherical) at either pole. */ GetFiducialNSC( wcsmap, &phi0, &theta0, status ); astSetPolarLong( sphmap, phi0 ); /* Create a unit MatrixMap to be the basis of the MatrixMap which rotates Native Spherical Coords to Celestial Coords (stage 7 in the prologue). */ matmap = astMatrixMap( 3, 3, 2, NULL, "", status ); /* Modify the above MatrixMap so that it rotates the Cartesian position vectors by -phip (i.e. LONPOLE) about the Z axis. This puts the north pole of the standard system at zero longitude in the rotated system. Then annul the original MatrixMap and use the new one instead. */ axis[ 0 ] = 0; axis[ 1 ] = 0; axis[ 2 ] = 1; matmap2 = astMtrRot( matmap, -phip, axis ); matmap = astAnnul( matmap ); matmap = matmap2; /* Now modify the above MatrixMap so that it rotates the Cartesian position vectors by -(PI/2-deltap) about the Y axis. This puts the north pole of the standard system as 90 degrees latitude in the rotated system. Then annul the original MatrixMap and use the new one instead. */ axis[ 0 ] = 0; axis[ 1 ] = 1; axis[ 2 ] = 0; matmap2 = astMtrRot( matmap, deltap - AST__DPIBY2, axis ); matmap = astAnnul( matmap ); matmap = matmap2; /* Finally modify the above MatrixMap so that it rotates the Cartesian position vectors (PI+alphap) about the Z axis. This puts the primary meridian of the standard system at zero longitude in the rotated system. This results in the rotated system being coincident with the standard system. */ axis[ 0 ] = 0; axis[ 1 ] = 0; axis[ 2 ] = 1; matmap2 = astMtrRot( matmap, AST__DPI + alphap, axis ); matmap = astAnnul( matmap ); matmap = matmap2; /* Combine the SphMap (stage 6) and MatrixMap (stage 7) in series. */ cmpmap = astCmpMap( sphmap, matmap, 1, "", status ); sphmap = astAnnul( sphmap ); matmap = astAnnul( matmap ); /* Create a new SphMap which converts Cartesian coordinates to spherical coordinates (stage 8 in the prologue). Indicate that the SphMap will only be used to transform points on a unit sphere. */ sphmap = astSphMap( "UnitRadius=1", status ); /* Set the PolarLong attribute of the SphMap so that a longitude of alpha0 (the celestial longitude of the fiducial point) is returned by the forward transformation (cartesian->spherical) at either pole. */ astSetPolarLong( sphmap, alpha0 ); /* Add it to the compound mapping. The CmpMap then corresponds to stage 4 in the prologue. Annul the constituent mappings. */ new = (AstMapping *) astCmpMap( cmpmap, sphmap, 1, "", status ); cmpmap = astAnnul( cmpmap ); sphmap = astAnnul( sphmap ); /* If there are any remaining axes (i.e. axes which do not describe a Celestial coordinate system), create a UnitMap which passes on their values unchanged (stage 5 in the prologue), and add it the CmpMap, putting it in parallel with the earlier mappings. The resulting CmpMap then corresponds to stage 2 in the prologue. Note, the axis numbering used by this UnitMap needs to take account of the fact that it is only applied to the non-celestial axes. The axes are re-ordered by the PermMap described at stage 1 in the prologue. */ nax_rem = naxis - 2; if( nax_rem > 0 ){ unitmap = astUnitMap( nax_rem, "", status ); cmpmap = astCmpMap( new, unitmap, 0, "", status ); new = astAnnul( new ); unitmap = astAnnul( unitmap ); new = (AstMapping *) cmpmap; } /* Now we need to ensure that axes 0 and 1 correspond to longitude and latitude. If this is already the case, then the CmpMap can be returned as it is. Otherwise, a PermMap needs to be created to rearrange the axes. */ if( axlon != 0 || axlat != 1 ){ /* Create the PermMap using the inperm and outperm arrays created earlier. This is the mapping described as stage 1 in the prologue. */ permmap = astPermMap( naxis, inperm, naxis, outperm, NULL, "", status ); /* Compound this PermMap and the CmpMap corresponding to stage 2 (created earlier) in series. */ cmpmap = astCmpMap( permmap, new, 1, "", status ); new = astAnnul( new ); new = (AstMapping *) cmpmap; /* Now invert the PermMap, so that it re-arranges the axes back into their original order. This is the mapping described as stage 3 in the prologue. */ astInvert( permmap ); /* And finally.... add this inverted PermMap onto the end of the CmpMap. */ cmpmap = astCmpMap( new, permmap, 1, "", status ); permmap = astAnnul( permmap ); new = astAnnul( new ); new = (AstMapping *) cmpmap; } /* Free the temporary arrays. */ inperm = (int *) astFree( (void *) inperm ); outperm = (int *) astFree( (void *) outperm ); } /* If an error has occurred, attempt to annul the new CmpMap. */ if( !astOK ) new = astAnnul( new ); /* Return the CmpMap. */ return new; } static int WcsNatPole( AstFitsChan *this, AstWcsMap *wcsmap, double alpha0, double delta0, double latpole, double *phip, double *alphap, double *deltap, int *status ){ /* * Name: * WcsNatPole * Purpose: * Find the celestial coordinates of the north pole of the Native Spherical * Coordinate system. * Type: * Private function. * Synopsis: * int WcsNatPole( AstFitsChan *this, AstWcsMap *wcsmap, double alpha0, * double delta0, double latpole, double *phip, * double *alphap, double *deltap, int *status ) * Class Membership: * FitsChan * Description: * The supplied WcsMap converts projected positions given in * "Projection Plane Coords" to positions in the "Native Spherical * Coordinate" system. This function finds the pole of this spherical * coordinate system in terms of the standard celestial coordinate * system to which the CRVALi, LONPOLE and LATPOLE keywords refer (this * system should be identified by characters 5-8 of the CTYPEi * keywords). It also supplies a default value for LONPOLE if no value * has been supplied explicitly in the FITS header. * * This function implements equations 8, 9 and 10 from the FITS-WCS paper * II by Calabretta & Greisen (plus the associated treatment of special * cases). The paper provides more detailed documentation for the * mathematics implemented by this function. * Parameters: * this * The FitsChan in which to store any warning cards. If NULL, no * warnings are stored. * wcsmap * A mapping describing the deprojection being used (i.e. the * mapping from Projection Plane Coords to Native Spherical Coords). * alpha0 * The longitude of the fiducial point in the standard celestial * coordinate frame (in radians). Note, this fiducial point does * not necessarily correspond to the point given by keywords CRPIXj. * delta0 * The celestial latitude (radians) of the fiducial point. * latpole * The value of FITS keyword LATPOLE, converted to radians, or the * symbolic constant AST__BAD if the keyword was not supplied. * phip * Pointer to a location at which is stored the longitude of the north * pole of the standard Celestial coordinate system, as measured in * the Native Spherical Coordinate system, in radians. This should be * supplied holding the radian equivalent of the value of the FITS * keyword LONPOLE, or the symbolic constant AST__BAD if the keyword was * not supplied (in which case a default value will be returned at the * given location). * alphap * Pointer to a location at which to store the calculated longitude * of the Native North Pole, in radians. * deltap * Pointer to a location at which to store the calculated latitude * of the Native North Pole, in radians. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A status: non-zero for success, zero if the position of the native * north pole is undefined. * Notes: * - Certain combinations of keyword values result in the latitude of * the Native North Pole being undefined. In these cases, a value of * 0 is returned for the function value, but no error is reported. * - All angular values used by this function are in radians. * - A value of 0 is returned if an error has already occurred. */ /* Local Variables: */ char buf[150]; /* Buffer for warning message */ double cos_theta0; /* Cosine of theta0 */ double cos_phip; /* Cosine of (phip - phi0) */ double cos_delta0; /* Cosine of delta0 */ double cos_deltap; /* Cosine of deltap */ double deltap_1; /* First possible value for deltap */ double deltap_2; /* Second possible value for deltap */ double sin_theta0; /* Sine of theta0 */ double sin_phip; /* Sine of (phip - phi0) */ double sin_delta0; /* Sine of delta0 */ double sin_deltap; /* Sine of deltap */ double t0, t1, t2, t3, t4; /* Intermediate values */ double phi0, theta0; /* Native coords of fiducial point */ /* Check the global status. */ if ( !astOK ) return 0; /* Get the longitude and latitude of the fiducial point in the native spherical coordinate frame (in radians). */ GetFiducialNSC( wcsmap, &phi0, &theta0, status ); /* If no value was supplied for the FITS keyword LONPOLE, set up a default value such that the celestial latitude increases in the same direction as the native latitude at the fiducial; point. */ if( *phip == AST__BAD ){ if( delta0 >= theta0 ){ *phip = 0.0; } else { *phip = AST__DPI; } /* Issue a warning that a default lonpole value has been adopted. */ sprintf( buf, "The original FITS header did not specify the " "longitude of the native north pole. A default value " "of %.8g degrees was assumed.", (*phip)*AST__DR2D ); Warn( this, "nolonpole", buf, "astRead", "FitsChan", status ); } /* If the fiducial point is coincident with the Native North Pole, then the Native North Pole must have the same coordinates as the fiducial point. Tests for equality include some tolerance to allow for rounding errors. */ sin_theta0 = sin( theta0 ); if( EQUAL( sin_theta0, 1.0 ) ){ *alphap = alpha0; *deltap = delta0; /* If the fiducial point is concident with the Native South Pole, then the Native North Pole must have the coordinates of the point diametrically opposite the fiducial point. */ } else if( EQUAL( sin_theta0, -1.0 ) ){ *alphap = alpha0 + AST__DPI; *deltap = -delta0; /* For all other cases, go through the procedure described in the WCS paper by Greisen & Calabretta, to find the position of the Native North Pole. First store some useful values. */ } else { cos_theta0 = cos( theta0 ); cos_delta0 = cos( delta0 ); cos_phip = cos( *phip - phi0 ); sin_delta0 = sin( delta0 ); sin_phip = sin( *phip - phi0 ); /* Next, find the two possible values for the latitude of the Native North Pole (deltap). If any stage of this transformation is indeterminate, return zero (except for the single special case noted in item 6 para. 2 of the WCS paper, for which LATPOLE specifies the values to be used). */ t0 = cos_theta0*cos_phip; if( fabs( t0 ) < TOL2 && fabs( sin_theta0 ) < TOL2 ){ if( latpole != AST__BAD ) { *deltap = latpole; } else { return 0; } } else { t1 = atan2( sin_theta0, t0 ); t2 = cos_theta0*cos_phip; t2 *= t2; t2 += sin_theta0*sin_theta0; if( t2 <= DBL_MIN ){ return 0; } else { t3 = sin_delta0/sqrt( t2 ); if( fabs( t3 ) > 1.0 + TOL1 ){ return 0; } else { if( t3 < -1.0 ){ t4 = AST__DPI; } else if( t3 > 1.0 ){ t4 = 0.0; } else { t4 = acos( t3 ); } deltap_1 = palDrange( t1 + t4 ); deltap_2 = palDrange( t1 - t4 ); /* Select which of these two values of deltap to use. Values outside the range +/- PI/2 cannot be used. If both values are within this range use the value which is closest to the supplied value of latpole (or use the northern most value if the LATPOLE keyword was not supplied. */ if( fabs( deltap_1 ) > AST__DPIBY2 + TOL2 ){ *deltap = deltap_2; } else if( fabs( deltap_2 ) > AST__DPIBY2 + TOL2 ){ *deltap = deltap_1; } else { if( latpole != AST__BAD ){ if( fabs( deltap_1 - latpole ) < fabs( deltap_2 - latpole ) ){ *deltap = deltap_1; } else { *deltap = deltap_2; } } else { if( deltap_1 > deltap_2 ){ *deltap = deltap_1; } else { *deltap = deltap_2; } /* Issue a warning that a default latpole value has been adopted. */ sprintf( buf, "The original FITS header did not specify " "the latitude of the native north pole. A " "default value of %.8g degrees was assumed.", (*deltap)*AST__DR2D ); Warn( this, "nolatpole", buf, "astRead", "FitsChan", status ); } } if( fabs( *deltap ) > AST__DPIBY2 + TOL2 ) { return 0; } else if( *deltap < -AST__DPIBY2 ){ *deltap = -AST__DPIBY2; } else if( *deltap > AST__DPIBY2 ){ *deltap = AST__DPIBY2; } } } } /* If a valid value for the latitude (deltap) has been found, find the longitude of the Native North Pole. */ if( *deltap != AST__BAD ) { if( fabs( cos_delta0) > TOL2 ){ cos_deltap = cos( *deltap ); sin_deltap = sin( *deltap ); if( fabs( cos_deltap ) > TOL2 ){ t1 = sin_phip*cos_theta0/cos_delta0; t2 = ( sin_theta0 - sin_deltap*sin_delta0 ) /( cos_delta0*cos_deltap ); if( ( fabs( t1 ) > TOL2 ) || ( fabs( t2 ) > TOL2 ) ){ *alphap = alpha0 - atan2( t1, t2 ); } else { *alphap = alpha0; } } else if( sin_deltap > 0.0 ){ *alphap = alpha0 + (*phip - phi0) - AST__DPI; } else { *alphap = alpha0 - (*phip - phi0); } } else { *alphap = alpha0; } } else { *alphap = AST__BAD; } } /* Return a success status if valid latitude and longitude values were found. */ return (*deltap) != AST__BAD && (*alphap) != AST__BAD ; } static AstMapping *WcsOthers( AstFitsChan *this, FitsStore *store, char s, AstFrame **frm, AstFrame *iwcfrm, const char *method, const char *class, int *status ){ /* * Name: * WcsOthers * Purpose: * Create a Mapping from intermediate world coords to any axes * which are not covered by specialised conventions. * Type: * Private function. * Synopsis: * AstMapping *WcsOthers( AstFitsChan *this, FitsStore *store, char s, * AstFrame **frm, AstFrame *iwcfrm, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function interprets the contents of the supplied FitsStore * structure, looking for world coordinate axes for which no * description has yet been added to the supplied Frame . It is * assumed that any such axes are simple linear axes. It returns a * Mapping which simply adds on the CRVAL values to such axes. * It also modifies the supplied Frame to describe the axes. * Parameters: * this * The FitsChan. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * frm * The address of a location at which to store a pointer to the * Frame describing the world coordinate axes. * iwcfrm * A pointer to the Frame describing the intermediate world coordinate * axes. The properties of this Frame may be changed on exit. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstFrame *pfrm; /* Pointer to primary Frame */ AstFrame *pfrm2; /* Pointer to primary Frame */ AstMapping *map1; /* Pointer to a Mapping */ AstMapping *map2; /* Pointer to a Mapping */ AstMapping *ret; /* The returned Mapping */ char **comms; /* Pointer to array of CTYPE commments */ char buf[ 100 ]; /* Buffer for textual attribute value */ char buf2[ 100 ]; /* Buffer for textual attribute value */ char buf3[ 20 ]; /* Buffer for default CTYPE value */ char *newdom; /* Pointer to new Domain value */ const char *ckeyval; /* Pointer to character keyword value */ int i; /* Axis index */ int j; /* Axis index */ int len; /* Used length of string */ int naxes; /* no. of axes in Frame */ int nother; /* The number of "other" axes */ int paxis; /* Primary axis index */ int usecom; /* Use CTYPE comments as axis Labels? */ /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Get the number of physical axes. */ naxes = astGetNaxes( *frm ); /* Assume we will use CTYPE comments as the axis labels. */ usecom = 1; /* Initialise the count of "other" axes. */ nother = 0; /* Get the comments associated with the CTYPE keywords for all "other" axes. */ comms = astMalloc( naxes*sizeof( char * ) ); if( comms ) { /* Loop round all axes in the Frame, and initialise the pointer to its comment. */ for( i = 0; i < naxes; i++ ){ comms[ i ] = NULL; /* Get the Domain for the primary frame containing the axis. This will be "AST_FITSCHAN" if the axis has not yet been recognised (this Domain is set up by WcsMapFrm). Only consider the axis further if the Domain has not been changed. */ astPrimaryFrame( *frm, i, &pfrm, &paxis ); if( !strcmp( astGetDomain( pfrm ), "AST_FITSCHAN" ) ) { /* Increment the count of "other" axes. */ nother++; /* Get the comment associated with the CTYPE header. */ ckeyval = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); /* If this axis has no CTYPE comment, we will use CTYPE values as axis labels (if given, the CNAME keyword take precedence). */ if( !ckeyval || astChrLen( ckeyval ) == 0 ) { usecom = 0; /* If the CTYPE comment for this axis is the same as any other comment, we will use CTYPE values as axis labels. */ } else { for( j = 0; j < nother - 1; j++ ) { if( comms[ j ] && !strcmp( ckeyval, comms[ j ] ) ) { usecom = 0; break; } } } /* If we are still using comments as axis labels, store a copy of it in the workspace. */ if( usecom ) comms[ i ] = astStore( NULL, ckeyval, strlen( ckeyval ) + 1 ); } pfrm = astAnnul( pfrm ); } /* Free the workspace holding comments. */ for( i = 0; i < naxes; i++ ) comms[ i ] = astFree( comms[ i ] ); comms = astFree( comms ); } /* If there are no "other" axes, just return a UnitMap. */ if( nother == 0 ) { ret = (AstMapping *) astUnitMap( naxes, "", status ); /* Otherwise... */ } else { /* If we have only a single other axis, use CTYPE value instead of comment. */ if( nother == 1 ) usecom = 0; /* Not yet started a new Domain value to replace "AST_FITSCHAN". */ newdom = NULL; pfrm2 = NULL; /* Check each axis of the Frame looking for axes which have not yet been recognised. */ for( i = 0; i < naxes; i++ ) { /* Get the Domain for the primary frame containing the axis. This will be "AST_FITSCHAN" if the axis has not yet been recognised (this Domain is set up by WcsMapFrm). Only consider the axis further if the Domain has not been changed. */ astPrimaryFrame( *frm, i, &pfrm, &paxis ); if( !strcmp( astGetDomain( pfrm ), "AST_FITSCHAN" ) ) { /* Save a pointer to the primary Frame which we will use to set the Domain of the primary Frame. */ if( !pfrm2 ) pfrm2 = astClone( pfrm ); /* Get the CTYPE value. Use a default of "AXISn". */ ckeyval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( !ckeyval ) { sprintf( buf3, "AXIS%d", i + 1 ); ckeyval = buf3; } /* If the CTYPE value ends with "-LOG", assume it is a logarithmically spaced axis. Get the Mapping from IWC to WCS. Reduce the used length of the CTYPE string to exlude any trailing "-LOG" string. */ len = strlen( ckeyval ); if( len > 3 && !strcmp( ckeyval + len - 4, "-LOG" ) ){ map1 = LogWcs( store, i, s, method, class, status ); sprintf( buf2, "%.*s", len - 4, ckeyval ); /* Otherwise, assume the axis is linearly spaced. */ } else { map1 = LinearWcs( store, i, s, method, class, status ); sprintf( buf2, "%.*s", len, ckeyval ); } /* Append the CTYPE value to the final Domain value for the primary Frame. */ if( ckeyval && astChrLen( ckeyval ) > 0 ) { if( newdom ) { sprintf( buf, "%s-%s", newdom, buf2 ); } else { sprintf( buf, "%s", buf2 ); newdom = buf; } } /* Now modify the axis in the Frame to have appropriate values for the Unit, Label and Symbol attributes. Also set the Unit attribute for the corresponding axis in the IWC Frame. */ if( ckeyval ) astSetSymbol( *frm, i, buf2 ); ckeyval = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status ); if( !ckeyval && usecom ) ckeyval = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status ); if( !ckeyval ) ckeyval = buf2; if( ckeyval ) astSetLabel( *frm, i, ckeyval ); ckeyval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( ckeyval ) { astSetUnit( *frm, i, ckeyval ); astSetUnit( iwcfrm, i, ckeyval ); } /* If this axis has been described by an earlier function (because it uses specialised conventions such as those described in FITS-WCS papers II or III), then create a UnitMap for this axis. */ } else { map1 = (AstMapping *) astUnitMap( 1, "", status ); } /* Annul the pointer to the primary Frame containing the current axis. */ pfrm = astAnnul( pfrm ); /* Add the Mapping for this axis in parallel with the current "running sum" Mapping (if any). */ if( ret ) { map2 = (AstMapping *) astCmpMap( ret, map1, 0, "", status ); ret = astAnnul( ret ); map1 = astAnnul( map1 ); ret = map2; } else { ret = map1; } } /* Set the Domain name for the primary Frame. It is currently set to AST_FITSCHAN. We replace it with a value formed by concatenating the CTYPE values of its axes. */ if( pfrm2 ) { if( newdom && astChrLen( newdom ) > 0 ) { astSetDomain( pfrm2, newdom ); } else { astClearDomain( pfrm2 ); } pfrm2 = astAnnul( pfrm2 ); } /* If the header contained a WCSNAME keyword, use it as the Domain name for the Frame. Also use it to create a title. */ ckeyval = GetItemC( &(store->wcsname), 0, 0, s, NULL, method, class, status ); if( ckeyval ){ astSetDomain( *frm, ckeyval ); sprintf( buf, "%s coordinates", ckeyval ); astSetTitle( *frm, buf ); } } /* Return the result. */ return ret; } static AstWinMap *WcsShift( FitsStore *store, char s, int naxes, const char *method, const char *class, int *status ){ /* * Name: * WcsShift * Purpose: * Create a WinMap which shifts pixels coordinates so that their origin * is at the reference pixel. * Type: * Private function. * Synopsis: * AstWinMap *WcsShift( FitsStore *store, char s, int naxes, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * A WinMap is created which implements a shift of origin by subtracting * the reference pixel coordinates (CRPIXi) from the input pixel * coordinates. * Parameters: * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the created WinMap or a NULL pointer if an * error occurred. * Notes: * - If an error occurs, a NULL pointer is returned. */ /* Local Variables: */ AstWinMap *new; /* The created WinMap */ int j; /* Pixel axis index */ double crpix; /* CRPIX keyword value */ double *c1_in; /* Input corner 1 */ double *c2_in; /* Input corner 2 */ double *c1_out; /* Output corner 1 */ double *c2_out; /* Output corner 2 */ /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the returned WinMap pointer. */ new = NULL; /* Allocate memory to hold the two corners, in both input and output coordinates. */ c1_in = (double *) astMalloc( sizeof( double )*(size_t) naxes ); c1_out = (double *) astMalloc( sizeof( double )*(size_t) naxes ); c2_in = (double *) astMalloc( sizeof( double )*(size_t) naxes ); c2_out = (double *) astMalloc( sizeof( double )*(size_t) naxes ); /* Check these pointers can be used. */ if( astOK ){ /* Set up two arbitrary corners in the input coordinate system, and the corresponding values with the CRPIX values subtracted off. */ for( j = 0; j < naxes; j++ ){ /* Get the CRPIX value for this axis. */ crpix = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status ); if( crpix == AST__BAD ) crpix = 0.0; /* Store the corner co-ordinates. */ c1_in[ j ] = 0.0; c2_in[ j ] = 1.0; c1_out[ j ] = -crpix; c2_out[ j ] = 1.0 - crpix; } /* Create the WinMap. */ new = astWinMap( naxes, c1_in, c2_in, c1_out, c2_out, "", status ); /* If an error has occurred, attempt to annul the new WinMap. */ if( !astOK ) new = astAnnul( new ); } /* Free the memory holding the corners. */ c1_in = (double *) astFree( (void *) c1_in ); c1_out = (double *) astFree( (void *) c1_out ); c2_in = (double *) astFree( (void *) c2_in ); c2_out = (double *) astFree( (void *) c2_out ); /* Return the WinMap. */ return new; } static AstSkyFrame *WcsSkyFrame( AstFitsChan *this, FitsStore *store, char s, int prj, char *sys, int axlon, int axlat, const char *method, const char *class, int *status ){ /* * Name: * WcsSkyFrame * Purpose: * Create a SkyFrame to describe a WCS celestial coordinate system. * Type: * Private function. * Synopsis: * AstSkyFrame *WcsSkyFrame( AstFitsChan this, FitsStore *store, char s, int prj, * char *sys, int axlon, int axlat, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A SkyFrame is returned describing the celestial coordinate system * described by a FITS header. The axes are *not* permuted in the * returned Frame (that is, axis 0 is longitude and axis 1 is latitude * in the returned SkyFrame, no matter what values are supplied for * "axlat" and "axlon"). * Parameters: * this * The FitsChan from which the keywords were read. Warning messages * may be added to this FitsChan. * store * A structure containing values for FITS keywords relating to * the World Coordinate System. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * prj * An integer code for the WCS projection being used. * sys * A pointer to a string identifying the celestial co-ordinate system * implied by the CTYPE values in the FitsStore. This will be "EQU" (for * equatorial), or a one or two character code extracted from the * CTYPE values. * axlon * Zero based index of the longitude axis in the FITS header. * axlat * Zero based index of the latitude axis in the FITS header. * method * The calling method. Used only in error messages. * class * The object class. Used only in error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the SkyFrame. * Notes: * - A NULL pointer is returned if an error has already occurred, or * if this function should fail for any reason. */ /* Local Variables: */ AstSkyFrame *ret; /* Returned Frame */ char *ckeyval; /* Pointer to string item value */ char *lattype; /* Pointer to latitude CTYPE value */ char *lontype; /* Pointer to longitude CTYPE value */ char bj; /* Besselian/Julian selector */ char buf[300]; /* Text buffer */ char sym[10]; /* Axis symbol */ double dval; /* Floating point attribute value */ double eqmjd; /* MJD equivalent of equinox */ double equinox; /* EQUINOX value */ double geolat; /* Observer's geodetic latitude */ double geolon; /* Observer's geodetic longitude */ double h; /* Observer's geodetic height */ double mjdobs; /* MJD-OBS value */ double obsgeo[ 3 ]; /* Observer's Cartesian position */ int radesys; /* RADESYS value */ int report; /* Report unknown lon/lat system? */ /* Initialise. */ ret = NULL; /* Check the global error status. */ if ( !astOK ) return ret; /* Get the RADESYS keyword from the header, and identify the value. Store a integer value identifying the system. Report an error if an unrecognised system is supplied. Store NORADEC if the keyword was not supplied. */ ckeyval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status ); radesys = NORADEC; if( ckeyval ){ if( !strncmp( ckeyval, "FK4 ", 4 ) || !strcmp( ckeyval, "FK4" ) ){ radesys = FK4; } else if( !strncmp( ckeyval, "FK4-NO-E", 8 ) ){ radesys = FK4NOE; } else if( !strncmp( ckeyval, "FK5 ", 4 ) || !strcmp( ckeyval, "FK5" ) ){ radesys = FK5; } else if( !strncmp( ckeyval, "ICRS ", 5 ) || !strcmp( ckeyval, "ICRS" ) ){ radesys = ICRS; } else if( !strncmp( ckeyval, "GAPPT ", 6 ) || !strcmp( ckeyval, "GAPPT" ) ){ radesys = GAPPT; } else if( astOK ){ astError( AST__BDFTS, "%s(%s): FITS keyword '%s' has the " "unrecognised value '%s'.", status, method, class, FormatKey( "RADESYS", -1, -1, s, status ), ckeyval ); } } else { radesys = NORADEC; } /* Get the value of the EQUINOX keyword. */ equinox = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status ); /* For FK4 and FK4-NO-E any supplied equinox value is Besselian. For all other systems, the equinox value is Julian. */ bj = 0; if( equinox != AST__BAD ){ if( radesys == FK4 || radesys == FK4NOE ){ bj = 'B'; } else if( radesys != NORADEC ) { bj = 'J'; /* If no RADESYS was suppied, but an equinox was, use the IAU 1984 rule to determine the default RADESYS and equinox type. */ } else { if( equinox < 1984.0 ){ radesys = FK4; bj = 'B'; } else { radesys = FK5; bj = 'J'; } /* If an equatorial system is being used, give a warning that a default RADESYS value is being used. */ if( !strcmp( sys, "EQU" ) ){ sprintf( buf, "The original FITS header did not specify the " "RA/DEC reference frame. A default value of %s was " "assumed.", ( radesys == FK4 ) ? "FK4" : "FK5" ); Warn( this, "noradesys", buf, method, class, status ); } } /* If no equinox was supplied, use a default equinox value depending on the frame of reference. For FK4-based systems, use B1950. */ } else { if( radesys == FK4 || radesys == FK4NOE ){ equinox = 1950.0; bj = 'B'; /* For FK5-based systems, use J2000. */ } else if( radesys == FK5 ){ equinox = 2000.0; bj = 'J'; /* If no RADESYS or EQUINOX was supplied, assume either FK4 B1950 or ICRS - as decided by attribute DefB1950 (GAPPT and ICRS do not use EQUINOX). */ } else if( radesys == NORADEC ) { if( astGetDefB1950( this ) ) { equinox = 1950.0; bj = 'B'; radesys = FK4; } else { radesys = ICRS; } if( !strcmp( sys, "EQU" ) ){ sprintf( buf, "The original FITS header did not specify the " "RA/DEC reference frame. A default value of %s was " "assumed.", ( radesys == FK4 ) ? "FK4" : "ICRS" ); Warn( this, "noradesys", buf, method, class, status ); } } /* If we have an equatorial or ecliptic system, issue a warning that a default equinox has been adopted. */ if( ( !strcmp( sys, "EQU" ) && radesys != ICRS && radesys != GAPPT ) || !strcmp( sys, "ECL" ) ){ sprintf( buf, "The original FITS header did not specify the " "reference equinox. A default value of %c%.8g was " "assumed.", bj, equinox ); Warn( this, "noequinox", buf, method, class, status ); } } /* Convert the equinox to a Modified Julian Date. */ if( equinox != AST__BAD ) { if( bj == 'B' ) { eqmjd = palEpb2d( equinox ); } else { eqmjd = palEpj2d( equinox ); } } else { eqmjd = AST__BAD; } /* Get a value for the Epoch attribute. If no value is available, use EQUINOX and issue a warning. */ mjdobs = ChooseEpoch( this, store, s, method, class, status ); if( mjdobs == AST__BAD ) { mjdobs = eqmjd; if( mjdobs != AST__BAD ) { sprintf( buf, "The original FITS header did not specify the " "date of observation. A default value of %c%.8g was " "assumed.", bj, equinox ); Warn( this, "nomjd-obs", buf, method, class, status ); } } /* Create a SkyFrame for the specified system. */ if( !strcmp( sys, "E" ) ){ ret = astSkyFrame( "System=Ecliptic", status ); } else if( !strcmp( sys, "H" ) ){ ret = astSkyFrame( "System=Helioecliptic", status ); } else if( !(strcmp( sys, "G" ) ) ){ ret = astSkyFrame( "System=Galactic", status ); } else if( !(strcmp( sys, "S" ) ) ){ ret = astSkyFrame( "System=Supergalactic", status ); } else if( !(strcmp( sys, "AZL" ) ) ){ ret = astSkyFrame( "System=AzEl", status ); } else if( !(strcmp( sys, "EQU" ) ) ){ /* For equatorial systems, the specific system is given by the RADESYS value. */ if( radesys == FK4 ){ ret = astSkyFrame( "System=FK4", status ); } else if( radesys == FK4NOE ){ ret = astSkyFrame( "System=FK4-NO-E", status ); } else if( radesys == FK5 ){ ret = astSkyFrame( "System=FK5", status ); } else if( radesys == ICRS ){ ret = astSkyFrame( "System=ICRS", status ); } else if( radesys == GAPPT ){ ret = astSkyFrame( "System=GAPPT", status ); } else if( astOK ){ astError( AST__INTER, "%s(%s): Internal AST programming " "error - FITS equatorial coordinate system type %d " "not yet supported in WcsSkyFrame.", status, method, class, radesys ); } /* If an unknown celestial co-ordinate system was specified by the CTYPE keywords, add warning messages to the FitsChan and treat the axes as a general spherical coordinate system. */ } else if( astOK ){ report = 1; ret = astSkyFrame( "System=UNKNOWN", status ); strcpy( sym, sys ); if( strlen( sys ) == 1 ) { strcpy( sym + 1, "LON" ); astSetSymbol( ret, 0, sym ); strcpy( sym + 1, "LAT" ); astSetSymbol( ret, 1, sym ); } else { strcpy( sym + 2, "LN" ); astSetSymbol( ret, 0, sym ); strcpy( sym + 2, "LT" ); astSetSymbol( ret, 1, sym ); /* The code "OF" is used by AST to describe offset sky coordinates. Set the Domain to SKY_OFFSETS in these cases, so that we can identify these Frames later. */ if( !strcmp( sys, "OF" ) ) { astSetDomain( ret, "SKY_OFFSETS" ); report = 0; } } if( report ) { lontype = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status ); lattype = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status ); if( lontype && lattype ){ sprintf( buf, "This FITS header contains references to an unknown " "spherical co-ordinate system specified in the values " "%s and %s. It may not be possible to convert to " "other standard co-ordinate systems.", lontype, lattype ); Warn( this, "badcel", buf, method, class, status ); } } } /* If a skyFrame was created... */ if( ret ){ /* Store the projection description. */ if( prj != AST__WCSBAD ) astSetProjection( ret, astWcsPrjDesc( prj ) ); /* Store the epoch of the observation in the SkyFrame. */ if( mjdobs != AST__BAD ) astSetEpoch( ret, mjdobs ); /* For equatorial and ecliptic systems, store the epoch of the reference equinox in the SkyFrame. */ if( ( !strcmp( sys, "EQU" ) || !strcmp( sys, "ECL" ) ) && equinox != AST__BAD ) astSetEquinox( ret, eqmjd ); /* If either of the CNAME keywords is set, use it as the axis label. */ ckeyval = GetItemC( &(store->cname), axlon, 0, s, NULL, method, class, status ); if( ckeyval ) astSetLabel( ret, 0, ckeyval ); ckeyval = GetItemC( &(store->cname), axlat, 0, s, NULL, method, class, status ); if( ckeyval ) astSetLabel( ret, 1, ckeyval ); /* Observer's position (from primary axis descriptions). Get the OBSGEO-X/Y/Z keywords, convert to geodetic longitude and latitude and store as the SpecFrame's ObsLat, ObsLon and ObsAlt attributes. */ obsgeo[ 0 ] = GetItem( &(store->obsgeox), 0, 0, ' ', NULL, method, class, status ); obsgeo[ 1 ] = GetItem( &(store->obsgeoy), 0, 0, ' ', NULL, method, class, status ); obsgeo[ 2 ] = GetItem( &(store->obsgeoz), 0, 0, ' ', NULL, method, class, status ); if( obsgeo[ 0 ] != AST__BAD && obsgeo[ 1 ] != AST__BAD && obsgeo[ 2 ] != AST__BAD ) { iauGc2gd( 1, obsgeo, &geolon, &geolat, &h ); astSetObsLat( ret, geolat ); astSetObsLon( ret, geolon ); astSetObsAlt( ret, h ); } /* Store values for the reference point in the SkyFrame. */ dval = GetItem( &(store->skyref), axlon, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) astSetSkyRef( ret, 0, dval ); dval = GetItem( &(store->skyref), axlat, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) astSetSkyRef( ret, 1, dval ); dval = GetItem( &(store->skyrefp), axlon, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) astSetSkyRefP( ret, 0, dval ); dval = GetItem( &(store->skyrefp), axlat, 0, s, NULL, method, class, status ); if( dval != AST__BAD ) astSetSkyRefP( ret, 1, dval ); /* We cannot store the SkyRefIs value yet since this needs to be done after the SkyFrame has been added into the FrameSet, so that the Frame will be remapped to represent the intended offsets. SO instance, mark the Frame by setting the domain to "SKY_POLE" or "SKY_ORIGIN". This odd Domain value will be cleared later in TidyOffsets. */ ckeyval = GetItemC( &(store->skyrefis), 0, 0, s, NULL, method, class, status ); if( ckeyval ) { if( !Ustrcmp( "POLE", ckeyval, status ) ) { astSetDomain( ret, "SKY_POLE" ); } else if( !Ustrcmp( "ORIGIN", ckeyval, status ) ) { astSetDomain( ret, "SKY_ORIGIN" ); } } } /* If an error has occurred, annul the Frame. */ if( !astOK ) ret = astAnnul( ret ); /* Return the Frame. */ return ret; } static AstMapping *WcsSpectral( AstFitsChan *this, FitsStore *store, char s, AstFrame **frm, AstFrame *iwcfrm, double reflon, double reflat, AstSkyFrame *reffrm, const char *method, const char *class, int *status ){ /* * Name: * WcsSpectral * Purpose: * Create a Mapping from intermediate world coords to spectral coords * as described in a FITS header. * Type: * Private function. * Synopsis: * AstMapping *WcsSpectral( AstFitsChan *this, FitsStore *store, char s, * AstFrame **frm, AstFrame *iwcfrm, double reflon, * double reflat, AstSkyFrame *reffrm, * const char *method, const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function interprets the contents of the supplied FitsStore * structure, looking for world coordinate axes which describe positions * in a spectrum. If such an axis is found, a Mapping is returned which * transforms the corresponding intermediate world coordinates to * spectral world coordinates (this mapping leaves any other axes * unchanged). It also, modifies the supplied Frame to describe the * axis (again, other axes are left unchanged). If no spectral axis * is found, a UnitMap is returned, and the supplied Frame is left * unchanged. * Parameters: * this * The FitsChan. * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * frm * The address of a location at which to store a pointer to the * Frame describing the world coordinate axes. * iwcfrm * A pointer to the Frame describing the intermediate world coordinate * axes. The properties of this Frame may be changed on exit. * reflon * The reference celestial longitude, in the frame given by reffrm. * reflat * The reference celestial latitude, in the frame given by reffrm. * reffrm * The SkyFrame defining reflon and reflat. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstFrame *ofrm; /* Pointer to a Frame */ AstMapping *map1; /* Pointer to Mapping */ AstMapping *map2; /* Pointer to Mapping */ AstMapping *ret; /* Pointer to the returned Mapping */ AstSpecFrame *specfrm; /* Pointer to a SpecFrame */ char algcode[ 5 ]; /* Displayed spectral type string */ char stype[ 5 ]; /* Displayed spectral type string */ const char *cname; /* Pointer to CNAME value */ const char *ctype; /* Pointer to CTYPE value */ const char *cunit; /* Pointer to CUNIT value */ const char *defunit; /* Default unit string */ const char *specsys; /* Pointer to SPECSYS value */ const char *ssyssrc; /* Pointer to SSYSSRC value */ double geolat; /* Observer's geodetic latitude */ double geolon; /* Observer's geodetic longitude */ double h; /* Observer's geodetic height */ double mjd; /* Modified Julian Date */ double obscentre; /* Spectral value at observation centre */ double obsgeo[ 3 ]; /* Observer's Cartesian position */ double restfrq; /* RESTFRQ keyword value */ double vsource; /* Source velocity */ int *axes; /* Pointer to axis permutation array */ int i; /* Axis index */ int j; /* Loop count */ int k; /* Loop count */ int kk; /* Loop count */ int naxes; /* No. of axes in Frame */ /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Get the number of physical axes. */ naxes = astGetNaxes( *frm ); /* An array to hold a list of axis selections. */ axes = astMalloc( naxes*sizeof( int ) ); /* Loop round checking each axis. */ defunit = NULL; map1 = NULL; for( i = 0; i < naxes && astOK; i++ ) { /* Get the CTYPE value. Pass on to the next axis if no CTYPE is available. */ ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ); if( ctype ) { /* See if this CTYPE describes a spectral axis, and if so, extract the system code, the algorithm code and get the default units. */ defunit = IsSpectral( ctype, stype, algcode, status ); /* Skip to the next axis if the system type was not a spectral system type. */ if( defunit ) { /* Create a SpecFrame or DSBSpecFrame with this system (the FITS type codes are also legal SpecFrame System values). We use astSetC rather than astSetSystem because astSetC translates string values into the corresponding integer system identifiers. */ if( GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status ) == AST__BAD ) { specfrm = astSpecFrame( "", status ); } else { specfrm = (AstSpecFrame *) astDSBSpecFrame( "", status ); } astSetC( specfrm, "System", stype ); /* Set the reference position (attributes RefRA and RefDec), if known. */ if( reffrm ) astSetRefPos( specfrm, reffrm, reflon, reflat ); /* Set the SpecFrame units. Use the value of the CUNIT FITS keyword for this axis if available, otherwise use the default units for the system, noted above. */ cunit = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status ); if( !cunit ) cunit = defunit; astSetUnit( specfrm, 0, cunit ); /* Set the axis unit in the IWC Frame. */ astSetUnit( iwcfrm, i, cunit ); /* Get a value for the Epoch attribute (the date of observation). */ mjd = ChooseEpoch( this, store, s, method, class, status ); if( mjd != AST__BAD ) astSetEpoch( specfrm, mjd ); /* Set the rest frequency. Use the RESTFRQ keyword (assumed to be in Hz), or (if RESTFRQ is not available), RESTWAV (assumes to be in m). */ restfrq = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status ); if( restfrq == AST__BAD ) { restfrq = GetItem( &(store->restwav), 0, 0, s, NULL, method, class, status ); if( restfrq != AST__BAD ) restfrq = AST__C/restfrq; } astSetRestFreq( specfrm, restfrq ); /* Observer's position (from primary axis descriptions). Get the OBSGEO-X/Y/Z keywords, convert to geodetic longitude and latitude and store as the SpecFrame's ObsLat, ObsLon and ObsAlt attributes. */ obsgeo[ 0 ] = GetItem( &(store->obsgeox), 0, 0, ' ', NULL, method, class, status ); obsgeo[ 1 ] = GetItem( &(store->obsgeoy), 0, 0, ' ', NULL, method, class, status ); obsgeo[ 2 ] = GetItem( &(store->obsgeoz), 0, 0, ' ', NULL, method, class, status ); if( obsgeo[ 0 ] != AST__BAD && obsgeo[ 1 ] != AST__BAD && obsgeo[ 2 ] != AST__BAD ) { iauGc2gd( 1, obsgeo, &geolon, &geolat, &h ); astSetObsLat( specfrm, geolat ); astSetObsLon( specfrm, geolon ); astSetObsAlt( specfrm, h ); } /* Source velocity rest frame */ ssyssrc = GetItemC( &(store->ssyssrc), 0, 0, s, NULL, method, class, status ); if( ssyssrc ) astSetC( specfrm, "SourceVRF", ssyssrc ); /* Source velocity. Use the ZSOURCE keyword and convert from redshift to velocity. */ vsource = GetItem( &(store->zsource), 0, 0, s, NULL, method, class, status ); if( vsource != AST__BAD ) { vsource += 1.0; vsource *= vsource; vsource = AST__C*( vsource - 1.0 )/( vsource + 1.0 ); astSetSourceVel( specfrm, vsource ); } /* Reference frame. If the SPECSYS keyword is set, use it (the FITS codes are also legal SpecFrame StdOfRest values). We use astSetC rather than astSetSystem because astSetC translates string values into the corresponding integer system identifiers. */ specsys = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status ); if( specsys ) astSetC( specfrm, "StdOfRest", specsys ); /* Axis label. If the CNAME keyword is set, use it as the axis label. */ cname = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status ); if( cname ) astSetLabel( specfrm, 0, cname ); /* If the header contains an AXREF value for the spectral axis, use it as the observation centre in preferences to the CRVAL value. AXREF keywords are created by the astWrite method for axes described by -TAB algorithm that have no inverse transformation. */ obscentre = GetItem( &(store->axref), i, 0, s, NULL, method, class, status ); if( obscentre == AST__BAD ) { obscentre = GetItem( &(store->crval), i, 0, s, NULL, method, class, status ); } /* Now do the extra stuff needed if we are creating a dual sideband SpecFrame. */ if( astIsADSBSpecFrame( specfrm ) ) { DSBSetUp( this, store, (AstDSBSpecFrame *) specfrm, s, obscentre, method, class, status ); } /* Now branch for each type of algorithm code. Each case returns a 1D Mapping which converts IWC value into the specified Spectral system. */ /* Linear */ if( strlen( algcode ) == 0 ) { map1 = LinearWcs( store, i, s, method, class, status ); /* Log-Linear */ } else if( !strcmp( "-LOG", algcode ) ) { map1 = LogWcs( store, i, s, method, class, status ); /* Non-Linear */ } else if( algcode[ 0 ] == '-' && algcode[ 2 ] == '2' ) { map1 = NonLinSpecWcs( this, algcode, store, i, s, specfrm, method, class, status ); /* Grism */ } else if( !strcmp( "-GRI", algcode ) || !strcmp( "-GRA", algcode ) ) { map1 = GrismSpecWcs( algcode, store, i, s, specfrm, method, class, status ); } else { map1 = NULL; } if( map1 == NULL && astOK ) { specfrm = astAnnul( specfrm ); astError( AST__BDFTS, "%s(%s): Cannot implement spectral " "algorithm code '%s' specified in FITS keyword '%s'.", status, method, class, ctype + 4, FormatKey( "CTYPE", i + 1, -1, s, status ) ); astError( AST__BDFTS, "%s(%s): Unknown algorithm code or " "unusable parameter values.", status, method, class ); break; } /* Create a Frame by picking all the other (non-spectral) axes from the supplied Frame. */ j = 0; for( k = 0; k < naxes; k++ ) { if( k != i ) axes[ j++ ] = k; } /* If there were no other axes, replace the supplied Frame with the specframe. */ if( j == 0 ) { (void) astAnnul( *frm ); *frm = (AstFrame *) specfrm; /* Otherwise pick the other axes from the supplied Frame */ } else { ofrm = astPickAxes( *frm, j, axes, NULL ); /* Replace the supplied Frame with a CmpFrame made up of this Frame and the SpecFrame. */ (void) astAnnul( *frm ); *frm = (AstFrame *) astCmpFrame( ofrm, specfrm, "", status ); ofrm = astAnnul( ofrm ); specfrm = astAnnul( specfrm ); } /* Permute the axis order to put the spectral axis back in its original position. */ j = 0; for( kk = 0; kk < naxes; kk++ ) { if( kk == i ) { axes[ kk ] = naxes - 1; } else { axes[ kk ] = j++; } } astPermAxes( *frm, axes ); } } /* If this axis is not a spectral axis, create a UnitMap (the Frame is left unchanged). */ if( !map1 && astOK ) map1 = (AstMapping *) astUnitMap( 1, "", status ); /* Add the Mapping for this axis in parallel with the Mappings for previous axes. */ if( ret ) { map2 = (AstMapping *) astCmpMap( ret, map1, 0, "", status ); ret = astAnnul( ret ); map1 = astAnnul( map1 ); ret = map2; } else { ret = map1; map1 = NULL; } } /* Free the axes array. */ axes= astFree( axes ); /* Return the result. */ return ret; } static void WcsToStore( AstFitsChan *this, AstFitsChan *trans, FitsStore *store, const char *method, const char *class, int *status ){ /* * Name: * WcsToStore * Purpose: * Extract WCS information from the supplied FitsChan using a FITSWCS * encoding, and store it in the supplied FitsStore. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WcsToStore( AstFitsChan *this, AstFitsChan *trans, * FitsStore *store, const char *method, * const char *class, int *status ) * Class Membership: * FitsChan member function. * Description: * A FitsStore is a structure containing a generalised represention of * a FITS WCS FrameSet. Functions exist to convert a FitsStore to and * from a set of FITS header cards (using a specified encoding), or * an AST FrameSet. In other words, a FitsStore is an encoding- * independant intermediary staging post between a FITS header and * an AST FrameSet. * * This function extracts FITSWCS keywords from the supplied FitsChan(s), * and stores the corresponding WCS information in the supplied FitsStore. * Keywords will be searched for first in "trans", and then, if they * are not found in "trans", they will be searched for in "this". * Parameters: * this * Pointer to the FitsChan containing the cards read from the * original FITS header. This may include non-standard keywords. * trans * Pointer to a FitsChan containing cards representing standard * translations of any non-standard keywords in "this". A NULL * pointer indicates that "this" contains no non-standard keywords. * store * Pointer to the FitsStore structure. * method * Pointer to a string holding the name of the calling method. * This is only for use in constructing error messages. * class * Pointer to a string holding the name of the supplied object class. * This is only for use in constructing error messages. * status * Pointer to the inherited status variable. */ /* Check the global error status. */ if ( !astOK ) return; /* Read all usable cards out of the main FitsChan, into the FitsStore. */ WcsFcRead( this, trans, store, method, class, status ); /* If a FitsChan containing standard translations was supplied, read all cards out of it, into the FitsStore, potentially over-writing the non-standard values stored in the previous call to WcsFcRead. */ if( trans ) WcsFcRead( trans, NULL, store, method, class, status ); } static int WorldAxes( AstFitsChan *this, AstMapping *cmap, double *dim, int *perm, int *status ){ /* * Name: * WorldAxes * Purpose: * Associate final world axes with pixel axes. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int WorldAxes( AstFitsChan *this, AstMapping *cmap, double *dim, int *perm, * int *status ) * Class Membership: * FitsChan * Description: * This function finds the association between the axes of the final * world coordinate system, and those of the pixel coordinate * system. This may not simply be a 1-to-1 association because the * Mapping may include a PermMap. Each output axis is associated with * the input axis which is most nearly aligned with it. * Parameters: * this * Pointer to the FitsChan. * cmap * Pointer to the Mapping from pixel coordinates to final world * coordinates. * dim * Pointer to an array with one element for each input of "map", * supplied holding the no. of pixels in the data cube along the axis, or * AST__BAD If unknown. * perm * Pointer to an array with one element for each output of "map". * On exit, each element of this array holds the zero-based index of the * "corresponding" (i.e. most nearly parallel) pixel axis. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero for success - zero for failure. */ /* Local Variables: */ AstMapping *smap; AstMapping *map; AstPointSet *pset1; AstPointSet *pset2; double **ptr2; double **ptr1; double *dw; double *g0; double *nwt; double *ntn; double *tn; double *wt; double *w0; double dg; double s; double sj; double tnmin; double wtmax; int *outs; int i2; int i; int imin; int j2; int j; int jmin; int nin; int nout; int nouts; int nused; int ret; int retain; int used; /* Initialise returned value */ ret = 0; /* Other initialisation to avoid compiler warnings. */ retain = 0; /* Check the status */ if( !astOK ) return ret; /* Simplfy the Mapping. */ map = astSimplify( cmap ); /* Get the number of inputs and outputs for the Mapping. */ nin = astGetNin( map ); nout = astGetNout( map ); /* Initialise "perm". */ for( i = 0; i < nout; i++ ) perm[ i ] = i; /* First deal with Mappings that are defined in both directions. */ if( astGetTranForward( map ) && astGetTranInverse( map ) ) { /* Use FindBasisVectors to find an input position which coresponds to a good output position. Store it in a dynamic array pointed to by "g0". */ pset1 = astPointSet( nin+1, nin, "", status ); pset2 = astPointSet( nin+1, nout, "", status ); if( FindBasisVectors( map, nin, nout, dim, pset1, pset2, status ) ) { g0 = astMalloc( sizeof(double)*nin ); ptr1 = astGetPoints( pset1 ); if( astOK ) { for( j = 0; j < nin; j++ ) g0[ j ] = ptr1[ j ][ 0 ]; } pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); /* If no basis vectors found, return. */ } else { pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); return ret; } /* Create Pointset to hold two input (pixel) points. */ pset1 = astPointSet( 2, nin, "", status ); ptr1 = astGetPoints( pset1 ); /* Create a Pointset to hold the same number of output (world) points. */ pset2 = astPointSet( 2, nout, "", status ); ptr2 = astGetPoints( pset2 ); /* Allocate memory to use as work space */ w0 = astMalloc( sizeof(double)*nout ); dw = astMalloc( sizeof(double)*nout ); tn = astMalloc( sizeof(double)*nout*nin ); wt = astMalloc( sizeof(double)*nout*nin ); /* Check that the pointers can be used. */ if( astOK ) { /* Transform the grid position found above, plus a position 1 pixel away along all pixel axes, into world coords. Also set up "dw" to hold "a small increment" along each world axis. */ for( j = 0; j < nin; j++ ) { ptr1[ j ] [ 0 ] = g0[ j ]; ptr1[ j ] [ 1 ] = g0[ j ] + 1.0; } (void) astTransform( map, pset1, 1, pset2 ); for( i = 0; i < nout; i++ ) { w0[ i ] = ptr2[ i ] [ 0 ]; if( w0[ i ] != AST__BAD && ptr2[ i ] [ 1 ] != AST__BAD ) { dw[ i ] = fabs( 0.1*( ptr2[ i ] [ 1 ] - w0[ i ] ) ); if( dw[ i ] <= fabs( 0.001*w0[ i ] ) ) { if( w0[ i ] != 0.0 ) { dw[ i ] = fabs( 0.001*w0[ i ] ); } else { dw[ i ] = 1.0; } } } else { dw[ i ] = AST__BAD; } } /* Any PermMap in the mapping may result in the the "inverse transformation" not being a true inverse of the forward transformation (for instance, constant values fed in for degenerate axis would have this effect). To ensure that "g0" and "w0" are corresponding positions, transform the "w0" position back into grid coords and use the resulting grid position as "g0". */ (void) astTransform( map, pset2, 0, pset1 ); for( j = 0; j < nin; j++ ) { g0[ j ] = ptr1[ j ] [ 0 ]; } /* In the next loop we find the tan of the angle between each WCS axis and each of the pixel axes. Loop round each WCS axis. */ for( i = 0; i < nout; i++ ) { /* Initialise the tan values for this WCS axis to AST__BAD. */ ntn = tn + i*nin; nwt = wt + i*nin; for( j = 0; j < nin; j++ ) ntn[ j ] = AST__BAD; /* As a side issue, initialise the pixel axis assigned to each WCS axis to -1, to indicate that no grid axis has yet been associated with this WCS axis. */ perm[ i ] = -1; /* Skip over this axis if the increment is bad. */ if( dw[ i ] != AST__BAD ) { /* Store a WCS position which is offset from the "w0" position by a small amount along the current WCS axis. The first position in "ptr2" is currently "w0". */ ptr2[ i ][ 0 ] += dw[ i ]; /* Transform this position into grid coords. */ (void) astTransform( map, pset2, 0, pset1 ); /* Re-instate the original "w0" values within "ptr2", ready for the next WCS axis. */ ptr2[ i ][ 0 ] = w0[ i ]; /* Consider each pixel axis in turn as a candidate for being assigned to the current WCS axis. */ for( j = 0; j < nin; j++ ) { /* Find the tan of the angle between the current ("i"th) WCS axis and the current ("j"th) pixel axis. This gets stored in tn[j+nin*i]. A corresponding weight for each angle is stored in nwt[j+nin*i]. This is the length of the projection of the vector onto the "j"th pixel axis. */ s = 0.0; sj = 0.0; for( j2 = 0; j2 < nin; j2++ ) { if( ptr1[ j2 ][ 0 ] != AST__BAD ) { dg = ptr1[ j2 ][ 0 ] - g0[ j2 ]; if( j2 != j ) { s += dg*dg; } else { sj = fabs( dg ); } } else { s = AST__BAD; break; } } if( s != AST__BAD && sj != 0.0 ) { ntn[ j ] = sqrt( s )/sj; nwt[ j ] = sj; } } } } /* Loop until every grid axes has been assigned to a WCS axis. */ while( 1 ) { /* Pass through the array of tan values, finding the smallest. Note the pixel and WCS axis for which the smallest tan value occurs. If the tan values are equal, favour the one with highest weight. */ ntn = tn; nwt = wt; tnmin = AST__BAD; wtmax = AST__BAD; imin = 0; jmin = 0; for( i = 0; i < nout; i++ ) { for( j = 0; j < nin; j++ ) { if( *ntn != AST__BAD ) { if( tnmin == AST__BAD || *ntn < tnmin ) { tnmin = *ntn; wtmax = *nwt; imin = i; jmin = j; } else if( EQUAL( *ntn, tnmin ) && *nwt > wtmax ) { wtmax = *nwt; imin = i; jmin = j; } } ntn++; nwt++; } } /* Check we found a usable minimum tan value */ if( tnmin != AST__BAD ) { /* Assign the pixel axis to the WCS axis. */ perm[ imin ] = jmin; /* Set bad all the tan values for this pixel and WCS axis pair. This ensures that the pixel axis will not be assigned to another WCS axis, and that the WCS will not have another pixel axis assigned to it. */ ntn = tn; for( i = 0; i < nout; i++ ) { for( j = 0; j < nin; j++ ) { if( i == imin || j == jmin ) *ntn = AST__BAD; ntn++; } } /* Leave the loop if no more good tan values were found. */ } else { break; } } /* The above process may have left some WCS axes with out any assigned pixel axis. We assign the remaining pixel arbitrarily to such axes, starting with the first remaining pixel axis. Find the lowest unused pixel axis. */ for( j = 0; j < nin; j++ ) { used = 0; for( i = 0; i < nout; i++ ) { if( perm[ i ] == j ) { used = 1; break; } } if( !used ) break; } /* Now check each WCS axis looking for outputs which were not assigned a pixel axis in the above process. */ for( i = 0; i < nout; i++ ) { if( perm[ i ] == -1 ) { /* Use the next unused axis value. */ perm[ i ] = j++; /* Find the next unused axis value. */ for( ; j < nin; j++ ) { used = 0; for( i2 = 0; i2 < nout; i2++ ) { if( perm[ i2 ] == j ) { used = 1; break; } } if( !used ) break; } } } /* Indicate success. */ if( astOK ) ret = 1; } /* Free resources. */ pset1 = astAnnul( pset1 ); pset2 = astAnnul( pset2 ); g0 = astFree( g0 ); w0 = astFree( w0 ); tn = astFree( tn ); wt = astFree( wt ); dw = astFree( dw ); /* Now, if we can use the TAB algorithm, deal with Mappings that are defined only in the forward direction. */ } else if( astGetTranForward( map ) && astGetTabOK( this ) > 0 ) { /* Assume success. */ ret = 1; /* Initialise to indicate no outputs have yet been assigned. */ for( i = 0; i < nout; i++ ) perm[ i ] = -1; /* Find the output associated with each input. */ for( j = 0; j < nin; j++ ) { /* Attempt to split off the current input. */ outs = astMapSplit( map, 1, &j, &smap ); /* If successfull, store the index of the corresponding input for each output. */ if( outs && smap ) { nouts = astGetNout( smap ); for( i = 0; i < nouts; i++ ) { if( perm[ outs[ i ] ] == -1 ) { perm[ outs[ i ] ] = j; } else { ret = 0; } } } /* Free resources. */ outs = astFree( outs ); if( smap ) smap = astAnnul( smap ); } /* Check all outputs were assigned . */ for( i = 0; i < nout && ret; i++ ) { if( perm[ i ] == -1 ) ret = 0; } /* If succesful, attempt to remove any duplicates from the "perm" array (i.e. inputs that supply more than one output). First get a list of the inputs that are currently unused (i.e. do not appear in "perm"). */ if( ret ) { /* Check each input. */ for( j = 0; j < nin; j++ ) { /* See how many outputs are fed by this input. */ nused = 0; for( i = 0; i < nout; i++ ) { if( perm[ i ] == j ) nused++; } /* If it used more than once, we need to remove all but one of the occurrences. */ if( nused > 1 ) { /* Choose the occurrence to retain. If the output with the same index as the input is one of them, use it. Otherwise, use the first occurrence. */ if( perm[ j ] == j ) { retain = j; } else { for( i = 0; i < nout; i++ ) { if( perm[ i ] == j ) { retain = i; break; } } } /* Loop round all occurrences of this input again. */ for( i = 0; i < nout && ret; i++ ) { if( perm[ i ] == j ) { /* Replace all occurrences, except for the one being retained. */ if( i != retain ) { /* Replace it with the next unused input. */ for( j2 = 0; j2 < nin; j2++ ) { used = 0; for( i2 = 0; i2 < nout; i2++ ) { if( perm[ i2 ] == j2 ) { used = 1; break; } } if( ! used ) { perm[ i ] = j2; break; } } /* If there were no unused inputs, we cannot do it. */ if( used ) ret = 0; } } } } } } } /* Free resources. */ map = astAnnul( map ); /* Return the result. */ return ret; } static int Write( AstChannel *this_channel, AstObject *object, int *status ) { /* * Name: * Write * Purpose: * Write an Object to a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * int Write( AstChannel *this, AstObject *object, int *status ) * Class Membership: * FitsChan member function (over-rides the astWrite method * inherited from the Channel class). * Description: * This function writes an Object to a FitsChan. * Parameters: * this * Pointer to the FitsChan. * object * Pointer to the Object which is to be written. * status * Pointer to the inherited status variable. * Returned Value: * The number of Objects written to the FitsChan by this invocation of * astWrite. * Notes: * - A value of zero will be returned if this function is invoked * with the AST error status set, or if it should fail for any * reason. * - The Base Frame in the FrameSet is used as the pixel Frame, and * the Current Frame is used to create the primary axis descriptions. * Attempts are made to create secondary axis descriptions for any * other Frames in the FrameSet (up to a total of 26). */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure */ FitsStore *store; /* Intermediate storage for WCS information */ char banner[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ]; /* Buffer for begin/end banner */ const char *class; /* Pointer to string holding object class */ const char *method; /* Pointer to string holding calling method */ double *dim; /* Pointer to array of axis dimensions */ int card0; /* Index of original current card */ int comm; /* Value of Comm attribute */ int encoding; /* FITS encoding scheme to use */ int i; /* Axis index */ int naxis; /* No. of pixel axes */ int ret; /* Number of objects read */ /* Initialise. */ ret = 0; /* Check the global error status. */ if ( !astOK ) return ret; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Ensure the source function has been called */ ReadFromSource( this, status ); /* Store the calling method, and object class. */ method = "astWrite"; class = astGetClass( this ); /* The original current card is re-instated at the end if no object is written. Save its index. */ card0 = astGetCard( this ); /* Indicate that all cards added to the FitsCHan by this call should be marked as "new". */ mark_new = 1; /* Get the encoding scheme used by the FitsChan. */ encoding = astGetEncoding( this ); /* First deal with cases where we are writing to a FitsChan in which AST objects are encoded using native AST-specific keywords... */ if( encoding == NATIVE_ENCODING ){ /* Increment the nesting level which keeps track of recursive invocations of this function. */ write_nest++; /* Initialise the current indentation level for top-level objects. */ if ( !write_nest ) current_indent = 0; /* Obtain the value of the Comm attribute. */ comm = astGetComment( this ); /* If this is the top-level invocation (i.e. we are about to write out a new top-level Object), then prefix it with a blank FITS line and an appropriate banner of FITS comments, unless comments have been suppressed. */ if ( !write_nest && comm ) { astSetFitsCom( this, " ", "", 0 ); MakeBanner( "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); if( astIsAFrameSet( object ) ) { MakeBanner( "WCS information in AST format", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); MakeBanner( "See http://www.starlink.ac.uk/ast/", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); } MakeBanner( HEADER_TEXT, astGetClass( object ), " object", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); MakeBanner( "................................................................", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); } /* Invoke the parent astWrite method to write out the Object data. */ (*parent_write)( this_channel, object, status ); /* Append a banner of FITS comments to the object data, as above, if necessary. */ if ( !write_nest && comm ) { MakeBanner( "................................................................", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); MakeBanner( FOOTER_TEXT, astGetClass( object ), " object", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); MakeBanner( "----------------------------------------------------------------", "", "", banner, status ); astSetFitsCom( this, "COMMENT", banner, 0 ); } /* Return the nesting level to its previous value. */ write_nest--; /* Indicate that an object has been written. */ ret = 1; /* Now deal with cases where we are writing to a FitsChan in which AST objects are encoded using any of the supported foreign encodings... */ } else { /* Only proceed if the supplied object is a FrameSet. */ if( astIsAFrameSet( object ) ){ /* Note the number of pixel (i.e. Base Frame) axes, and allocate memory to hold the image dimensions. */ naxis = astGetNin( (AstFrameSet *) object ); dim = (double *) astMalloc( sizeof(double)*naxis ); if( dim ){ /* Note the image dimensions, if known. If not, store AST__BAD values. */ for( i = 0; i < naxis; i++ ){ if( !astGetFitsF( this, FormatKey( "NAXIS", i + 1, -1, ' ', status ), dim + i ) ) dim[ i ] = AST__BAD; } /* Extract the required information from the FrameSet into a standard intermediary structure called a FitsStore. The indices of any celestial axes are returned. */ store = FsetToStore( this, (AstFrameSet *) object, naxis, dim, encoding, method, class, status ); /* If the FrameSet cannot be described in terms of any of the supported FITS encodings, a null pointer will have been returned. */ if( store ){ /* Now put header cards describing the contents of the FitsStore into the supplied FitsChan, using the requested encoding. Zero or one is returned depending on whether the information could be encoded. */ ret = FitsFromStore( this, store, encoding, dim, (AstFrameSet *) object, method, class, status ); /* Release the resources used by the FitsStore. */ store = FreeStore( store, status ); /* If the Object was written to the FitsChan, set the current card to end-of-file. */ if( ret ) astSetCard( this, INT_MAX ); } /* Free workspace holding image dimensions */ dim = (double *) astFree( (void *) dim ); } } } /* If an error has occurred, return zero and remove any new cards added to the FitsCHan by this call. */ if( !astOK ) ret = 0; /* Clear the new flag associated with cards which have been added to the FitsChan as a result of this function. If the object was not added succesfully to the FitsChan, remove any cards which were added before the error was discovered. */ FixNew( this, NEW1, !ret, method, class, status ); FixNew( this, NEW2, !ret, method, class, status ); /* Indicate that all cards added to the FitsChan from now on should not be marked as "new". */ mark_new = 0; /* If no object was written, re-instate the original current card. */ if( !ret ) astSetCard( this, card0 ); /* Return the answer. */ return ret; } static void WriteBegin( AstChannel *this_channel, const char *class, const char *comment, int *status ) { /* * Name: * WriteBegin * Purpose: * Write a "Begin" data item to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteBegin( AstChannel *this, const char *class, * const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected astWriteBegin * method inherited from the Channel class). * Description: * This function writes a "Begin" data item to the data sink * associated with a FitsChan, so as to begin the output of a new * Object definition. * Parameters: * this * Pointer to the FitsChan. * class * Pointer to a constant null-terminated string containing the * name of the class to which the Object belongs. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the "Begin" * item. Normally, this will describe the purpose of the Object. * Notes: * - The comment supplied may not actually be used, depending on * the nature of the FitsChan supplied. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ]; /* Character buffer */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Increment the indentation level for comments. */ current_indent += INDENT_INC; /* If we are not beginning a top-level Object definition, and helpful information has not been suppressed, generate an indented comment to mark the "Begin" item and write it to the FitsChan as a comment card with a blank keyword. */ if ( write_nest && ( astGetFull( this ) >= 0 ) ) { MakeIndentedComment( current_indent, '+', "Beginning of ", class, buff, status ); astSetFitsCom( this, " ", buff, 0 ); } /* Create a unique FITS keyword for this "Begin" item, basing it on "BEGAST". */ CreateKeyword( this, "BEGAST", keyword, status ); /* Generate a pre-quoted version of the class name. */ PreQuote( class, buff, status ); /* Write the "Begin" item to the FitsChan as a keyword and string value. */ astSetFitsS( this, keyword, buff, astGetComment( this ) ? comment : NULL, 0 ); /* Clear the count of items written. */ items_written = 0; } static void WriteDouble( AstChannel *this_channel, const char *name, int set, int helpful, double value, const char *comment, int *status ) { /* * Name: * WriteDouble * Purpose: * Write a double value to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteDouble( AstChannel *this, const char *name, * int set, int helpful, * double value, const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected * astWriteDouble method inherited from the Channel class). * Description: * This function writes a named double value, representing the * value of a class instance variable, to the data sink associated * with a FitsChan. It is intended for use by class "Dump" * functions when writing out class information which will * subsequently be re-read. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a constant null-terminated string containing the * name to be used to identify the value in the external * representation. This will form the key for identifying it * again when it is re-read. The name supplied should be unique * within its class. * * Mixed case may be used and will be preserved in the external * representation (where possible) for cosmetic effect. However, * case is not significant when re-reading values. * * It is recommended that a maximum of 6 alphanumeric characters * (starting with an alphabetic character) be used. This permits * maximum flexibility in adapting to standard external data * representations (e.g. FITS). * set * If this is zero, it indicates that the value being written is * a default value (or can be re-generated from other values) so * need not necessarily be written out. Such values will * typically be included in the external representation with * (e.g.) a comment character so that they are available to * human readers but will be ignored when re-read. They may also * be completely omitted in some circumstances. * * If "set" is non-zero, the value will always be explicitly * included in the external representation so that it can be * re-read. * helpful * This flag provides a hint about whether a value whose "set" * flag is zero (above) should actually appear at all in the * external representaton. * * If the external representation allows values to be "commented * out" then, by default, values will be included in this form * only if their "helpful" flag is non-zero. Otherwise, they * will be omitted entirely. When possible, omitting the more * obscure values associated with a class is recommended in * order to improve readability. * * This default behaviour may be further modified if the * FitsChan's Full attribute is set - either to permit all * values to be shown, or to suppress non-essential information * entirely. * value * The value to be written. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the value. * * Note that this comment may not actually be used, depending on * the nature of the FitsChan supplied and the setting of its * Comm attribute. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Use the "set" and "helpful" flags, along with the FitsChan's attributes to decide whether this value should actually be written. */ if ( Use( this, set, helpful, status ) ) { /* Create a unique FITS keyword from the name supplied. */ CreateKeyword( this, name, keyword, status ); /* Write the value to the FitsChan as a keyword and value */ astSetFitsF( this, keyword, value, astGetComment( this ) ? comment : NULL, 0 ); /* If the value is not "set", replace the card just written by a COMMENT card containing the text of the card as the comment. */ if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status ); /* Increment the count of items written. */ items_written++; } } static void WriteEnd( AstChannel *this_channel, const char *class, int *status ) { /* * Name: * WriteEnd * Purpose: * Write an "End" data item to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteEnd( AstChannel *this, const char *class ) * Class Membership: * FitsChan member function (over-rides the protected astWriteEnd * method inherited from the Channel class). * Description: * This function writes an "End" data item to the data sink * associated with a FitsChan. This item delimits the end of an * Object definition. * Parameters: * this * Pointer to the FitsChan. * class * Pointer to a constant null-terminated string containing the * class name of the Object whose definition is being terminated * by the "End" item. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ]; /* Character buffer */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Create a unique FITS keyword for this "End" item, basing it on "ENDAST". */ CreateKeyword( this, "ENDAST", keyword, status ); /* Generate a pre-quoted version of the class name. */ PreQuote( class, buff, status ); /* Write the "End" item to the FitsChan as a keyword and string value. */ astSetFitsS( this, keyword, buff, astGetComment( this ) ? "End of object definition" : NULL, 0 ); /* If we are not ending a top-level Object definition, and helpful information has not been suppressed, generate an indented comment to mark the "End" item and write it to the FitsChan as a comment card with a blank keyword. */ if ( write_nest && ( astGetFull( this ) >= 0 ) ) { MakeIndentedComment( current_indent, '-', "End of ", class, buff, status ); astSetFitsCom( this, " ", buff, 0 ); } /* Decrement the indentation level for comments. */ current_indent -= INDENT_INC; } static void WriteFits( AstFitsChan *this, int *status ){ /* *++ * Name: c astWriteFits f AST_WRITEFITS * Purpose: * Write out all cards in a FitsChan to the sink function. * Type: * Public virtual function. * Synopsis: c #include "fitschan.h" c void astWriteFits( AstFitsChan *this ) f CALL AST_WRITEFITS( THIS, STATUS ) * Class Membership: * FitsChan method. * Description: c This function f This routine * writes out all cards currently in the FitsChan. If the SinkFile * attribute is set, they will be written out to the specified sink file. * Otherwise, they will be written out using the sink function specified * when the FitsChan was created. All cards are then deleted from the * FitsChan. * Parameters: c this f THIS = INTEGER (Given) * Pointer to the FitsChan. f STATUS = INTEGER (Given and Returned) f The global status. * Notes: * - If the SinkFile is unset, and no sink function is available, this * method simply empties the FitsChan, and is then equivalent to c astEmptyFits. f AST_EMPTYFITS. * - This method attempt to execute even if an error has occurred * previously. *-- */ /* Ensure a FitsChan was supplied. */ if( this ) { /* Ensure the source function has been called */ ReadFromSource( this, status ); /* We can usefully use the local destructor function to do the work, since it only frees resources used within teh FitsChan, rather than freeing the FitsChan itself. */ Delete( (AstObject *) this, status ); } } static void WriteInt( AstChannel *this_channel, const char *name, int set, int helpful, int value, const char *comment, int *status ) { /* * Name: * WriteInt * Purpose: * Write an int value to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteInt( AstChannel *this, const char *name, * int set, int helpful, * int value, const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected * astWriteInt method inherited from the Channel class). * Description: * This function writes a named int value, representing the * value of a class instance variable, to the data sink associated * with a FitsChan. It is intended for use by class "Dump" * functions when writing out class information which will * subsequently be re-read. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a constant null-terminated string containing the * name to be used to identify the value in the external * representation. This will form the key for identifying it * again when it is re-read. The name supplied should be unique * within its class. * * Mixed case may be used and will be preserved in the external * representation (where possible) for cosmetic effect. However, * case is not significant when re-reading values. * * It is recommended that a maximum of 6 alphanumeric characters * (starting with an alphabetic character) be used. This permits * maximum flexibility in adapting to standard external data * representations (e.g. FITS). * set * If this is zero, it indicates that the value being written is * a default value (or can be re-generated from other values) so * need not necessarily be written out. Such values will * typically be included in the external representation with * (e.g.) a comment character so that they are available to * human readers but will be ignored when re-read. They may also * be completely omitted in some circumstances. * * If "set" is non-zero, the value will always be explicitly * included in the external representation so that it can be * re-read. * helpful * This flag provides a hint about whether a value whose "set" * flag is zero (above) should actually appear at all in the * external representaton. * * If the external representation allows values to be "commented * out" then, by default, values will be included in this form * only if their "helpful" flag is non-zero. Otherwise, they * will be omitted entirely. When possible, omitting the more * obscure values associated with a class is recommended in * order to improve readability. * * This default behaviour may be further modified if the * FitsChan's Full attribute is set - either to permit all * values to be shown, or to suppress non-essential information * entirely. * value * The value to be written. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the value. * * Note that this comment may not actually be used, depending on * the nature of the FitsChan supplied and the setting of its * Comm attribute. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Use the "set" and "helpful" flags, along with the FitsChan's attributes to decide whether this value should actually be written. */ if ( Use( this, set, helpful, status ) ) { /* Create a unique FITS keyword from the name supplied. */ CreateKeyword( this, name, keyword, status ); /* Write the value to the FitsChan as a keyword and value */ astSetFitsI( this, keyword, value, astGetComment( this ) ? comment : NULL, 0 ); /* If the value is not "set", replace the card just written by a COMMENT card containing the text of the card as the comment. */ if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status ); /* Increment the count of items written. */ items_written++; } } static void WriteIsA( AstChannel *this_channel, const char *class, const char *comment, int *status ) { /* * Name: * WriteIsA * Purpose: * Write an "IsA" data item to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteIsA( AstChannel *this, const char *class, * const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected astWriteIsA * method inherited from the Channel class). * Description: * This function writes an "IsA" data item to the data sink * associated with a FitsChan. This item delimits the end of the * data associated with the instance variables of a class, as part * of an overall Object definition. * Parameters: * this * Pointer to the FitsChan. * class * Pointer to a constant null-terminated string containing the * name of the class whose data are terminated by the "IsA" * item. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the "IsA" * item. Normally, this will describe the purpose of the class * whose data are being terminated. * Notes: * - The comment supplied may not actually be used, depending on * the nature of the FitsChan supplied. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ]; /* Character buffer */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Output an "IsA" item only if there has been at least one item written since the last "Begin" or "IsA" item, or if the Full attribute for the Channel is greater than zero (requesting maximum information). */ if ( items_written || astGetFull( this ) > 0 ) { /* Create a unique FITS keyword for this "IsA" item, basing it on "ISA". */ CreateKeyword( this, "ISA", keyword, status ); /* Generate a pre-quoted version of the class name. */ PreQuote( class, buff, status ); /* Write the "IsA" item to the FitsChan as a keyword and string value. */ astSetFitsS( this, keyword, buff, astGetComment( this ) ? comment : NULL, 0 ); /* If helpful information has not been suppressed, generate an indented comment to mark the "IsA" item and write it to the FitsChan as a comment card with a blank keyword. */ if ( astGetFull( this ) >= 0 ) { MakeIndentedComment( current_indent, '.', "Class boundary", "", buff, status ); astSetFitsCom( this, " ", buff, 0 ); } } /* Clear the count of items written. */ items_written = 0; } static void WriteObject( AstChannel *this_channel, const char *name, int set, int helpful, AstObject *value, const char *comment, int *status ) { /* * Name: * WriteObject * Purpose: * Write an Object value to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteObject( AstChannel *this, const char *name, * int set, int helpful, * AstObject *value, const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected * astWriteObject method inherited from the Channel class). * Description: * This function writes a named Object value, representing the * value of a class instance variable, to the data sink associated * with a FitsChan. It is intended for use by class "Dump" * functions when writing out class information which will * subsequently be re-read. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a constant null-terminated string containing the * name to be used to identify the value in the external * representation. This will form the key for identifying it * again when it is re-read. The name supplied should be unique * within its class. * * Mixed case may be used and will be preserved in the external * representation (where possible) for cosmetic effect. However, * case is not significant when re-reading values. * * It is recommended that a maximum of 6 alphanumeric characters * (starting with an alphabetic character) be used. This permits * maximum flexibility in adapting to standard external data * representations (e.g. FITS). * set * If this is zero, it indicates that the value being written is * a default value (or can be re-generated from other values) so * need not necessarily be written out. Such values will * typically be included in the external representation with * (e.g.) a comment character so that they are available to * human readers but will be ignored when re-read. They may also * be completely omitted in some circumstances. * * If "set" is non-zero, the value will always be explicitly * included in the external representation so that it can be * re-read. * helpful * This flag provides a hint about whether a value whose "set" * flag is zero (above) should actually appear at all in the * external representaton. * * If the external representation allows values to be "commented * out" then, by default, values will be included in this form * only if their "helpful" flag is non-zero. Otherwise, they * will be omitted entirely. When possible, omitting the more * obscure values associated with a class is recommended in * order to improve readability. * * This default behaviour may be further modified if the * FitsChan's Full attribute is set - either to permit all * values to be shown, or to suppress non-essential information * entirely. * value * A pointer to the Object to be written. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the value. * * Note that this comment may not actually be used, depending on * the nature of the FitsChan supplied and the setting of its * Comm attribute. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Use the "set" and "helpful" flags, along with the FitsChan's attributes to decide whether this value should actually be written. */ if ( Use( this, set, helpful, status ) ) { /* Create a unique FITS keyword from the name supplied. */ CreateKeyword( this, name, keyword, status ); /* Write the value to the FitsChan as a keyword and a blank string value, not pre-quoted (this "null" value indicates that an Object description follows). */ astSetFitsS( this, keyword, "", astGetComment( this ) ? comment : NULL, 0 ); /* If the value is "set", write out the Object description. */ if ( set ) { astWrite( this, value ); /* If the value is not set, replace the card just written to the FitsChan by COMENT card containing the keyword and blank string value (do not write out the Object description). */ } else { MakeIntoComment( this, "astWrite", astGetClass( this ), status ); } /* Increment the count of items written. */ items_written++; } } static void WriteToSink( AstFitsChan *this, int *status ){ /* * Name: * WriteToSink * Purpose: * Write the contents of the FitsChan out to the sink file or function. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteToSink( AstFitsChan *this, int *status ) * Class Membership: * FitsChan member function. * Description: * If the SinkFile attribute is set, each card in the FitsChan is * written out to the sink file. Otherwise, the cards are passed in * turn to the sink function specified when the FitsChan was created. * If no sink function was provided, the cards are not written out. * Cards marked as having been read into an AST object are not written * out. * Parameters: * this * Pointer to the FitsChan. * status * Pointer to the inherited status variable. * Notes: * - The current card is left unchanged. */ /* Local Constants: */ #define ERRBUF_LEN 80 /* Local Variables: */ FILE *fd; /* File descriptor for sink file */ astDECLARE_GLOBALS /* Declare the thread specific global data */ char *errstat; /* Pointer for system error message */ char card[ AST__FITSCHAN_FITSCARDLEN + 1]; /* Buffer for header card */ char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ const char *sink_file; /* Path to output sink file */ int icard; /* Current card index on entry */ int old_ignore_used; /* Original value of external variable ignore_used */ /* Check the global status. */ if( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this); /* If the SinkFile attribute is set, open the file. */ fd = NULL; if( astTestSinkFile( this ) ) { sink_file = astGetSinkFile( this ); fd = fopen( sink_file, "w" ); if( !fd ) { if ( errno ) { #if HAVE_STRERROR_R strerror_r( errno, errbuf, ERRBUF_LEN ); errstat = errbuf; #else errstat = strerror( errno ); #endif astError( AST__WRERR, "astDelete(%s): Failed to open output " "SinkFile '%s' - %s.", status, astGetClass( this ), sink_file, errstat ); } else { astError( AST__WRERR, "astDelete(%s): Failed to open output " "SinkFile '%s'.", status, astGetClass( this ), sink_file ); } } } /* Only proceed if a file was opened, or sink function and wrapper were supplied. */ if( fd || ( this->sink && this->sink_wrap ) ){ /* Store the current card index. */ icard = astGetCard( this ); /* Indicate that cards which have been read into an AST object should skipped over by the functions which navigate the linked list of cards. */ old_ignore_used = ignore_used; ignore_used = 1; /* Ensure that the first card in the FitsChan will be the next one to be read. */ astSetCard( this, 1 ); /* Loop round obtaining and writing out each card, until all cards have been processed. */ while( !astFitsEof( this ) && astOK ){ /* Get the current card, and write it out through the sink function. The call to astFindFits increments the current card. */ if( astFindFits( this, "%f", card, 1 ) ) { /* If s sink file was opened, write the card out to it. */ if( fd ) { fprintf( fd, "%s\n", card ); /* Otherwise, use the isnk function. The sink function is an externally supplied function which may not be thread-safe, so lock a mutex first. Also store the channel data pointer in a global variable so that it can be accessed in the sink function using macro astChannelData. */ } else { astStoreChannelData( this ); LOCK_MUTEX3; ( *this->sink_wrap )( *this->sink, card, status ); UNLOCK_MUTEX3; } } } /* Re-instate the original flag indicating if cards marked as having been read should be skipped over. */ ignore_used = old_ignore_used; /* Set the current card index back to what it was on entry. */ astSetCard( this, icard ); } /* Close the sink file. */ if( fd ) fclose( fd ); } static void WriteString( AstChannel *this_channel, const char *name, int set, int helpful, const char *value, const char *comment, int *status ) { /* * Name: * WriteString * Purpose: * Write a string value to a data sink. * Type: * Private function. * Synopsis: * #include "fitschan.h" * void WriteString( AstChannel *this, const char *name, * int set, int helpful, * const char *value, const char *comment ) * Class Membership: * FitsChan member function (over-rides the protected * astWriteString method inherited from the Channel class). * Description: * This function writes a named string value, representing the * value of a class instance variable, to the data sink associated * with a FitsChan. It is intended for use by class "Dump" * functions when writing out class information which will * subsequently be re-read. * Parameters: * this * Pointer to the FitsChan. * name * Pointer to a constant null-terminated string containing the * name to be used to identify the value in the external * representation. This will form the key for identifying it * again when it is re-read. The name supplied should be unique * within its class. * * Mixed case may be used and will be preserved in the external * representation (where possible) for cosmetic effect. However, * case is not significant when re-reading values. * * It is recommended that a maximum of 6 alphanumeric characters * (starting with an alphabetic character) be used. This permits * maximum flexibility in adapting to standard external data * representations (e.g. FITS). * set * If this is zero, it indicates that the value being written is * a default value (or can be re-generated from other values) so * need not necessarily be written out. Such values will * typically be included in the external representation with * (e.g.) a comment character so that they are available to * human readers but will be ignored when re-read. They may also * be completely omitted in some circumstances. * * If "set" is non-zero, the value will always be explicitly * included in the external representation so that it can be * re-read. * helpful * This flag provides a hint about whether a value whose "set" * flag is zero (above) should actually appear at all in the * external representaton. * * If the external representation allows values to be "commented * out" then, by default, values will be included in this form * only if their "helpful" flag is non-zero. Otherwise, they * will be omitted entirely. When possible, omitting the more * obscure values associated with a class is recommended in * order to improve readability. * * This default behaviour may be further modified if the * FitsChan's Full attribute is set - either to permit all * values to be shown, or to suppress non-essential information * entirely. * value * Pointer to a constant null-terminated string containing the * value to be written. * comment * Pointer to a constant null-terminated string containing a * textual comment to be associated with the value. * * Note that this comment may not actually be used, depending on * the nature of the FitsChan supplied and the setting of its * Comm attribute. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ AstFitsChan *this; /* Pointer to the FitsChan structure. */ char *c; /* Pointer to next buffer character */ char buff1[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ]; /* Buffer for a single substring */ char buff2[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ]; /* Buffer for pre-quoted string */ char cc; /* Next character */ char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */ const char *start; /* Pointer to start of substring */ int first; /* Is this the first sub-string? */ int nc; /* No. of available columns remaining */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_channel); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_channel; /* Use the "set" and "helpful" flags, along with the FitsChan's attributes to decide whether this value should actually be written. */ if ( Use( this, set, helpful, status ) ) { /* Create a unique FITS keyword from the name supplied. */ CreateKeyword( this, name, keyword, status ); /* Store a pointer to the start of the next sub-string (i.e. the beggining of the string), and then loop round until the end of the string is reached. */ start = value; first = 1; while( *start && astOK ){ /* Store the number of characters available in the 80 column header card for the next substring, leaving room for the "= " string at the start, and the delimiting quotes. Also reserve 2 characters to allow for the possibility of double quotes being needed to protect trailing white space (see function PreQuote). */ nc = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 6; /* If this is the first sub-string reserve room for any comment. */ if( first ){ if( comment && comment[0] ) nc -= ChrLen( comment, status ) + 3; /* If the first card will be turned into a comment card, we need to leave room for the keyword name and equals sign, etc, within the 80 columns. */ if( !set ) nc -= FITSNAMLEN + 5; } /* We need to check the sub-string for single quotes since these will take up 2 characters each instead of 1 when encoded since single quotes within a string are doubled. Search through from the starting character, copying the sub-string into a buffer, and reducing the number of available characters remaining in the card for each character. */ c = buff1; while( *start && nc > 0 ){ cc = *(start++); *(c++) = cc; if( cc == '\'' ) { nc -= 2; } else { nc -= 1; } } /* If the last character in the substring was a single quote, there may not have been room for the extra quote which is added when the sub-string is encoded. In this case we need to back up a character in order to remove the single quote frin this substring and move it into the next sub-string. */ if( nc < 0 ){ start--; c--; } /* If the supplied value has not been exhausted, append an ampersand to the string. In this case we need to move the last character in the substring into the next substring to make room for the ampersand. */ if( *start ) { start--; c--; *(c++) = '&'; } /* Terminate the buffer. */ *c = 0; /* The FITS standard considers trailing white space is be insignificant, and so we need to guard against external applications throwing away significant trailing white space. This is done by encosing the string, including trailing white space, in double quotes. */ PreQuote( buff1, buff2, status ); /* On the first pass through this loop, write the value to the FitsChan as a keyword and value */ if( first ){ astSetFitsS( this, keyword, buff2, astGetComment( this ) ? comment : NULL, 0 ); /* If the value is not "set", replace the card just written by a COMMENT card containing the text of the card as the comment. */ if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status ); /* On subsequent passes through the loop, store the string using a CONTINUE keyword, with type AST__CONTINUE (this type is like AST__STRING but is formatted without an equals sign). */ } else { astSetFitsCN( this, "CONTINUE", buff2, NULL, 0 ); } first = 0; } /* Increment the count of items written. */ items_written++; } } static AstMapping *ZPXMapping( AstFitsChan *this, FitsStore *store, char s, int naxes, int zpxaxes[2], const char *method, const char *class, int *status ){ /* * Name: * ZPXMapping * Purpose: * Create a Mapping descriping "-ZPX" (IRAF) distortion. * Type: * Private function. * Synopsis: * AstMapping *ZPXMapping( AstFitsChan *this, FitsStore *store, char s, * int naxes, int zpxaxes[2], const char *method, * const char *class, int *status ) * Class Membership: * FitsChan * Description: * This function uses the values in the supplied FitsStore to create a * Mapping which implements the "-ZPX" distortion code, produced by * the IRAF project. See: * * http://iraf.noao.edu/projects/ccdmosaic/zpx.html * * Note, the Mapping created by this function implements the "lngcor" * and "latcor" corrections described in the WAT... keywords. The * basic ZPN projection code is handled in the normal way, as any * other projection is handled. * Parameters: * store * A structure containing information about the requested axis * descriptions derived from a FITS header. * s * A character identifying the co-ordinate version to use. A space * means use primary axis descriptions. Otherwise, it must be an * upper-case alphabetical characters ('A' to 'Z'). * naxes * The number of intermediate world coordinate axes (WCSAXES). * zpxaxes * The zero-based indices of the two IWC axes that use the ZPX projection. * method * A pointer to a string holding the name of the calling method. * This is used only in the construction of error messages. * class * A pointer to a string holding the class of the object being * read. This is used only in the construction of error messages. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the Mapping. */ /* Local Variables: */ AstMapping *ret; char *watstr; double *cvals[ 2 ]; int *mvals[ 2 ]; int ncoeff[ 2 ]; int i; int icoeff; int ok; /* Initialise the pointer to the returned Mapping. */ ret = NULL; /* Check the global status. */ if ( !astOK ) return ret; /* Check both axes */ for( i = 0; i < 2; i++ ){ mvals[ i ] = NULL; cvals[ i ] = NULL; ncoeff[ i ] = 0; /* Concatenate all the IRAF "WAT" keywords together for this axis. These keywords are marked as having been used, so that they are not written out when the FitsChan is deleted. */ watstr = ConcatWAT( this, zpxaxes[ i ], method, class, status ); /* Extract the polynomial coefficients from the concatenated WAT string. These are returned in the form of a list of PVi_m values for a TPN projection. */ ncoeff[ i ] = WATCoeffs( watstr, i, cvals + i, mvals + i, &ok, status ); /* If the current axis of the ZPX projection uses features not supported by AST, do not do any more axes. */ if( !ok ) break; /* Free the WAT string. */ watstr = astFree( watstr ); } /* If we can handle the ZPX projection, store the polynomial coefficients in a new inverted TPN WcsMap. This WcsMap is used as a correction to the ZPN WcsMap to be created later, therefore set its FITSProj value to zero so that it is not used as the FITS projection when written out via astWrite. Also set TPNTan to zero to indicate that the TAN part of the TPN projection should not be used (i.e. just use the polynomial part). */ if( ok && astOK ) { if( ncoeff[ 0 ] || ncoeff[ 1 ] ) { ret = (AstMapping *) astWcsMap( naxes, AST__TPN, zpxaxes[ 0 ] + 1, zpxaxes[ 1 ] + 1, "Invert=1", status ); astSetFITSProj( ret, 0 ); astSetTPNTan( ret, 0 ); for( i = 0; i < 2; i++ ){ for( icoeff = 0; icoeff < ncoeff[ i ]; icoeff++ ) { astSetPV( ret, zpxaxes[ i ], (mvals[ i ])[ icoeff ], (cvals[ i ])[ icoeff ] ); } } } else { ret = (AstMapping *) astUnitMap( naxes, " ", status ); } /* If the TNX cannot be represented in FITS-WCS (within our restrictions), add warning keywords to the FitsChan. */ } else { Warn( this, "zpx", "This FITS header includes, or was " "derived from, a ZPX projection which requires " "unsupported IRAF-specific corrections. The WCS " "information may therefore be incorrect.", method, class, status ); } /* Return the result. */ return ret; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* Card. */ /* ===== */ /* *att++ * Name: * Card * Purpose: * Index of current FITS card in a FitsChan. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute gives the index of the "current" FITS header card * within a FitsChan, the first card having an index of 1. The c choice of current card affects the behaviour of functions that f choice of current card affects the behaviour of routines that c access the contents of the FitsChan, such as astDelFits, c astFindFits and astPutFits. f access the contents of the FitsChan, such as AST_DELFITS, f AST_FINDFITS and AST_PUTFITS. * * A value assigned to Card will position the FitsChan at any * desired point, so that a particular card within it can be * accessed. Alternatively, the value of Card may be enquired in * order to determine the current position of a FitsChan. * * The default value of Card is 1. This means that clearing c this attribute (using astClear) effectively "rewinds" the f this attribute (using AST_CLEAR) effectively "rewinds" the * FitsChan, so that the first card is accessed next. If Card is * set to a value which exceeds the total number of cards in the * FitsChan (as given by its Ncard attribute), it is regarded as * pointing at the "end-of-file". In this case, the value returned * in response to an enquiry is always one more than the number of * cards in the FitsChan. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Encoding. */ /* ========= */ /* *att++ * Name: * Encoding * Purpose: * System for encoding Objects as FITS headers. * Type: * Public attribute. * Synopsis: * String. * Description: * This attribute specifies the encoding system to use when AST * Objects are stored as FITS header cards in a FitsChan. It c affects the behaviour of the astWrite and astRead functions when f affects the behaviour of the AST_WRITE and AST_READ routines when * they are used to transfer any AST Object to or from an external * representation consisting of FITS header cards (i.e. whenever a * write or read operation is performed using a FitsChan as the I/O * Channel). * * There are several ways (conventions) by which coordinate system * information may be represented in the form of FITS headers and * the Encoding attribute is used to specify which of these should * be used. The encoding options available are outlined in the * "Encodings Available" section below, and in more detail in the * sections which follow. * * Encoding systems differ in the range of possible Objects * (e.g. classes) they can represent, in the restrictions they * place on these Objects (e.g. compatibility with some * externally-defined coordinate system model) and in the number of * Objects that can be stored together in any particular set of * FITS header cards (e.g. multiple Objects, or only a single * Object). The choice of encoding also affects the range of * external applications which can potentially read and interpret * the FITS header cards produced. * * The encoding options available are not necessarily mutually * exclusive, and it may sometimes be possible to store multiple * Objects (or the same Object several times) using different * encodings within the same set of FITS header cards. This * possibility increases the likelihood of other applications being * able to read and interpret the information. * * By default, a FitsChan will attempt to determine which encoding * system is already in use, and will set the default Encoding * value accordingly (so that subsequent I/O operations adopt the * same conventions). It does this by looking for certain critical * FITS keywords which only occur in particular encodings. For * details of how this works, see the "Choice of Default Encoding" * section below. If you wish to ensure that a particular encoding * system is used, independently of any FITS cards already present, * you should set an explicit Encoding value yourself. * Encodings Available: * The Encoding attribute can take any of the following (case * insensitive) string values to select the corresponding encoding * system: * * - "DSS": Encodes coordinate system information in FITS header * cards using the convention developed at the Space Telescope * Science Institute (STScI) for the Digitised Sky Survey (DSS) * astrometric plate calibrations. The main advantages of this * encoding are that FITS images which use it are widely available * and it is understood by a number of important and * well-established astronomy applications. For further details, * see the section "The DSS Encoding" below. * * - "FITS-WCS": Encodes coordinate system information in FITS * header cards using the conventions described in the FITS * world coordinate system (FITS-WCS) papers by E.W. Greisen, * M. Calabretta, et al. The main advantages of this encoding are that * it should be understood by any FITS-WCS compliant application and * is likely to be adopted widely for FITS data in future. For further * details, see the section "The FITS-WCS Encoding" below. * * - "FITS-PC": Encodes coordinate system information in FITS * header cards using the conventions described in an earlier draft * of the FITS world coordinate system papers by E.W. Greisen and * M. Calabretta. This encoding uses a combination of CDELTi and * PCiiijjj keywords to describe the scale and rotation of the pixel * axes. This encoding is included to support existing data and * software which uses these now superceded conventions. In general, * the "FITS-WCS" encoding (which uses CDi_j or PCi_j keywords to * describe the scale and rotation) should be used in preference to * "FITS-PC". * * - "FITS-IRAF": Encodes coordinate system information in FITS * header cards using the conventions described in the document * "World Coordinate Systems Representations Within the FITS * Format" by R.J. Hanisch and D.G. Wells, 1988. This encoding is * currently employed by the IRAF data analysis facility, so its * use will facilitate data exchange with IRAF. Its main advantages * are that it is a stable convention which approximates to a * subset of the propsed FITS-WCS encoding (above). This makes it * suitable as an interim method for storing coordinate system * information in FITS headers until the FITS-WCS encoding becomes * stable. Since many datasets currently use the FITS-IRAF * encoding, conversion of data from FITS-IRAF to the final form of * FITS-WCS is likely to be well supported. * * - "FITS-AIPS": Encodes coordinate system information in FITS * header cards using the conventions originally introduced by the * AIPS data analysis facility. This is base on the use of CDELTi and * CROTAi keuwords to desribe the scale and rotation of each axis. * These conventions have been superceded but are still widely used. * * - "FITS-AIPS++": Encodes coordinate system information in FITS * header cards using the conventions used by the AIPS++ project. * This is an extension of FITS-AIPS which includes some of the * features of FITS-IRAF and FITS-PC. * * - "FITS-CLASS": Encodes coordinate system information in FITS * header cards using the conventions used by the CLASS project. * CLASS is a software package for reducing single-dish radio and * sub-mm spectroscopic data. See the section "CLASS FITS format" at * http://www.iram.fr/IRAMFR/GILDAS/doc/html/class-html/. * * - "NATIVE": Encodes AST Objects in FITS header cards using a * convention which is private to the AST library (but adheres to * the general FITS standard) and which uses FITS keywords that * will not clash with other encoding systems. The main advantages * of this are that any class of AST Object may be encoded, and any * (reasonable) number of Objects may be stored sequentially in the * same FITS header. This makes FITS headers an almost loss-less * communication path for passing AST Objects between applications * (although all such applications must, of course, make use of the * AST library to interpret the information). For further details, * see the section "The NATIVE Encoding" below. * Choice of Default Encoding: * If the Encoding attribute of a FitsChan is not set, the default * value it takes is determined by the presence of certain critical * FITS keywords within the FitsChan. The sequence of decisions * used to arrive at the default value is as follows: * * - If the FitsChan contains any keywords beginning with the * string "BEGAST", then NATIVE encoding is used, * - Otherwise, FITS-CLASS is used if the FitsChan contains a DELTAV * keyword and a keyword of the form VELO-xxx, where xxx indicates one * of the rest frames used by class (e.g. "VELO-LSR"), or "VLSR". * - Otherwise, if the FitsChan contains a CTYPE keyword which * represents a spectral axis using the conventions of the AIPS and * AIPS++ projects (e.g. "FELO-LSR", etc), then one of FITS-AIPS or * FITS-AIPS++ encoding is used. FITS-AIPS++ is used if any of the * keywords CDi_j, PROJP, LONPOLE or LATPOLE are * found in the FitsChan. Otherwise FITS-AIPS is used. * - Otherwise, if the FitsChan contains a keyword of the form * "PCiiijjj", where "i" and "j" are single digits, then * FITS-PC encoding is used, * - Otherwise, if the FitsChan contains a keyword of the form * "CDiiijjj", where "i" and "j" are single digits, then * FITS-IRAF encoding is used, * - Otherwise, if the FitsChan contains a keyword of the form * "CDi_j", and at least one of RADECSYS, PROJPi, or CjVALi * where "i" and "j" are single digits, then FITS-IRAF encoding is * used. * - Otherwise, if the FitsChan contains any keywords of the form * PROJPi, CjVALi or RADECSYS, where "i" and "j" are single digits, * then FITS-PC encoding is used. * - Otherwise, if the FitsChan contains a keyword of the form * CROTAi, where "i" is a single digit, then FITS-AIPS encoding is * used. * - Otherwise, if the FitsChan contains a keyword of the form * CRVALi, where "i" is a single digit, then FITS-WCS encoding is * used. * - Otherwise, if the FitsChan contains the "PLTRAH" keyword, then * DSS encoding is used, * - Otherwise, if none of these conditions is met (as would be the * case when using an empty FitsChan), then NATIVE encoding is * used. * * Except for the NATIVE and DSS encodings, all the above checks * also require that the header contains at least one CTYPE, CRPIX and * CRVAL keyword (otherwise the checking process continues to the next * case). * * Setting an explicit value for the Encoding attribute always * over-rides this default behaviour. * * Note that when writing information to a FitsChan, the choice of * encoding will depend greatly on the type of application you * expect to be reading the information in future. If you do not * know this, there may sometimes be an advantage in writing the * information several times, using a different encoding on each * occasion. * The DSS Encoding: * The DSS encoding uses FITS header cards to store a multi-term * polynomial which relates pixel positions on a digitised * photographic plate to celestial coordinates (right ascension and * declination). This encoding may only be used to store a single * AST Object in any set of FITS header cards, and that Object must * be a FrameSet which conforms to the STScI/DSS coordinate system * model (this means the Mapping which relates its base and current * Frames must include either a DssMap or a WcsMap with type * AST__TAN or AST__TPN). * c When reading a DSS encoded Object (using astRead), the FitsChan f When reading a DSS encoded Object (using AST_READ), the FitsChan * concerned must initially be positioned at the first card (its * Card attribute must equal 1) and the result of the read, if * successful, will always be a pointer to a FrameSet. The base * Frame of this FrameSet represents DSS pixel coordinates, and the * current Frame represents DSS celestial coordinates. Such a read * is always destructive and causes the FITS header cards required * for the construction of the FrameSet to be removed from the * FitsChan, which is then left positioned at the "end-of-file". A * subsequent read using the same encoding will therefore not * return another FrameSet, even if the FitsChan is rewound. * c When astWrite is used to store a FrameSet using DSS encoding, f When AST_WRITE is used to store a FrameSet using DSS encoding, * an attempt is first made to simplify the FrameSet to see if it * conforms to the DSS model. Specifically, the current Frame must * be a FK5 SkyFrame; the projection must be a tangent plane * (gnomonic) projection with polynomial corrections conforming to * DSS requirements, and north must be parallel to the second base * Frame axis. * * If the simplification process succeeds, a description of the * FrameSet is written to the FitsChan using appropriate DSS FITS * header cards. The base Frame of the FrameSet is used to form the * DSS pixel coordinate system and the current Frame gives the DSS * celestial coordinate system. A successful write operation will * over-write any existing DSS encoded data in the FitsChan, but * will not affect other (non-DSS) header cards. If a destructive * read of a DSS encoded Object has previously occurred, then an * attempt will be made to store the FITS header cards back in * their original locations. * * If an attempt to simplify a FrameSet to conform to the DSS model * fails (or if the Object supplied is not a FrameSet), then no c data will be written to the FitsChan and astWrite will return f data will be written to the FitsChan and AST_WRITE will return * zero. No error will result. * The FITS-WCS Encoding: * The FITS-WCS convention uses FITS header cards to describe the * relationship between pixels in an image (not necessarily * 2-dimensional) and one or more related "world coordinate systems". * The FITS-WCS encoding may only be used to store a single AST Object * in any set of FITS header cards, and that Object must be a FrameSet * which conforms to the FITS-WCS model (the FrameSet may, however, * contain multiple Frames which will be result in multiple FITS * "alternate axis descriptions"). Details of the use made by this * Encoding of the conventions described in the FITS-WCS papers are * given in the appendix "FITS-WCS Coverage" of this document. A few * main points are described below. * * The rotation and scaling of the intermediate world coordinate system * can be specified using either "CDi_j" keywords, or "PCi_j" together * with "CDELTi" keywords. When writing a FrameSet to a FitsChan, the * the value of the CDMatrix attribute of the FitsChan determines * which system is used. * * In addition, this encoding supports the "TAN with polynomial correction * terms" projection which was included in a draft of the FITS-WCS paper, * but was not present in the final version. A "TAN with polynomial * correction terms" projection is represented using a WcsMap with type * AST__TPN (rather than AST__TAN which is used to represent simple * TAN projections). When reading a FITS header, a CTYPE keyword value * including a "-TAN" code results in an AST__TPN projection if there are * any projection parameters (given by the PVi_m keywords) associated with * the latitude axis, or if there are projection parameters associated * with the longitude axis for m greater than 4. When writing a * FrameSet to a FITS header, an AST__TPN projection gives rise to a * CTYPE value including the normal "-TAN" code, but the projection * parameters are stored in keywords with names "QVi_m", instead of the * usual "PVi_m". Since these QV parameters are not part of the * FITS-WCS standard they will be ignored by other non-AST software, * resulting in the WCS being interpreted as a simple TAN projection * without any corrections. This should be seen as an interim solution * until such time as an agreed method for describing projection * distortions within FITS-WCS has been published. * * AST extends the range of celestial coordinate systems which may be * described using this encoding by allowing the inclusion of * "AZ--" and "EL--" as the coordinate specification within CTYPE * values. These form a longitude/latitude pair of axes which describe * azimuth and elevation. The geographic position of the observer * should be supplied using the OBSGEO-X/Y/Z keywords described in FITS-WCS * paper III. Currently, a simple model is used which includes diurnal * aberration, but ignores atmospheric refraction, polar motion, etc. * These may be added in a later release. * * If an AST SkyFrame that represents offset rather than absolute * coordinates (see attribute SkyRefIs) is written to a FitsChan using * FITS-WCS encoding, two alternate axis descriptions will be created. * One will describe the offset coordinates, and will use "OFLN" and * "OFLT" as the axis codes in the CTYPE keywords. The other will * describe absolute coordinates as specified by the System attribute * of the SkyFrame, using the usual CTYPE codes ("RA--"/"DEC-", etc). * In addition, the absolute coordinates description will contain * AST-specific keywords (SREF1/2, SREFP1/2 and SREFIS) that allow the * header to be read back into AST in order to reconstruct the original * SkyFrame. * c When reading a FITS-WCS encoded Object (using astRead), the FitsChan f When reading a FITS-WCS encoded Object (using AST_READ), the FitsChan * concerned must initially be positioned at the first card (its * Card attribute must equal 1) and the result of the read, if * successful, will always be a pointer to a FrameSet. The base * Frame of this FrameSet represents FITS-WCS pixel coordinates, * and the current Frame represents the physical coordinate system * described by the FITS-WCS primary axis descriptions. If * secondary axis descriptions are also present, then the FrameSet * may contain additional (non-current) Frames which represent * these. Such a read is always destructive and causes the FITS * header cards required for the construction of the FrameSet to be * removed from the FitsChan, which is then left positioned at the * "end-of-file". A subsequent read using the same encoding will * therefore not return another FrameSet, even if the FitsChan is * rewound. * c When astWrite is used to store a FrameSet using FITS-WCS f When AST_WRITE is used to store a FrameSet using FITS-WCS * encoding, an attempt is first made to simplify the FrameSet to * see if it conforms to the FITS-WCS model. If this simplification * process succeeds (as it often should, as the model is reasonably * flexible), a description of the FrameSet is written to the * FitsChan using appropriate FITS header cards. The base Frame of * the FrameSet is used to form the FITS-WCS pixel coordinate * system and the current Frame gives the physical coordinate * system to be described by the FITS-WCS primary axis * descriptions. Any additional Frames in the FrameSet may be used * to construct secondary axis descriptions, where appropriate. * * A successful write operation will over-write any existing * FITS-WCS encoded data in the FitsChan, but will not affect other * (non-FITS-WCS) header cards. If a destructive read of a FITS-WCS * encoded Object has previously occurred, then an attempt will be * made to store the FITS header cards back in their original * locations. Otherwise, the new cards will be inserted following * any other FITS-WCS related header cards present or, failing * that, in front of the current card (as given by the Card * attribute). * * If an attempt to simplify a FrameSet to conform to the FITS-WCS * model fails (or if the Object supplied is not a FrameSet), then c no data will be written to the FitsChan and astWrite will f no data will be written to the FitsChan and AST_WRITE will * return zero. No error will result. * The FITS-IRAF Encoding: * The FITS-IRAF encoding can, for most purposes, be considered as * a subset of the FITS-WCS encoding (above), although it differs * in the details of the FITS keywords used. It is used in exactly * the same way and has the same restrictions, but with the * addition of the following: * * - The only celestial coordinate systems that may be represented * are equatorial, galactic and ecliptic, * - Sky projections can be represented only if any associated * projection parameters are set to their default values. * - Secondary axis descriptions are not supported, so when writing * a FrameSet to a FitsChan, only information from the base and * current Frames will be stored. * * Note that this encoding is provided mainly as an interim measure to * provide a more stable alternative to the FITS-WCS encoding until the * FITS standard for encoding WCS information is finalised. The name * "FITS-IRAF" indicates the general keyword conventions used and does * not imply that this encoding will necessarily support all features of * the WCS scheme used by IRAF software. Nevertheless, an attempt has * been made to support a few such features where they are known to be * used by important sources of data. * * When writing a FrameSet using the FITS-IRAF encoding, axis rotations * are specified by a matrix of FITS keywords of the form "CDi_j", where * "i" and "j" are single digits. The alternative form "CDiiijjj", which * is also in use, is recognised when reading an Object, but is never * written. * * In addition, the experimental IRAF "ZPX" and "TNX" sky projections will * be accepted when reading, but will never be written (the corresponding * FITS "ZPN" or "distorted TAN" projection being used instead). However, * there are restrictions on the use of these experimental projections. * For "ZPX", longitude and latitude correction surfaces (appearing as * "lngcor" or "latcor" terms in the IRAF-specific "WAT" keywords) are * not supported. For "TNX" projections, only cubic surfaces encoded as * simple polynomials with "half cross-terms" are supported. If an * un-usable "TNX" or "ZPX" projection is encountered while reading * from a FitsChan, a simpler form of TAN or ZPN projection is used * which ignores the unsupported features and may therefore be * inaccurate. If this happens, a warning message is added to the * contents of the FitsChan as a set of cards using the keyword "ASTWARN". * * You should not normally attempt to mix the foreign FITS encodings within * the same FitsChan, since there is a risk that keyword clashes may occur. * The FITS-PC Encoding: * The FITS-PC encoding can, for most purposes, be considered as * equivalent to the FITS-WCS encoding (above), although it differs * in the details of the FITS keywords used. It is used in exactly * the same way and has the same restrictions. * The FITS-AIPS Encoding: * The FITS-AIPS encoding can, for most purposes, be considered as * equivalent to the FITS-WCS encoding (above), although it differs * in the details of the FITS keywords used. It is used in exactly * the same way and has the same restrictions, but with the * addition of the following: * * - The only celestial coordinate systems that may be represented * are equatorial, galactic and ecliptic, * - Spectral axes can only be represented if they represent * frequency, radio velocity or optical velocity, and are linearly * sampled in frequency. In addition, the standard of rest * must be LSRK, LSRD, barycentric or geocentric. * - Sky projections can be represented only if any associated * projection parameters are set to their default values. * - The AIT, SFL and MER projections can only be written if the CRVAL * keywords are zero for both longitude and latitude axes. * - Secondary axis descriptions are not supported, so when writing * a FrameSet to a FitsChan, only information from the base and * current Frames will be stored. * - If there are more than 2 axes in the base and current Frames, any * rotation must be restricted to the celestial plane, and must involve * no shear. * The FITS-AIPS++ Encoding: * The FITS-AIPS++ encoding is based on the FITS-AIPS encoding, but * includes some features of the FITS-IRAF and FITS-PC encodings. * Specifically, any celestial projections supported by FITS-PC may be * used, including those which require parameterisation, and the axis * rotation and scaling may be specified using CDi_j keywords. When * writing a FITS header, rotation will be specified using CROTA/CDELT * keywords if possible, otherwise CDi_j keywords will be used instead. * The FITS-CLASS Encoding: * The FITS-CLASS encoding uses the conventions of the CLASS project. * These are described in the section "Developer Manual"/"CLASS FITS * Format" contained in the CLASS documentation at: * * http://www.iram.fr/IRAMFR/GILDAS/doc/html/class-html/class.html. * * This encoding is similar to FITS-AIPS with the following restrictions: * * - When a SpecFrame is created by reading a FITS-CLASS header, the * attributes describing the observer's position (ObsLat, ObsLon and * ObsAlt) are left unset because the CLASS encoding does not specify * these values. Conversions to or from the topocentric standard of rest * will therefore be inaccurate (typically by up to about 0.5 km/s) * unless suitable values are assigned to these attributes after the * FrameSet has been created. * - When writing a FrameSet to a FITS-CLASS header, the current Frame * in the FrameSet must have at least 3 WCS axes, of which one must be * a linear spectral axis. The spectral axis in the created header will * always describe frequency. If the spectral axis in the supplied * FrameSet refers to some other system (e.g. radio velocity, etc), * then it will be converted to frequency. * - There must be a pair of celestial axes - either (RA,Dec) or * (GLON,GLAT). RA and Dec must be either FK4/B1950 or FK5/J2000. * - A limited range of projection codes (TAN, ARC, STG, AIT, SFL, SIN) * can be used. For AIT and SFL, the reference point must be at the * origin of longitude and latitude. For SIN, the associated projection * parameters must both be zero. * - No rotation of the celestial axes is allowed, unless the spatial * axes are degenerate (i.e. cover only a single pixel). * - The frequency axis in the created header will always describe * frequency in the source rest frame. If the supplied FrameSet uses * some other standard of rest then suitable conversion will be applied. * - The source velocity must be defined. In other words, the SpecFrame * attributes SourceVel and SourceVRF must have been assigned values. * - The frequency axis in a FITS-CLASS header does not represent * absolute frequency, but instead represents offsets from the rest * frequency in the standard of rest of the source. * * When writing a FrameSet out using FITS-CLASS encoding, the current * Frame may be temporarily modified if this will allow the header * to be produced. If this is done, the associated pixel->WCS Mapping * will also be modified to take account of the changes to the Frame. * The modifications performed include re-ordering axes (WCS axes, not * pixel axes), changing spectral coordinate system and standard of * rest, changing the celestial coordinate system and reference equinox, * and changing axis units. * The NATIVE Encoding: * The NATIVE encoding may be used to store a description of any * class of AST Object in the form of FITS header cards, and (for * most practical purposes) any number of these Object descriptions * may be stored within a single set of FITS cards. If multiple * Object descriptions are stored, they are written and read * sequentially. The NATIVE encoding makes use of unique FITS * keywords which are designed not to clash with keywords that have * already been used for other purposes (if a potential clash is * detected, an alternative keyword is constructed to avoid the * clash). * * When reading a NATIVE encoded object from a FitsChan (using c astRead), FITS header cards are read, starting at the current f AST_READ), FITS header cards are read, starting at the current * card (as determined by the Card attribute), until the start of * the next Object description is found. This description is then * read and converted into an AST Object, for which a pointer is * returned. Such a read is always destructive and causes all the * FITS header cards involved in the Object description to be * removed from the FitsChan, which is left positioned at the * following card. * * The Object returned may be of any class, depending on the * description that was read, and other AST routines may be used to * validate it (for example, by examining its Class or ID attribute c using astGetC). If further NATIVE encoded Object descriptions f using AST_GETC). If further NATIVE encoded Object descriptions c exist in the FitsChan, subsequent calls to astRead will return f exist in the FitsChan, subsequent calls to AST_READ will return * the Objects they describe in sequence (and destroy their * descriptions) until no more remain between the current card and * the "end-of-file". * c When astWrite is used to write an Object using NATIVE encoding, f When AST_WRITE is used to write an Object using NATIVE encoding, * a description of the Object is inserted immediately before the * current card (as determined by the Card attribute). Multiple * Object descriptions may be written in this way and are stored * separately (and sequentially if the Card attribute is not * modified between the writes). A write operation using the NATIVE * encoding does not over-write previously written Object * descriptions. Note, however, that subsequent behaviour is * undefined if an Object description is written inside a * previously-written description, so this should be avoided. * * When an Object is written to a FitsChan using NATIVE encoding, c astWrite should (barring errors) always transfer data and f AST_WRITE should (barring errors) always transfer data and * return a value of 1. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,Encoding,encoding,UNKNOWN_ENCODING) astMAKE_SET(FitsChan,Encoding,int,encoding,( value == NATIVE_ENCODING || value == FITSPC_ENCODING || value == FITSWCS_ENCODING || value == FITSIRAF_ENCODING || value == FITSAIPS_ENCODING || value == FITSAIPSPP_ENCODING || value == FITSCLASS_ENCODING || value == DSS_ENCODING ? value : (astError( AST__BADAT, "astSetEncoding: Unknown encoding system %d " "supplied.", status, value ), UNKNOWN_ENCODING ))) astMAKE_TEST(FitsChan,Encoding,( this->encoding != UNKNOWN_ENCODING )) /* DefB1950 */ /* ======== */ /* *att++ * Name: * DefB1950 * Purpose: * Use FK4 B1950 as defaults? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which specifies a default equinox * and reference frame to use when reading a FrameSet from a FitsChan * with a foreign (i.e. non-native) encoding. It is only used if the FITS * header contains RA and DEC axes but contains no information about the * reference frame or equinox. If this is the case, then values of FK4 and * B1950 are assumed if the DefB1950 attribute has a non-zero value and * ICRS is assumed if DefB1950 is zero. The default value for DefB1950 * depends on the value of the Encoding attribute: for FITS-WCS encoding * the default is zero, and for all other encodings it is one. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,DefB1950,defb1950,-1) astMAKE_GET(FitsChan,DefB1950,int,1,(this->defb1950 == -1 ? (astGetEncoding(this)== FITSWCS_ENCODING?0:1): this->defb1950)) astMAKE_SET(FitsChan,DefB1950,int,defb1950,( value ? 1 : 0 )) astMAKE_TEST(FitsChan,DefB1950,( this->defb1950 != -1 )) /* TabOK */ /* ===== */ /* *att++ * Name: * TabOK * Purpose: * Should the FITS-WCS -TAB algorithm be recognised? * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute is an integer value which indicates if the "-TAB" * algorithm, defined in FITS-WCS paper III, should be supported by * the FitsChan. The default value is zero. A zero or negative value * results in no support for -TAB axes (i.e. axes that have "-TAB" * in their CTYPE keyword value). In this case, the c astWrite f AST_WRITE * method will return zero if the write operation would required the * use of the -TAB algorithm, and the c astRead f AST_READ * method will return c a NULL pointer f AST__NULL * if any axis in the supplied header uses the -TAB algorithm. * If TabOK is set to a non-zero positive integer, these methods will * recognise and convert axes described by the -TAB algorithm, as * follows: * c The astWrite f The AST_WRITE * method will generate headers that use the -TAB algorithm (if * possible) if no other known FITS-WCS algorithm can be used to * describe the supplied FrameSet. This will result in a table of * coordinate values and index vectors being stored in the FitsChan. * After the write operation, the calling application should check to * see if such a table has been stored in the FitsChan. If so, the * table should be retrived from the FitsChan using the c astGetTables f AST_GETTABLES * method, and the data (and headers) within it copied into a new * FITS binary table extension. See c astGetTables f AST_GETTABLES * for more information. The FitsChan uses a FitsTable object to store * the table data and headers. This FitsTable will contain the required * columns and headers as described by FITS-WCS paper III - the * coordinates array will be in a column named "COORDS", and the index * vector(s) will be in columns named "INDEX" (where is the index * of the corresponding FITS WCS axis). Note, index vectors are only * created if required. The EXTNAME value will be set to the value of the * AST__TABEXTNAME constant (currently "WCS-TAB"). The EXTVER header * will be set to the positive integer value assigned to the TabOK * attribute. No value will be stored for the EXTLEVEL header, and should * therefore be considered to default to 1. * c The astRead f The AST_READ * method will generate a FrameSet from headers that use the -TAB * algorithm so long as the necessary FITS binary tables are made * available. There are two ways to do this: firstly, if the application * knows which FITS binary tables will be needed, then it can create a * Fitstable describing each such table and store it in the FitsChan * (using method c astPutTables or astPutTable) before invoking the astRead method. f AST_PUTTABLES or AST_PUTTABLE) before invoking the AST_READ method. * Secondly, if the application does not know which FITS binary tables * will be needed by c astRead, f AST_READ, * then it can register a call-back function with the FitsChan using * method c astTableSource. f AST_TABLESOURCE. * This call-back function will be called from within c astRead f AST_READ * if and when a -TAB header is encountered. When called, its arguments * will give the name, version and level of the FITS extension containing * a required table. The call-back function should read this table from * an external FITS file, and create a corresponding FitsTable which * it should then return to c astRead. Note, currently astRead f AST_READ. Note, currently AST_READ * can only handle -TAB headers that describe 1-dimensional (i.e. * separable) axes. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,TabOK,tabok,-INT_MAX) astMAKE_GET(FitsChan,TabOK,int,0,(this->tabok == -INT_MAX ? 0 : this->tabok)) astMAKE_SET(FitsChan,TabOK,int,tabok,value) astMAKE_TEST(FitsChan,TabOK,( this->tabok != -INT_MAX )) /* CarLin */ /* ====== */ /* *att++ * Name: * CarLin * Purpose: * Ignore spherical rotations on CAR projections? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which specifies how FITS "CAR" * (plate carree, or "Cartesian") projections should be treated when * reading a FrameSet from a foreign encoded FITS header. If zero (the * default), it is assumed that the CAR projection conforms to the * conventions described in the FITS world coordinate system (FITS-WCS) * paper II "Representation of Celestial Coordinates in FITS" by * M. Calabretta & E.W. Greisen. If CarLin is non-zero, then these * conventions are ignored, and it is assumed that the mapping from pixel * coordinates to celestial coordinates is a simple linear transformation * (hence the attribute name "CarLin"). This is appropriate for some older * FITS data which claims to have a "CAR" projection, but which in fact do * not conform to the conventions of the FITS-WCS paper. * * The FITS-WCS paper specifies that headers which include a CAR projection * represent a linear mapping from pixel coordinates to "native spherical * coordinates", NOT celestial coordinates. An extra mapping is then * required from native spherical to celestial. This mapping is a 3D * rotation and so the overall Mapping from pixel to celestial coordinates * is NOT linear. See the FITS-WCS papers for further details. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,CarLin,carlin,-1) astMAKE_GET(FitsChan,CarLin,int,1,(this->carlin == -1 ? 0 : this->carlin)) astMAKE_SET(FitsChan,CarLin,int,carlin,( value ? 1 : 0 )) astMAKE_TEST(FitsChan,CarLin,( this->carlin != -1 )) /* PolyTan */ /* ======= */ /* *att++ * Name: * PolyTan * Purpose: * Use PVi_m keywords to define distorted TAN projection? * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute is a boolean value which specifies how FITS "TAN" * projections should be treated when reading a FrameSet from a foreign * encoded FITS header. If zero, the projection is assumed to conform * to the published FITS-WCS standard. If positive, the convention * for a distorted TAN projection included in an early draft version * of FITS-WCS paper II are assumed. In this convention the * coefficients of a polynomial distortion to be applied to * intermediate world coordinates are specified by the PVi_m keywords. * This convention was removed from the paper before publication and so * does not form part of the standard. Indeed, it is incompatible with * the published standard because it re-defines the meaning of the * first five PVi_m keywords on the longitude axis, which are reserved * by the published standard for other purposes. However, headers that * use this convention are still to be found, for instance the SCAMP * utility (http://www.astromatic.net/software/scamp) creates them. * * The default value for the PolyTan attribute is -1. A negative * values causes the used convention to depend on the contents * of the FitsChan. If the FitsChan contains any PVi_m keywords for * the latitude axis, or if it contains PVi_m keywords for the * longitude axis with "m" greater than 4, then the distorted TAN * convention is used. Otherwise, the standard convention is used. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,PolyTan,polytan,-INT_MAX) astMAKE_SET(FitsChan,PolyTan,int,polytan,value) astMAKE_TEST(FitsChan,PolyTan,( this->polytan != -INT_MAX )) astMAKE_GET(FitsChan,PolyTan,int,-1,(this->polytan == -INT_MAX ? -1 : this->polytan)) /* Iwc */ /* === */ /* *att++ * Name: * Iwc * Purpose: * Include a Frame representing FITS-WCS intermediate world coordinates? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which is used when a FrameSet is * read from a FitsChan with a foreign FITS encoding (e.g. FITS-WCS) using c astRead. f AST_READ. * If it has a non-zero value then the returned FrameSet will include * Frames representing "intermediate world coordinates" (IWC). These * Frames will have Domain name "IWC" for primary axis descriptions, and * "IWCa" for secondary axis descriptions, where "a" is replaced by * the single alternate axis description character, as used in the * FITS-WCS header. The default value for "Iwc" is zero. * * FITS-WCS paper 1 defines IWC as a Cartesian coordinate system with one * axis for each WCS axis, and is the coordinate system produced by the * rotation matrix (represented by FITS keyword PCi_j, CDi_j, etc). * For instance, for a 2-D FITS-WCS header describing projected * celestial longitude and latitude, the intermediate world * coordinates represent offsets in degrees from the reference point * within the plane of projection. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,Iwc,iwc,-1) astMAKE_GET(FitsChan,Iwc,int,1,(this->iwc == -1 ? 0 : this->iwc)) astMAKE_SET(FitsChan,Iwc,int,iwc,( value ? 1 : 0 )) astMAKE_TEST(FitsChan,Iwc,( this->iwc != -1 )) /* *att++ * Name: * CDMatrix * Purpose: * Use CDi_j keywords to represent pixel scaling, rotation, etc? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute is a boolean value which specifies how the linear * transformation from pixel coordinates to intermediate world * coordinates should be represented within a FitsChan when using * FITS-WCS encoding. This transformation describes the scaling, * rotation, shear, etc., of the pixel axes. * * If the attribute has a non-zero value then the transformation is * represented by a set of CDi_j keywords representing a square matrix * (where "i" is the index of an intermediate world coordinate axis * and "j" is the index of a pixel axis). If the attribute has a zero * value the transformation is represented by a set of PCi_j keywords * (which also represent a square matrix) together with a corresponding * set of CDELTi keywords representing the axis scalings. See FITS-WCS * paper II "Representation of Celestial Coordinates in FITS" by * M. Calabretta & E.W. Greisen, for a complete description of these two * schemes. * * The default value of the CDMatrix attribute is determined by the * contents of the FitsChan at the time the attribute is accessed. If * the FitsChan contains any CDi_j keywords then the default value is * non-zero. Otherwise it is zero. Note, reading a FrameSet from a * FitsChan will in general consume any CDi_j keywords present in the * FitsChan. Thus the default value for CDMatrix following a read will * usually be zero, even if the FitsChan originally contained some * CDi_j keywords. This behaviour is similar to that of the Encoding * attribute, the default value for which is determined by the contents * of the FitsChan at the time the attribute is accessed. If you wish * to retain the original value of the CDMatrix attribute (that is, * the value before reading the FrameSet) then you should enquire the * default value before doing the read, and then set that value * explicitly. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,CDMatrix,cdmatrix,-1) astMAKE_SET(FitsChan,CDMatrix,int,cdmatrix,( value ? 1 : 0 )) astMAKE_TEST(FitsChan,CDMatrix,( this->cdmatrix != -1 )) /* Clean */ /* ===== */ /* *att++ * Name: * Clean * Purpose: * Remove cards used whilst reading even if an error occurs? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This attribute indicates whether or not cards should be removed from * the FitsChan if an error occurs within c astRead. f AST_READ. * A succesful read on a FitsChan always results in the removal of * the cards which were involved in the description of the returned * Object. However, in the event of an error during the read (for instance * if the cards in the FitsChan have illegal values, or if some required * cards are missing) no cards will be removed from the FitsChan if * the Clean attribute is zero (the default). If Clean is non-zero then * any cards which were used in the aborted attempt to read an object * will be removed. * * This provides a means of "cleaning" a FitsChan of WCS related cards * which works even in the event of the cards not forming a legal WCS * description. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,Clean,clean,-1) astMAKE_SET(FitsChan,Clean,int,clean,( value ? 1 : 0 )) astMAKE_TEST(FitsChan,Clean,( this->clean != -1 )) /* FitsDigits. */ /* =========== */ /* *att++ * Name: * FitsDigits * Purpose: * Digits of precision for floating point FITS values. * Type: * Public attribute. * Synopsis: * Integer. * Description: * This attribute gives the number of significant decimal digits to * use when formatting floating point values for inclusion in the * FITS header cards within a FitsChan. * * By default, a positive value is used which results in no loss of c information, assuming that the value's precision is double. f information, assuming that the value is double precision. * Usually, this causes no problems. * * However, to adhere strictly to the recommendations of the FITS * standard, the width of the formatted value (including sign, * decimal point and exponent) ought not to be more than 20 * characters. If you are concerned about this, you should set * FitsDigits to a negative value, such as -15. In this case, the * absolute value (+15) indicates the maximum number of significant * digits to use, but the actual number used may be fewer than this * to ensure that the FITS recommendations are satisfied. When * using this approach, the resulting number of significant digits * may depend on the value being formatted and on the presence of * any sign, decimal point or exponent. * * The value of this attribute is effective when FITS header cards * are output, either using c astFindFits or by the action of the FitsChan's sink function f AST_FINDFITS or by the action of the FitsChan's sink routine * when it is finally deleted. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ astMAKE_CLEAR(FitsChan,FitsDigits,fitsdigits,DBL_DIG) astMAKE_GET(FitsChan,FitsDigits,int,DBL_DIG,this->fitsdigits) astMAKE_SET(FitsChan,FitsDigits,int,fitsdigits,value) astMAKE_TEST(FitsChan,FitsDigits,( this->fitsdigits != DBL_DIG )) /* CardComm */ /* ======== */ /* *att++ * Name: * CardComm * Purpose: * The comment for the current card in a FitsChan. * Type: * Public attribute. * Synopsis: * String, read-only. * Description: * This attribute gives the comment for the current card of the * FitsChan. A zero-length string is returned if the card has no comment. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* CardName */ /* ======== */ /* *att++ * Name: * CardName * Purpose: * The keyword name of the current card in a FitsChan. * Type: * Public attribute. * Synopsis: * String, read-only. * Description: * This attribute gives the name of the keyword for the * current card of the FitsChan. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* CardType */ /* ======== */ /* *att++ * Name: * CardType * Purpose: * The data type of the current card in a FitsChan. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute gives the data type of the keyword value for the * current card of the FitsChan. It will be one of the following * integer constants: AST__NOTYPE, AST__COMMENT, AST__INT, AST__FLOAT, * AST__STRING, AST__COMPLEXF, AST__COMPLEXI, AST__LOGICAL, * AST__CONTINUE, AST__UNDEF. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Ncard */ /* ===== */ /* *att++ * Name: * Ncard * Purpose: * Number of FITS header cards in a FitsChan. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute gives the total number of FITS header cards * stored in a FitsChan. It is updated as cards are added or * deleted. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Nkey */ /* ==== */ /* *att++ * Name: * Nkey * Purpose: * Number of unique FITS keywords in a FitsChan. * Type: * Public attribute. * Synopsis: * Integer, read-only. * Description: * This attribute gives the total number of unique FITS keywords * stored in a FitsChan. It is updated as cards are added or * deleted. If no keyword occurrs more than once in the FitsChan, the * Ncard and Nkey attributes will be equal. If any keyword occurrs * more than once, the Nkey attribute value will be smaller than * the Ncard attribute value. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Warnings. */ /* ======== */ /* *att++ * Name: * Warnings * Purpose: * Controls the issuing of warnings about various conditions. * Type: * Public attribute. * Synopsis: * String * Description: * This attribute controls the issuing of warnings about selected * conditions when an Object or keyword is read from or written to a * FitsChan. The value supplied for the Warnings attribute should * consist of a space separated list of condition names (see the * AllWarnings attribute for a list of the currently defined names). * Each name indicates a condition which should be reported. The default * value for Warnings is the string "Tnx Zpx BadCel BadMat BadPV BadCTYPE". * * The text of any warning will be stored within the FitsChan in the * form of one or more new header cards with keyword ASTWARN. If * required, applications can check the FitsChan for ASTWARN cards c (using astFindFits) after the call to astRead or astWrite has been f (using AST_FINDFITS) after the call to AST_READ or AST_WRITE has been * performed, and report the text of any such cards to the user. ASTWARN * cards will be propagated to any output header unless they are c deleted from the FitsChan using astDelFits. f deleted from the FitsChan using astDelFits. * Notes: * This attribute only controls the warnings that are to be stored as * a set of header cards in the FitsChan as described above. It has no * effect on the storage of warnings in the parent Channel structure. * All warnings are stored in the parent Channel structure, from where * they can be retrieved using the c astWarnings f AST_WARNINGS * function. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Clear the Warnings value by freeing the allocated memory and assigning a NULL pointer. */ astMAKE_CLEAR(FitsChan,Warnings,warnings,astFree( this->warnings )) /* If the Warnings value is not set, supply a default in the form of a pointer to the constant string "Tnx Zpx BadCel BadMat BadCTYPE". */ astMAKE_GET(FitsChan,Warnings,const char *,NULL,( this->warnings ? this->warnings : "Tnx Zpx BadPV BadCel BadMat BadCTYPE" )) /* Set a Warnings value by freeing any previously allocated memory, allocating new memory, storing the string and saving the pointer to the copy. First check that the list does not contain any unknown conditions. If it does, an error is reported by GoodWarns and the current attribute value is retained. */ astMAKE_SET(FitsChan,Warnings,const char *,warnings,( GoodWarns( value, status ) ? astStore( this->warnings, value, strlen( value ) + (size_t) 1 ) : this->warnings)) /* The Warnings value is set if the pointer to it is not NULL. */ astMAKE_TEST(FitsChan,Warnings,( this->warnings != NULL )) /* AllWarnings. */ /* ============ */ /* *att++ * Name: * AllWarnings * Purpose: * A list of all currently available condition names. * Type: * Public attribute. * Synopsis: * String, read-only * Description: * This read-only attribute is a space separated list of all the conditions * names recognized by the Warnings attribute. The names are listed * below. * Conditions: * The following conditions are currently recognised (all are * case-insensitive): * * - "BadCel": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan if an unknown celestial co-ordinate * system is specified by the CTYPE keywords. * * - "BadCTYPE": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan if an illegal algorithm code is specified * by a CTYPE keyword, and the illegal code can be converted to an * equivalent legal code. * * - "BadLat": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan if the latitude of the reference point * has an absolute value greater than 90 degrees. The actual absolute * value used is set to exactly 90 degrees in these cases. * * - "BadMat": This condition arises if the matrix describing the * transformation from pixel offsets to intermediate world coordinates * cannot be inverted. This matrix describes the scaling, rotation, shear, * etc., applied to the pixel axes, and is specified by keywords such as * PCi_j, CDi_j, CROTA, etc. For example, the matrix will not be invertable * if any rows or columns consist entirely of zeros. The FITS-WCS Paper I * "Representation of World Coordinates in FITS" by Greisen & Calabretta * requires that this matrix be invertable. Many operations (such as * grid plotting) will not be possible if the matrix cannot be inverted. * * - "BadPV": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan. It is issued if a PVi_m header is found * that refers to a projection parameter that is not used by the * projection type specified by CTYPE, or the PV values are otherwise * inappropriate for the projection type. * * - "BadVal": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan if it is not possible to convert the * value of a FITS keywords to the expected type. For instance, this * can occur if the FITS header contains a string value for a keyword * which should have a floating point value, or if the keyword has no * value at all (i.e. is a comment card). * * - "Distortion": This condition arises when reading a FrameSet from a * non-Native encoded FitsChan if any of the CTYPE keywords specify an * unsupported distortion code using the "4-3-3" format specified in * FITS-WCS paper IV. Such distortion codes are ignored. * * - "NoCTYPE": This condition arises if a default CTYPE value is used c within astRead, due to no value being present in the supplied FitsChan. f within AST_READ, due to no value being present in the supplied FitsChan. * This condition is only tested for when using non-Native encodings. * * - "NoEquinox": This condition arises if a default equinox value is used c within astRead, due to no value being present in the supplied FitsChan. f within AST_READ, due to no value being present in the supplied FitsChan. * This condition is only tested for when using non-Native encodings. * * - "NoRadesys": This condition arises if a default reference frame is c used for an equatorial co-ordinate system within astRead, due to no f used for an equatorial co-ordinate system within AST_READ, due to no * value being present in the supplied FitsChan. This condition is only * tested for when using non-Native encodings. * * - "NoLonpole": This condition arises if a default value is used for c the LONPOLE keyword within astRead, due to no value being present f the LONPOLE keyword within AST_READ, due to no value being present * in the supplied FitsChan. This condition is only tested for when * using non-Native encodings. * * - "NoLatpole": This condition arises if a default value is used for c the LATPOLE keyword within astRead, due to no value being present f the LATPOLE keyword within AST_READ, due to no value being present * in the supplied FitsChan. This condition is only tested for when * using non-Native encodings. * * - "NoMjd-obs": This condition arises if a default value is used for c the date of observation within astRead, due to no value being present f the date of observation within AST_READ, due to no value being present * in the supplied FitsChan. This condition is only tested for when using * non-Native encodings. * * - "Tnx": This condition arises if a FrameSet is read from a FITS * header containing an IRAF "TNX" projection which includes terms * not supproted by AST. Such terms are ignored and so the resulting * FrameSet may be inaccurate. * * - "Zpx": This condition arises if a FrameSet is read from a FITS * header containing an IRAF "ZPX" projection which includes "lngcor" * or "latcor" correction terms. These terms are not supported by AST * and are ignored. The resulting FrameSet may therefore be inaccurate. * Applicability: * FitsChan * All FitsChans have this attribute. *att-- */ /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for FitsChan objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status ) * Description: * This function implements the copy constructor for FitsChan objects. * Parameters: * objin * Pointer to the FitsChan to be copied. * objout * Pointer to the FitsChan being constructed. * status * Pointer to the inherited status variable. * Notes: * - The source and sink functions are not propagated (i.e. the * pointers are set NULL in the output FitsChan). * - This constructor makes a deep copy, including a copy of the * keyword values. */ /* Local Variables: */ astDECLARE_GLOBALS /* Declare the thread specific global data */ const char *class; /* Pointer to object class */ AstFitsChan *in; /* Pointer to input FitsChan */ AstFitsChan *out; /* Pointer to output FitsChan */ int *flags; int icard; int old_ignore_used; /* Original value of external variable ignore_used */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(objin); /* Obtain pointers to the input and output FitsChans. */ in = (AstFitsChan *) objin; out = (AstFitsChan *) objout; /* Nullify all pointers in the output FitsChan so that the input data will not be deleted in the event of an error occurring. */ out->card = NULL; out->head = NULL; out->keyseq = NULL; out->keywords = NULL; out->source = NULL; out->saved_source = NULL; out->source_wrap = NULL; out->sink = NULL; out->sink_wrap = NULL; out->warnings = NULL; out->tabsource = NULL; out->tabsource_wrap = NULL; /* Store the object class. */ class = astGetClass( in ); /* Ensure all cards are copied, including those already read by astRead. */ old_ignore_used = ignore_used; ignore_used = 0; /* Save the current card index in the input FitsChan. */ icard = astGetCard( in ); /* Rewind the input FitsChan. */ astClearCard( in ); /* Copy all the FitsCard structures from input to output. */ while( !astFitsEof( in ) && astOK ){ /* Get a pointer to the flags mask for this card. */ flags = CardFlags( in, status ); /* Store a new card in the output, holding the same information as the input card. */ NewCard( out, CardName( in, status ), CardType( in, status ), CardData( in, NULL, status ), CardComm( in, status ), (flags?(*flags):0), status ); /* Move on to the next input card. */ MoveCard( in, 1, "astCopy", class, status ); } /* Set the current card in both input and output to the current input card on entry. */ astSetCard( in, icard ); astSetCard( out, icard ); /* Copy the list of keyword sequence numbers used. */ if( in->keyseq ) out->keyseq = astCopy( in->keyseq ); /* Copy the Warnings attribute value */ if( in->warnings ) out->warnings = astStore( NULL, in->warnings, strlen( in->warnings ) + 1 ); /* Copy any tables currently in the FitsChan structure. */ if( in->tables ) out->tables = astCopy( in->tables ); /* Reinstate the original setting of the external ignore_used variable. */ ignore_used = old_ignore_used; /* If an error occurred, delete the contents of the output Object. */ if( !astOK ) Delete( objout, status ); } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for FitsChan objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status ) * Description: * This function implements the destructor for FitsChan objects. * Parameters: * obj * Pointer to the FitsChan to be deleted. * status * Pointer to the inherited status variable. * Notes: * This function attempts to execute even if the global error status is * set. */ /* Local Variables: */ AstFitsChan *this; /* Pointer to FitsChan */ /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) obj; /* Write out the contents of the FitsChan using the sink function provided when it was created. */ WriteToSink( this, status ); /* Remove all cards from the FitsChan. */ EmptyFits( this, status ); } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for FitsChan objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status ) * Description: * This function implements the Dump function which writes out data * for the FitsChan class to an output Channel. * Parameters: * this * Pointer to the FitsChan whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ AstFitsChan *this; /* Pointer to the FitsChan structure */ astDECLARE_GLOBALS /* Declare the thread specific global data */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ const char *class; /* Object class */ const char *sval; /* Pointer to string value */ int cardtype; /* Keyword data type */ int flags; /* Keyword flags */ int icard; /* Index of current card */ int ival; /* Integer value */ int ncard; /* No. of cards dumped so far */ int old_ignore_used; /* Original value of external variable ignore_used */ int set; /* Attribute value set? */ void *data; /* Pointer to keyword data value */ /* Check the global error status. */ if ( !astOK ) return; /* Get a pointer to the structure holding thread-specific global data. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the FitsChan structure. */ this = (AstFitsChan *) this_object; /* Store the object class. */ class = astGetClass( this ); /* Save the index of ht ecurrent card. */ icard = astGetCard( this ); /* Write out values representing the instance variables for the FitsChan class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* Card. */ /* ----- */ astWriteInt( channel, "Card", 1, 1, icard, "Index of current card" ); /* Encoding. */ /* --------- */ set = TestEncoding( this, status ); ival = set ? GetEncoding( this, status ) : astGetEncoding( this ); if( ival > UNKNOWN_ENCODING && ival <= MAX_ENCODING ) { astWriteString( channel, "Encod", set, 1, xencod[ival], "Encoding system" ); } else { astWriteString( channel, "Encod", set, 1, UNKNOWN_STRING, "Encoding system" ); } /* FitsDigits. */ /* ----------- */ set = TestFitsDigits( this, status ); ival = set ? GetFitsDigits( this, status ) : astGetFitsDigits( this ); astWriteInt( channel, "FitsDg", set, 1, ival, "No. of digits for floating point values" ); /* DefB1950 */ /* -------- */ set = TestDefB1950( this, status ); ival = set ? GetDefB1950( this, status ) : astGetDefB1950( this ); astWriteInt( channel, "DfB1950", set, 1, ival, (ival ? "Default to FK4 B1950": "Default to ICRS") ); /* TabOK */ /* ----- */ set = TestTabOK( this, status ); ival = set ? GetTabOK( this, status ) : astGetTabOK( this ); astWriteInt( channel, "TabOK", set, 1, ival, ( ival > 0 ? "EXTVER value for -TAB headers": "Do not support -TAB CTYPE codes") ); /* CDMatrix */ /* -------- */ set = TestCDMatrix( this, status ); ival = set ? GetCDMatrix( this, status ) : astGetCDMatrix( this ); astWriteInt( channel, "CdMat", set, 1, ival, (ival ? "Use CD Matrix":"Use PC matrix") ); /* CarLin */ /* ------ */ set = TestCarLin( this, status ); ival = set ? GetCarLin( this, status ) : astGetCarLin( this ); astWriteInt( channel, "CarLin", set, 1, ival, (ival ? "Use simple linear CAR projections": "Use full FITS-WCS CAR projections") ); /* PolyTan */ /* ------- */ set = TestPolyTan( this, status ); ival = set ? GetPolyTan( this, status ) : astGetPolyTan( this ); astWriteInt( channel, "PolyTan", set, 0, ival, (ival ? "Use distorted TAN convention": "Use standard TAN convention") ); /* Iwc */ /* --- */ set = TestIwc( this, status ); ival = set ? GetIwc( this, status ) : astGetIwc( this ); astWriteInt( channel, "Iwc", set, 1, ival, (ival ? "Include an IWC Frame": "Do not include an IWC Frame") ); /* Clean */ /* ----- */ set = TestClean( this, status ); ival = set ? GetClean( this, status ) : astGetClean( this ); astWriteInt( channel, "Clean", set, 0, ival, "Always remove used cards?" ); /* Warnings. */ /* --------- */ set = TestWarnings( this, status ); sval = set ? GetWarnings( this, status ) : astGetWarnings( this ); astWriteString( channel, "Warn", set, 1, sval, "Warnings to be reported" ); /* Now do instance variables which are not attributes. */ /* =================================================== */ /* Ensure all cards are copied, including those already read by astRead. */ old_ignore_used = ignore_used; ignore_used = 0; /* Rewind the FitsChan. */ astClearCard( this ); /* Dump each card. */ ncard = 1; while( !astFitsEof( this ) && astOK ){ /* Write out the keyword name. */ if( CardName( this, status ) ){ (void) sprintf( buff, "Nm%d", ncard ); astWriteString( channel, buff, 1, 1, CardName( this, status ), "FITS keyword name" ); } /* Write out the keyword type. */ cardtype = CardType( this, status ); (void) sprintf( buff, "Ty%d", ncard ); astWriteString( channel, buff, 1, 1, type_names[ cardtype ], "FITS keyword data type" ); /* Write out the flag values if any are non-zero. */ flags = *CardFlags( this, status ); if( flags ){ (void) sprintf( buff, "Fl%d", ncard ); astWriteInt( channel, buff, 1, 1, flags, "FITS keyword flags" ); } /* Write out the data value, if defined, using the appropriate data type. */ data = CardData( this, NULL, status ); if( data && cardtype != AST__UNDEF ){ if( cardtype == AST__FLOAT ){ (void) sprintf( buff, "Dt%d", ncard ); astWriteDouble( channel, buff, 1, 1, *( (double *) data ), "FITS keyword value" ); } else if( cardtype == AST__STRING || cardtype == AST__CONTINUE ){ (void) sprintf( buff, "Dt%d", ncard ); astWriteString( channel, buff, 1, 1, (char *) data, "FITS keyword value" ); } else if( cardtype == AST__INT ){ (void) sprintf( buff, "Dt%d", ncard ); astWriteInt( channel, buff, 1, 1, *( (int *) data ), "FITS keyword value" ); } else if( cardtype == AST__LOGICAL ){ (void) sprintf( buff, "Dt%d", ncard ); astWriteInt( channel, buff, 1, 1, *( (int *) data ), "FITS keyword value" ); } else if( cardtype == AST__COMPLEXF ){ (void) sprintf( buff, "Dr%d", ncard ); astWriteDouble( channel, buff, 1, 1, *( (double *) data ), "FITS keyword real value" ); (void) sprintf( buff, "Di%d", ncard ); astWriteDouble( channel, buff, 1, 1, *( ( (double *) data ) + 1 ), "FITS keyword imaginary value" ); } else if( cardtype == AST__COMPLEXI ){ (void) sprintf( buff, "Dr%d", ncard ); astWriteInt( channel, buff, 1, 1, *( (int *) data ), "FITS keyword real value" ); (void) sprintf( buff, "Di%d", ncard ); astWriteInt( channel, buff, 1, 1, *( ( (int *) data ) + 1 ), "FITS keyword imaginary value" ); } } /* Write out the keyword comment. */ if( CardComm( this, status ) ){ (void) sprintf( buff, "Cm%d", ncard ); astWriteString( channel, buff, 1, 1, CardComm( this, status ), "FITS keyword comment" ); } /* Move on to the next card. */ ncard++; MoveCard( this, 1, "astDump", class, status ); } /* Dump any FitTables. */ if( this->tables ) { astWriteObject( channel, "Tables", 1, 1, this->tables, "A KeyMap holding associated binary tables" ); } /* Reinstate the original setting of the external ignore_used variable. */ ignore_used = old_ignore_used; /* Reinstate the original current card. */ astSetCard( this, icard ); #undef KEY_LEN } /* Standard class functions. */ /* ========================= */ /* Implement the astIsAFitsChan and astCheckFitsChan functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(FitsChan,Channel) astMAKE_CHECK(FitsChan) AstFitsChan *astFitsChan_( const char *(* source)( void ), void (* sink)( const char * ), const char *options, int *status, ...) { /* *++ * Name: c astFitsChan f AST_FITSCHAN * Purpose: * Create a FitsChan. * Type: * Public function. * Synopsis: c #include "fitschan.h" c AstFitsChan *astFitsChan( const char *(* source)( void ), c void (* sink)( const char * ), c const char *options, ... ) f RESULT = AST_FITSCHAN( SOURCE, SINK, OPTIONS, STATUS ) * Class Membership: * FitsChan constructor. * Description: * This function creates a new FitsChan and optionally initialises * its attributes. * * A FitsChan is a specialised form of Channel which supports I/O * operations involving the use of FITS (Flexible Image Transport * System) header cards. Writing an Object to a FitsChan (using c astWrite) will, if the Object is suitable, generate a f AST_WRITE) will, if the Object is suitable, generate a * description of that Object composed of FITS header cards, and * reading from a FitsChan will create a new Object from its FITS * header card description. * * While a FitsChan is active, it represents a buffer which may * contain zero or more 80-character "header cards" conforming to * FITS conventions. Any sequence of FITS-conforming header cards * may be stored, apart from the "END" card whose existence is * merely implied. The cards may be accessed in any order by using * the FitsChan's integer Card attribute, which identifies a "current" * card, to which subsequent operations apply. Searches c based on keyword may be performed (using astFindFits), new c cards may be inserted (astPutFits, astPutCards, astSetFits) and c existing ones may be deleted (astDelFits) or changed (astSetFits). f based on keyword may be performed (using AST_FINDFITS), new f cards may be inserted (AST_PUTFITS, AST_PUTCARDS, AST_SETFITS) and f existing ones may be deleted (AST_DELFITS) or changed (AST_SETFITS). * * When you create a FitsChan, you have the option of specifying * "source" and "sink" functions which connect it to external data * stores by reading and writing FITS header cards. If you provide * a source function, it is used to fill the FitsChan with header cards * when it is accessed for the first time. If you do not provide a * source function, the FitsChan remains empty until you explicitly enter c data into it (e.g. using astPutFits, astPutCards, astWrite f data into it (e.g. using AST_PUTFITS, AST_PUTCARDS, AST_WRITE * or by using the SourceFile attribute to specifying a text file from * which headers should be read). When the FitsChan is deleted, any * remaining header cards in the FitsChan can be saved in either of * two ways: 1) by specifying a value for the SinkFile attribute (the * name of a text file to which header cards should be written), or 2) * by providing a sink function (used to to deliver header cards to an * external data store). If you do not provide a sink function or a * value for SinkFile, any header cards remaining when the FitsChan * is deleted will be lost, so you should arrange to extract them * first if necessary c (e.g. using astFindFits or astRead). f (e.g. using AST_FINDFITS or AST_READ). * * Coordinate system information may be described using FITS header * cards using several different conventions, termed * "encodings". When an AST Object is written to (or read from) a * FitsChan, the value of the FitsChan's Encoding attribute * determines how the Object is converted to (or from) a * description involving FITS header cards. In general, different * encodings will result in different sets of header cards to * describe the same Object. Examples of encodings include the DSS * encoding (based on conventions used by the STScI Digitised Sky * Survey data), the FITS-WCS encoding (based on a proposed FITS * standard) and the NATIVE encoding (a near loss-less way of * storing AST Objects in FITS headers). * * The available encodings differ in the range of Objects they can * represent, in the number of Object descriptions that can coexist * in the same FitsChan, and in their accessibility to other * (external) astronomy applications (see the Encoding attribute * for details). Encodings are not necessarily mutually exclusive * and it may sometimes be possible to describe the same Object in * several ways within a particular set of FITS header cards by * using several different encodings. * c The detailed behaviour of astRead and astWrite, when used with f The detailed behaviour of AST_READ and AST_WRITE, when used with * a FitsChan, depends on the encoding in use. In general, however, c all use of astRead is destructive, so that FITS header cards f all use of AST_READ is destructive, so that FITS header cards * are consumed in the process of reading an Object, and are * removed from the FitsChan (this deletion can be prevented for * specific cards by calling the c astRetainFits function). f AST_RETAINFITS routine). * * If the encoding in use allows only a single Object description * to be stored in a FitsChan (e.g. the DSS, FITS-WCS and FITS-IRAF c encodings), then write operations using astWrite will f encodings), then write operations using AST_WRITE will * over-write any existing Object description using that * encoding. Otherwise (e.g. the NATIVE encoding), multiple Object * descriptions are written sequentially and may later be read * back in the same sequence. * Parameters: c source f SOURCE = FUNCTION (Given) c Pointer to a source function which takes no arguments and c returns a pointer to a null-terminated string. This function c will be used by the FitsChan to obtain input FITS header c cards. On each invocation, it should read the next input card c from some external source (such as a FITS file), and return a c pointer to the (null-terminated) contents of the card. It c should return a NULL pointer when there are no more cards to c be read. c c If "source" is NULL, the FitsChan will remain empty until c cards are explicitly stored in it (e.g. using astPutCards, c astPutFits or via the SourceFile attribute). f A source routine, which is a function taking two arguments: a f character argument of length 80 to contain a FITS card, and an f integer error status argument. It should return an integer value. f This function will be used by the FitsChan to obtain input f FITS header cards. On each invocation, it should read the f next input card from some external source (such as a FITS f file), and return the contents of the card via its character f argument. It should return a function result of one unless f there are no more cards to be read, in which case it should f return zero. If an error occurs, it should set its error f status argument to an error value before returning. f f If the null routine AST_NULL is supplied as the SOURCE value, f the FitsChan will remain empty until cards are explicitly f stored in it (e.g. using AST_PUTCARDS, AST_PUTFITS or via the f SourceFile attribute). c sink f SINK = SUBROUTINE (Given) c Pointer to a sink function that takes a pointer to a c null-terminated string as an argument and returns void. If c no value has been set for the SinkFile attribute, this c function will be used by the FitsChan to deliver any FITS c header cards it contains when it is finally deleted. On c each invocation, it should deliver the contents of the character c string passed to it as a FITS header card to some external c data store (such as a FITS file). f A sink routine, which is a subroutine which takes two f arguments: a character argument of length 80 to contain a f FITS card, and an integer error status argument. If no f value has been set for the SinkFile attribute, this routine f will be used by the FitsChan to deliver any FITS header cards f it contains when it is finally deleted. On each invocation, f it should deliver the contents of the character string passed f to it as a FITS header card to some external data store (such f as a FITS file). If an error occurs, it should set its error f status argument to an error value before returning. * c If "sink" is NULL, f If the null routine AST_NULL is supplied as the SINK value, * and no value has been set for the SinkFile attribute, the * contents of the FitsChan will be lost when it is deleted. c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new FitsChan. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new FitsChan. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). * * Note, the FITSCHAN_OPTIONS environment variable may be used * to specify default options for all newly created FitsChans. f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astFitsChan() f AST_FITSCHAN = INTEGER * A pointer to the new FitsChan. * Notes: f - The names of the routines supplied for the SOURCE and SINK f arguments should appear in EXTERNAL statements in the Fortran f routine which invokes AST_FITSCHAN. However, this is not generally f necessary for the null routine AST_NULL (so long as the AST_PAR f include file has been used). c - No FITS "END" card will be written via the sink function. You f - No FITS "END" card will be written via the sink routine. You * should add this card yourself after the FitsChan has been * deleted. * - A null Object pointer (AST__NULL) will be returned if this * function is invoked with the AST error status set, or if it * should fail for any reason. f - Note that the null routine AST_NULL (one underscore) is f different to AST__NULL (two underscores), which is the null Object f pointer. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFitsChan *new; /* Pointer to new FitsChan */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the FitsChan, allocating memory and initialising the virtual function table as well if necessary. This interface is for use by other C functions within AST, and uses the standard "wrapper" functions included in this class. */ new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init, &class_vtab, "FitsChan", source, SourceWrap, sink, SinkWrap ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Apply any default options specified by "_OPTIONS" environment variable. */ astEnvSet( new ); /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new FitsChan's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new FitsChan. */ return new; } AstFitsChan *astFitsChanId_( const char *(* source)( void ), void (* sink)( const char * ), const char *options, ... ) { /* * Name: * astFitsChanId_ * Purpose: * Create a FitsChan. * Type: * Private function. * Synopsis: * #include "fitschan.h" * AstFitsChan *astFitsChanId_( const char *(* source)( void ), * void (* sink)( const char * ), * const char *options, ... ) * Class Membership: * FitsChan constructor. * Description: * This function implements the external (public) C interface to the * astFitsChan constructor function. Another function (astFitsChanForId) * should be called to create a FitsChan for use within other languages. * Both functions return an ID value (instead of a true C pointer) to * external users, and must be provided because astFitsChan_ has a variable * argument list which cannot be encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astFitsChan_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astFitsChan_. * Returned Value: * The ID value associated with the new FitsChan. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFitsChan *new; /* Pointer to new FitsChan */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the FitsChan, allocating memory and initialising the virtual function table as well if necessary. This interface is for use by external C functions and uses the standard "wrapper" functions included in this class. */ new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init, &class_vtab, "FitsChan", source, SourceWrap, sink, SinkWrap ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Apply any default options specified by "_OPTIONS" environment variable. */ astEnvSet( new ); /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new FitsChan's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new FitsChan. */ return astMakeId( new ); } AstFitsChan *astFitsChanForId_( const char *(* source)( void ), char *(* source_wrap)( const char *(*)( void ), int * ), void (* sink)( const char * ), void (* sink_wrap)( void (*)( const char * ), const char *, int * ), const char *options, ... ) { /* *+ * Name: * astFitsChanFor * Purpose: * Initialise a FitsChan from a foreign language interface. * Type: * Public function. * Synopsis: * #include "fitschan.h" * AstFitsChan *astFitsChanFor( const char *(* source)( void ), * char *(* source_wrap)( const char *(*) * ( void ), int * ), * void (* sink)( const char * ), * void (* sink_wrap)( void (*)( const char * ), * const char *, int * ), * const char *options, ... ) * Class Membership: * FitsChan constructor. * Description: * This function creates a new FitsChan from a foreign language * interface and optionally initialises its attributes. * * A FitsChan implements FITS input/output for the AST library. * Writing an Object to a FitsChan (using astWrite) will generate a * textual representation of that Object in terms of FITS header cards, * and reading from a FitsChan (using astRead) will create a new Object * from its FITS representation. * * Normally, when you use a FitsChan, you should provide "source" * and "sink" functions which connect it to an external data store * by reading and writing the resulting text. This function also * requires you to provide "wrapper" functions which will invoke * the source and sink functions. * Parameters: * source * Pointer to a "source" function which will be used to obtain * FITS header cards. Generally, this will be obtained by * casting a pointer to a source function which is compatible * with the "source_wrap" wrapper function (below). The pointer * should later be cast back to its original type by the * "source_wrap" function before the function is invoked. * * If "source" is NULL, the FitsChan will remain empty until * cards are added explicitly (e.g. using astPutCards or astPutFits). * source_wrap * Pointer to a function which can be used to invoke the * "source" function supplied (above). This wrapper function is * necessary in order to hide variations in the nature of the * source function, such as may arise when it is supplied by a * foreign (non-C) language interface. * * The single parameter of the "source_wrap" function is a * pointer to the "source" function, and it should cast this * function pointer (as necessary) and invoke the function with * appropriate arguments to obtain the next FITS header card. * The "source_wrap" function should then return a pointer * to a dynamically allocated, null terminated string containing * the text that was read. The string will be freed (using * astFree) when no longer required and the "source_wrap" * function need not concern itself with this. A NULL pointer * should be returned if there is no more input to read. * * If "source" is NULL, the FitsChan will remain empty until * cards are added explicitly (e.g. using astPutCards or astPutFits). * sink * Pointer to a "sink" function which will be used to deliver * FITS header cards. Generally, this will be obtained by * casting a pointer to a sink function which is compatible with * the "sink_wrap" wrapper function (below). The pointer should * later be cast back to its original type by the "sink_wrap" * function before the function is invoked. * * If "sink" is NULL, the contents of the FitsChan will not be * written out before being deleted. * sink_wrap * Pointer to a function which can be used to invoke the "sink" * function supplied (above). This wrapper function is necessary * in order to hide variations in the nature of the sink * function, such as may arise when it is supplied by a foreign * (non-C) language interface. * * The first parameter of the "sink_wrap" function is a pointer * to the "sink" function, and the second parameter is a pointer * to a const, null-terminated character string containing the * text to be written. The "sink_wrap" function should cast the * "sink" function pointer (as necessary) and invoke the * function with appropriate arguments to deliver the line of * output text. The "sink_wrap" function then returns void. * * If "sink_wrap" is NULL, the contents of the FitsChan will not be * written out before being deleted. * options * Pointer to a null-terminated string containing an optional * comma-separated list of attribute assignments to be used for * initialising the new FitsChan. The syntax used is identical to * that for the astSet function and may include "printf" format * specifiers identified by "%" symbols in the normal way. * ... * If the "options" string contains "%" format specifiers, then * an optional list of additional arguments may follow it in * order to supply values to be substituted for these * specifiers. The rules for supplying these are identical to * those for the astSet function (and for the C "printf" * function). * Returned Value: * astFitsChanFor() * A pointer to the new FitsChan. * Notes: * - A null Object pointer (AST__NULL) will be returned if this * function is invoked with the global error status set, or if it * should fail for any reason. * - This function is only available through the public interface * to the FitsChan class (not the protected interface) and is * intended solely for use in implementing foreign language * interfaces to this class. *- * Implememtation Notes: * - This function behaves exactly like astFitsChanId_, in that it * returns ID values and not true C pointers, but it has two * additional arguments. These are pointers to the "wrapper * functions" which are needed to accommodate foreign language * interfaces. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFitsChan *new; /* Pointer to new FitsChan */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Check the global status. */ if ( !astOK ) return NULL; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialise the FitsChan, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init, &class_vtab, "FitsChan", source, source_wrap, sink, sink_wrap ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Apply any default options specified by "_OPTIONS" environment variable. */ astEnvSet( new ); /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new FitsChan's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new FitsChan. */ return astMakeId( new ); } AstFitsChan *astInitFitsChan_( void *mem, size_t size, int init, AstFitsChanVtab *vtab, const char *name, const char *(* source)( void ), char *(* source_wrap)( const char *(*)( void ), int * ), void (* sink)( const char * ), void (* sink_wrap)( void (*)( const char * ), const char *, int * ), int *status ) { /* *+ * Name: * astInitFitsChan * Purpose: * Initialise a FitsChan. * Type: * Protected function. * Synopsis: * #include "fitschan.h" * AstFitsChan *astInitFitsChan_( void *mem, size_t size, int init, * AstFitsChanVtab *vtab, const char *name, * const char *(* source)( void ), * char *(* source_wrap)( const char *(*)( void ), int * ), * void (* sink)( const char * ), * void (* sink_wrap)( void (*)( const char * ), * const char *, int * ) ) * Class Membership: * FitsChan initialiser. * Description: * This function is provided for use by class implementations to * initialise a new FitsChan object. It allocates memory (if * necessary) to accommodate the FitsChan plus any additional data * associated with the derived class. It then initialises a * FitsChan structure at the start of this memory. If the "init" * flag is set, it also initialises the contents of a virtual * function table for a FitsChan at the start of the memory passed * via the "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the FitsChan is to be * initialised. This must be of sufficient size to accommodate * the FitsChan data (sizeof(FitsChan)) plus any data used by the * derived class. If a value of NULL is given, this function * will allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the FitsChan (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the FitsChan structure, so a valid value must be * supplied even if not required for allocating memory. * init * A boolean flag indicating if the FitsChan's virtual function * table is to be initialised. If this value is non-zero, the * virtual function table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be * associated with the new FitsChan. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * source * Pointer to a "source" function which will be used to obtain * FITS header cards. Generally, this will be obtained by * casting a pointer to a source function which is compatible * with the "source_wrap" wrapper function (below). The pointer * should later be cast back to its original type by the * "source_wrap" function before the function is invoked. * * If "source" is NULL, the FitsChan will remain empty until * cards are added explicitly (e.g. using astPutCards or astPutFits). * source_wrap * Pointer to a function which can be used to invoke the * "source" function supplied (above). This wrapper function is * necessary in order to hide variations in the nature of the * source function, such as may arise when it is supplied by a * foreign (non-C) language interface. * * The single parameter of the "source_wrap" function is a * pointer to the "source" function, and it should cast this * function pointer (as necessary) and invoke the function with * appropriate arguments to obtain the next FITS header card. * The "source_wrap" function should then return a pointer * to a dynamically allocated, null terminated string containing * the text that was read. The string will be freed (using * astFree) when no longer required and the "source_wrap" * function need not concern itself with this. A NULL pointer * should be returned if there is no more input to read. * * If "source" is NULL, the FitsChan will remain empty until * cards are added explicitly (e.g. using astPutCards or astPutFits). * sink * Pointer to a "sink" function which will be used to deliver * FITS header cards. Generally, this will be obtained by * casting a pointer to a sink function which is compatible with * the "sink_wrap" wrapper function (below). The pointer should * later be cast back to its original type by the "sink_wrap" * function before the function is invoked. * * If "sink" is NULL, the contents of the FitsChan will not be * written out before being deleted. * sink_wrap * Pointer to a function which can be used to invoke the "sink" * function supplied (above). This wrapper function is necessary * in order to hide variations in the nature of the sink * function, such as may arise when it is supplied by a foreign * (non-C) language interface. * * The first parameter of the "sink_wrap" function is a pointer * to the "sink" function, and the second parameter is a pointer * to a const, null-terminated character string containing the * text to be written. The "sink_wrap" function should cast the * "sink" function pointer (as necessary) and invoke the * function with appropriate arguments to deliver the line of * output text. The "sink_wrap" function then returns void. * * If "sink_wrap" is NULL, the contents of the FitsChan will not be * written out before being deleted. * Returned Value: * A pointer to the new FitsChan. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ /* Local Variables: */ AstFitsChan *new; /* Pointer to new FitsChan */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitFitsChanVtab( vtab, name ); /* Initialise a Channel structure (the parent class) as the first component within the FitsChan structure, allocating memory if necessary. I am not sure why FitsChan has its own source_wrap and sink_wrap items, rather than just using those inherited from Channel. It may be possible to do away with the fitschan wrappers and just use the channel wrapper, but I have not yet tried this. Old mail from RFWS suggests that it may be because the F77 FitsChan source and sink interfaces handle fixed length strings (80 characters), whereas Channel sournce and sink handle variable length strings. This needs investigating. */ new = (AstFitsChan *) astInitChannel( mem, size, 0, (AstChannelVtab *) vtab, name, NULL, NULL, NULL, NULL ); if ( astOK ) { /* Initialise the FitsChan data. */ /* ---------------------------- */ new->head = NULL; new->card = NULL; new->keyseq = NULL; new->keywords = NULL; new->defb1950 = -1; new->tabok = -INT_MAX; new->cdmatrix = -1; new->carlin = -1; new->polytan = -INT_MAX; new->iwc = -1; new->clean = -1; new->fitsdigits = DBL_DIG; new->encoding = UNKNOWN_ENCODING; new->warnings = NULL; new->tables = NULL; /* Save the pointers to the source and sink functions and the wrapper functions that invoke them. */ new->source = source; new->saved_source = NULL; new->source_wrap = source_wrap; new->sink = sink; new->sink_wrap = sink_wrap; new->tabsource = NULL; new->tabsource_wrap = NULL; /* Rewind the FitsChan so that the next read operation will return the first card. */ new->card = new->head; /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new object. */ return new; } AstFitsChan *astLoadFitsChan_( void *mem, size_t size, AstFitsChanVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadFitsChan * Purpose: * Load a FitsChan. * Type: * Protected function. * Synopsis: * #include "fitschan.h" * AstFitsChan *astLoadFitsChan( void *mem, size_t size, * AstFitsChanVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * FitsChan loader. * Description: * This function is provided to load a new FitsChan using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * FitsChan structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a FitsChan at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the FitsChan is to be * loaded. This must be of sufficient size to accommodate the * FitsChan data (sizeof(FitsChan)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the FitsChan (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the FitsChan structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstFitsChan) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new FitsChan. If this is NULL, a pointer * to the (static) virtual function table for the FitsChan class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "FitsChan" is used instead. * Returned Value: * A pointer to the new FitsChan. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstFitsChan *new; /* Pointer to the new FitsChan */ char *comment; /* Pointer to keyword comment */ char *keynm; /* Keyword name */ char *text; /* Textual version of integer value */ char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */ double dval[2]; /* Double precision data values */ int flags; /* Keyword flags */ int free_data; /* Should data memory be freed? */ int ival[2]; /* Integer data values */ int ncard; /* No. of FitsCards read so far */ int type; /* Keyword type */ void *data; /* Pointer to keyword data value */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this FitsChan. In this case the FitsChan belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstFitsChan ); vtab = &class_vtab; name = "FitsChan"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitFitsChanVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built FitsChan. */ new = astLoadChannel( mem, size, (AstChannelVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "FitsChan" ); /* Initialise the KeyMap holding the keywords in the FitsChan. */ new->keywords = NULL; /* Initialise the list of keyword sequence numbers. */ new->keyseq = NULL; /* Set the pointers to the source and sink functions, and their wrapper functions, to NULL (we cannot restore these since they refer to process-specific addresses). */ new->source = NULL; new->saved_source = NULL; new->source_wrap = NULL; new->sink = NULL; new->sink_wrap = NULL; new->tabsource = NULL; new->tabsource_wrap = NULL; /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* Encoding. */ /* --------- */ text = astReadString( channel, "encod", UNKNOWN_STRING ); if( text && strcmp( text, UNKNOWN_STRING ) ) { new->encoding = FindString( MAX_ENCODING + 1, xencod, text, "the FitsChan component 'Encod'", "astRead", astGetClass( channel ), status ); } else { new->encoding = UNKNOWN_ENCODING; } if ( TestEncoding( new, status ) ) SetEncoding( new, new->encoding, status ); text = astFree( text ); /* FitsDigits. */ /* ----------- */ new->fitsdigits = astReadInt( channel, "fitsdg", DBL_DIG ); if ( TestFitsDigits( new, status ) ) SetFitsDigits( new, new->fitsdigits, status ); /* DefB1950 */ /* -------- */ new->defb1950 = astReadInt( channel, "dfb1950", -1 ); if ( TestDefB1950( new, status ) ) SetDefB1950( new, new->defb1950, status ); /* TabOK */ /* ----- */ new->tabok = astReadInt( channel, "tabok", -INT_MAX ); if ( TestTabOK( new, status ) ) SetTabOK( new, new->tabok, status ); /* CDMatrix */ /* -------- */ new->cdmatrix = astReadInt( channel, "cdmat", -1 ); if ( TestCDMatrix( new, status ) ) SetCDMatrix( new, new->cdmatrix, status ); /* CarLin */ /* ------ */ new->carlin = astReadInt( channel, "carlin", -1 ); if ( TestCarLin( new, status ) ) SetCarLin( new, new->carlin, status ); /* PolyTan */ /* ------- */ new->polytan = astReadInt( channel, "polytan", -1 ); if ( TestPolyTan( new, status ) ) SetPolyTan( new, new->polytan, status ); /* Iwc */ /* --- */ new->iwc = astReadInt( channel, "iwc", -1 ); if ( TestIwc( new, status ) ) SetIwc( new, new->iwc, status ); /* Clean */ /* ----- */ new->clean = astReadInt( channel, "clean", -1 ); if ( TestClean( new, status ) ) SetClean( new, new->clean, status ); /* Warnings. */ /* --------- */ new->warnings = astReadString( channel, "warn", NULL ); /* Card. */ /* ----- */ /* Initialise the index of the card to be read next. */ ncard = 1; new->card = NULL; new->head = NULL; /* Load each card. */ type = AST__NOTYPE + 1; while( type != AST__NOTYPE && astOK ){ /* Get the keyword type. */ (void) sprintf( buff, "ty%d", ncard ); text = astReadString( channel, buff, " " ); if( strcmp( text, " " ) ) { type = FindString( 9, type_names, text, "a FitsChan keyword data type", "astRead", astGetClass( channel ), status ); } else { type = AST__NOTYPE; } text = astFree( text ); /* Only proceed if the keyword type was found. */ if( type != AST__NOTYPE ){ /* Get the keyword name. Use a default blank name. */ (void) sprintf( buff, "nm%d", ncard ); keynm = astReadString( channel, buff, " " ); /* Get the data value, using the appropriate data type, unless the keyword is a comment keyword or is undefined. */ free_data = 0; if( type == AST__FLOAT ){ (void) sprintf( buff, "dt%d", ncard ); dval[ 0 ] = astReadDouble( channel, buff, AST__BAD ); data = (void *) dval; } else if( type == AST__STRING || type == AST__CONTINUE ){ (void) sprintf( buff, "dt%d", ncard ); data = (void *) astReadString( channel, buff, "" ); free_data = 1; } else if( type == AST__INT ){ (void) sprintf( buff, "dt%d", ncard ); ival[ 0 ] = astReadInt( channel, buff, 0 ); data = (void *) ival; } else if( type == AST__LOGICAL ){ (void) sprintf( buff, "dt%d", ncard ); ival[ 0 ] = astReadInt( channel, buff, 0 ); data = (void *) ival; } else if( type == AST__COMPLEXF ){ (void) sprintf( buff, "dr%d", ncard ); dval[ 0 ] = astReadDouble( channel, buff, AST__BAD ); (void) sprintf( buff, "di%d", ncard ); dval[ 1 ] = astReadDouble( channel, buff, AST__BAD ); data = (void *) dval; } else if( type == AST__COMPLEXI ){ (void) sprintf( buff, "dr%d", ncard ); ival[ 0 ] = astReadInt( channel, buff, 0 ); (void) sprintf( buff, "di%d", ncard ); ival[ 1 ] = astReadInt( channel, buff, 0 ); data = (void *) ival; } else { data = NULL; } /* Get the keyword flags (only written by versions of AST later than V1.4). These are packed into an int. */ (void) sprintf( buff, "fl%d", ncard ); flags = astReadInt( channel, buff, 0 ); /* If the flags were not found, use the keyword deletion flag written by AST V1.4 and earlier. */ if( !flags ) { (void) sprintf( buff, "dl%d", ncard ); flags = astReadInt( channel, buff, 0 ); } /* Get the keyword comment. */ (void) sprintf( buff, "cm%d", ncard ); comment = astReadString( channel, buff, NULL ); /* Append a new card to the output FitsChan. */ NewCard( new, keynm, type, data, comment, flags, status ); /* Free the character strings, and data (if required). */ comment = (char *) astFree( (void *) comment ); keynm = (char *) astFree( (void *) keynm ); if( free_data ) data = astFree( data ); } /* Move on to the next card. */ ncard++; } /* Set up the current card index. */ astSetCard( new, astReadInt( channel, "card", 0 ) ); /* Load any FitTables. */ new->tables = astReadObject( channel, "tables", NULL ); } /* If an error occurred, clean up by deleting the new FitsChan. */ if ( !astOK ) new = astDelete( new ); /* Return the new FitsChan pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ void astWriteFits_( AstFitsChan *this, int *status ){ if( !this ) return; (**astMEMBER(this,FitsChan,WriteFits))(this, status ); } void astReadFits_( AstFitsChan *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,ReadFits))(this, status ); } void astEmptyFits_( AstFitsChan *this, int *status ){ if( !this ) return; (**astMEMBER(this,FitsChan,EmptyFits))(this, status ); } void astShowFits_( AstFitsChan *this, int *status ){ if( !this ) return; (**astMEMBER(this,FitsChan,ShowFits))(this, status ); } void astPutCards_( AstFitsChan *this, const char *cards, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,PutCards))(this,cards, status ); } void astPutFits_( AstFitsChan *this, const char *card, int overwrite, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,PutFits))(this,card,overwrite, status ); } void astDelFits_( AstFitsChan *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,DelFits))(this, status ); } void astPurgeWCS_( AstFitsChan *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,PurgeWCS))(this, status ); } AstKeyMap *astGetTables_( AstFitsChan *this, int *status ){ if( !astOK ) return NULL; return (**astMEMBER(this,FitsChan,GetTables))(this, status ); } void astPutTables_( AstFitsChan *this, AstKeyMap *tables, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,PutTables))(this, tables, status ); } void astPutTable_( AstFitsChan *this, AstFitsTable *table, const char *extnam, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,PutTable))(this, table, extnam, status ); } void astRemoveTables_( AstFitsChan *this, const char *key, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,RemoveTables))(this, key, status ); } void astRetainFits_( AstFitsChan *this, int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,RetainFits))(this, status ); } int astFitsEof_( AstFitsChan *this, int *status ){ if( !this ) return 1; return (**astMEMBER(this,FitsChan,FitsEof))( this, status ); } void astSetFitsCom_( AstFitsChan *this, const char *name, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsCom))( this, name, comment, overwrite, status ); } void astSetFitsI_( AstFitsChan *this, const char *name, int value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsI))( this, name, value, comment, overwrite, status ); } void astSetFitsF_( AstFitsChan *this, const char *name, double value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsF))( this, name, value, comment, overwrite, status ); } void astSetFitsS_( AstFitsChan *this, const char *name, const char *value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsS))( this, name, value, comment, overwrite, status ); } void astSetFitsCN_( AstFitsChan *this, const char *name, const char *value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsCN))( this, name, value, comment, overwrite, status ); } void astSetFitsCF_( AstFitsChan *this, const char *name, double *value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsCF))( this, name, value, comment, overwrite, status ); } void astSetFitsCI_( AstFitsChan *this, const char *name, int *value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsCI))( this, name, value, comment, overwrite, status ); } void astSetFitsL_( AstFitsChan *this, const char *name, int value, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsL))( this, name, value, comment, overwrite, status ); } void astSetFitsU_( AstFitsChan *this, const char *name, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsU))( this, name, comment, overwrite, status ); } void astSetFitsCM_( AstFitsChan *this, const char *comment, int overwrite, int *status ) { if ( !astOK ) return; (**astMEMBER(this,FitsChan,SetFitsCM))( this, comment, overwrite, status ); } void astClearCard_( AstFitsChan *this, int *status ){ if( !this ) return; (**astMEMBER(this,FitsChan,ClearCard))( this, status ); } void astSetCard_( AstFitsChan *this, int card, int *status ){ if( !this ) return; (**astMEMBER(this,FitsChan,SetCard))( this, card, status ); } int astTestCard_( AstFitsChan *this, int *status ){ if( !this ) return 0; return (**astMEMBER(this,FitsChan,TestCard))( this, status ); } int astGetCard_( AstFitsChan *this, int *status ){ if( !this ) return 0; return (**astMEMBER(this,FitsChan,GetCard))( this, status ); } int astGetNcard_( AstFitsChan *this, int *status ){ if( !this ) return 0; return (**astMEMBER(this,FitsChan,GetNcard))( this, status ); } int astGetCardType_( AstFitsChan *this, int *status ){ if( !this ) return AST__NOTYPE; return (**astMEMBER(this,FitsChan,GetCardType))( this, status ); } const char *astGetCardComm_( AstFitsChan *this, int *status ){ if( !this ) return NULL; return (**astMEMBER(this,FitsChan,GetCardComm))( this, status ); } const char *astGetCardName_( AstFitsChan *this, int *status ){ if( !this ) return NULL; return (**astMEMBER(this,FitsChan,GetCardName))( this, status ); } int astGetNkey_( AstFitsChan *this, int *status ){ if( !this ) return 0; return (**astMEMBER(this,FitsChan,GetNkey))( this, status ); } int astGetClean_( AstFitsChan *this, int *status ){ if( !this ) return 0; return (**astMEMBER(this,FitsChan,GetClean))( this, status ); } const char *astGetAllWarnings_( AstFitsChan *this, int *status ){ if( !this ) return NULL; return (**astMEMBER(this,FitsChan,GetAllWarnings))( this, status ); } int astGetFitsCF_( AstFitsChan *this, const char *name, double *value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsCF))( this, name, value, status ); } int astGetFitsCI_( AstFitsChan *this, const char *name, int *value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsCI))( this, name, value, status ); } int astGetFitsF_( AstFitsChan *this, const char *name, double *value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsF))( this, name, value, status ); } int astGetFitsI_( AstFitsChan *this, const char *name, int *value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsI))( this, name, value, status ); } int astGetFitsL_( AstFitsChan *this, const char *name, int *value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsL))( this, name, value, status ); } int astTestFits_( AstFitsChan *this, const char *name, int *there, int *status ){ if( there ) *there = 0; if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,TestFits))( this, name, there, status ); } int astGetFitsS_( AstFitsChan *this, const char *name, char **value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsS))( this, name, value, status ); } int astGetFitsCN_( AstFitsChan *this, const char *name, char **value, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetFitsCN))( this, name, value, status ); } int astFitsGetCom_( AstFitsChan *this, const char *name, char **comment, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,FitsGetCom))( this, name, comment, status ); } int astKeyFields_( AstFitsChan *this, const char *filter, int maxfld, int *ubnd, int *lbnd, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,KeyFields))( this, filter, maxfld, ubnd, lbnd, status ); } int astFindFits_( AstFitsChan *this, const char *name, char *card, int inc, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,FindFits))( this, name, card, inc, status ); } int astGetEncoding_( AstFitsChan *this, int *status ){ if( !astOK ) return UNKNOWN_ENCODING; return (**astMEMBER(this,FitsChan,GetEncoding))( this, status ); } int astGetCDMatrix_( AstFitsChan *this, int *status ){ if( !astOK ) return 0; return (**astMEMBER(this,FitsChan,GetCDMatrix))( this, status ); } void astSetTableSource_( AstFitsChan *this, void (*tabsource)( void ), void (*tabsource_wrap)( void (*)( void ), AstFitsChan *, const char *, int, int, int * ), int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,SetTableSource))( this, tabsource, tabsource_wrap, status ); } void astTableSource_( AstFitsChan *this, void (* tabsource)( AstFitsChan *, const char *, int, int, int * ), int *status ){ if( !astOK ) return; (**astMEMBER(this,FitsChan,TableSource))( this, tabsource, status ); } /* * A diagnostic function which lists the contents of a FitsChan to * standard output. */ /* static void ListFC( AstFitsChan *, const char * ); static void ListFC( AstFitsChan *this, const char *ttl ) { FitsCard *cardo; char card[ 81 ]; printf("%s\n----------------------------------------\n", ttl ); cardo = (FitsCard *) this->card; astClearCard( this ); while( !astFitsEof( this ) && astOK ){ FormatCard( this, card, "List" ); if( this->card == cardo ) { printf( "%s <<<<< currrent card <<<<< \n", card ); } else { printf( "%s\n", card ); } MoveCard( this, 1, "List", "FitsChan" ); } this->card = cardo; } */ ./ast-7.3.3/selectormap.h0000644000175000017500000002025412262533650013634 0ustar olesoles#if !defined( SELECTORMAP_INCLUDED ) /* Include this file only once */ #define SELECTORMAP_INCLUDED /* *+ * Name: * selectormap.h * Type: * C include file. * Purpose: * Define the interface to the SelectorMap class. * Invocation: * #include "selectormap.h" * Description: * This include file defines the interface to the SelectorMap class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * Inheritance: * The SelectorMap class inherits from the Mapping class. * Attributes Over-Ridden: * None. * New Attributes Defined: * None. * Methods Over-Ridden: * Public: * None. * * Protected: * astMapMerge * Merge a SelectorMap within a sequence of Mappings. * astTransform * Transform a set of points. * New Methods Defined: * Public: * None. * * Protected: * None. * Other Class Functions: * Public: * astIsASelectorMap * Test class membership. * astSelectorMap * Create a SelectorMap. * * Protected: * astCheckSelectorMap * Validate class membership. * astInitSelectorMap * Initialise a SelectorMap. * astInitSelectorMapVtab * Initialise the virtual function table for the SelectorMap class. * astLoadSelectorMap * Load a SelectorMap. * Macros: * None. * Type Definitions: * Public: * AstSelectorMap * SelectorMap object type. * * Protected: * AstSelectorMapVtab * SelectorMap virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 13-MAR-2006 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "mapping.h" /* Coordinate Mappings (parent class) */ #include "region.h" /* Coordinate Regions (parent class) */ #if defined(astCLASS) /* Protected */ #include "pointset.h" /* Sets of points/coordinates */ #include "channel.h" /* I/O channels */ #endif /* C header files. */ /* --------------- */ #if defined(astCLASS) /* Protected */ #include #endif /* Macros */ /* ====== */ /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* SelectorMap structure. */ /* ----------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstSelectorMap { /* Attributes inherited from the parent class. */ AstMapping mapping; /* Parent class structure */ /* Attributes specific to objects in this class. */ int nreg; /* The number of Regions in the SelectorMap */ AstRegion **reg; /* Array of Region pointers */ double badval; /* Output value for positions with bad axis values */ } AstSelectorMap; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstSelectorMapVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstMappingVtab mapping_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ /* None. */ } AstSelectorMapVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within the object.c file. */ typedef struct AstSelectorMapGlobals { AstSelectorMapVtab Class_Vtab; int Class_Init; } AstSelectorMapGlobals; /* Thread-safe initialiser for all global data used by this module. */ void astInitSelectorMapGlobals_( AstSelectorMapGlobals * ); #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(SelectorMap) /* Check class membership */ astPROTO_ISA(SelectorMap) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstSelectorMap *astSelectorMap_( int, void **, double, const char *, int *, ...); #else AstSelectorMap *astSelectorMapId_( int, void **, double, const char *, ... )__attribute__((format(printf,4,5))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstSelectorMap *astInitSelectorMap_( void *, size_t, int, AstSelectorMapVtab *, const char *, int, AstRegion **, double, int * ); /* Vtab initialiser. */ void astInitSelectorMapVtab_( AstSelectorMapVtab *, const char *, int * ); /* Loader. */ AstSelectorMap *astLoadSelectorMap_( void *, size_t, AstSelectorMapVtab *, const char *, AstChannel *, int * ); #endif /* Prototypes for member functions. */ /* -------------------------------- */ /* None. */ /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckSelectorMap(this) astINVOKE_CHECK(SelectorMap,this,0) #define astVerifySelectorMap(this) astINVOKE_CHECK(SelectorMap,this,1) /* Test class membership. */ #define astIsASelectorMap(this) astINVOKE_ISA(SelectorMap,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astSelectorMap astINVOKE(F,astSelectorMap_) #else #define astSelectorMap astINVOKE(F,astSelectorMapId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitSelectorMap(mem,size,init,vtab,name,nreg,regs,badval) \ astINVOKE(O,astInitSelectorMap_(mem,size,init,vtab,name,nreg,regs,badval,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitSelectorMapVtab(vtab,name) astINVOKE(V,astInitSelectorMapVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadSelectorMap(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadSelectorMap_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckSelectorMap to validate SelectorMap pointers before use. This provides a contextual error report if a pointer to the wrong sort of Object is supplied. */ /* None. */ #endif ./ast-7.3.3/plot3d.h0000644000175000017500000002111512262533650012520 0ustar olesoles#if !defined( PLOT3D_INCLUDED ) /* Include this file only once */ #define PLOT3D_INCLUDED /* *+ * Name: * plot3d.h * Type: * C include file. * Purpose: * Define the interface to the Plot3D class. * Invocation: * #include "plot3d.h" * Description: * This include file defines the interface to the Plot3D class * and provides the type definitions, function prototypes and * macros, etc. needed to use this class. * 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 6-JUN-2007 (DSB): * Original version. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "object.h" /* Base Object class */ #include "plot.h" /* Parent Plot class */ /* Macros. */ /* ======= */ #if defined(astCLASS) || defined(astFORTRAN77) #define STATUS_PTR status #else #define STATUS_PTR astGetStatusPtr #endif #if defined(astCLASS) /* Protected */ #endif /* Type Definitions. */ /* ================= */ /* Plot3D structure. */ /* ------------------- */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstPlot3D { /* Attributes inherited from the parent class. */ AstPlot plot; /* Parent class structure */ /* Attributes specific to objects in this class. */ AstPlot *plotxy; /* Plot describing the XY plane */ AstPlot *plotxz; /* Plot describing the XZ plane */ AstPlot *plotyz; /* Plot describing the YZ plane */ double gbox[6]; /* Graphics box */ int pix_frame; /* Index of original base Frame */ int rootcorner; /* Corner at junction of the annotated axes */ int baseplot; /* The Plot that is used to label 2 3D axes */ int axis_plot1[3]; /* The Plot used to label each 3D axis */ int axis_index1[3]; /* The axis index within the axis_plot1 Plot */ int axis_plot2[3]; /* The other Plot touching each 3D axis */ int axis_index2[3]; /* The axis index within the axis_plot2 Plot */ double norm[3]; /* Normal vector for text plane */ } AstPlot3D; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstPlot3DVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstPlotVtab plot_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; int (* GetRootCorner)( AstPlot3D *, int * ); int (* TestRootCorner)( AstPlot3D *, int * ); void (* SetRootCorner)( AstPlot3D *, int, int * ); void (* ClearRootCorner)( AstPlot3D *, int * ); double (* GetNorm)( AstPlot3D *, int, int * ); int (* TestNorm)( AstPlot3D *, int, int * ); void (* SetNorm)( AstPlot3D *, int, double, int * ); void (* ClearNorm)( AstPlot3D *, int, int * ); } AstPlot3DVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstPlot3DGlobals { AstPlot3DVtab Class_Vtab; int Class_Init; char GetAttrib_Buff[ 101 ]; } AstPlot3DGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(Plot3D) /* Check class membership */ astPROTO_ISA(Plot3D) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected */ AstPlot3D *astPlot3D_( void *, const float *, const double *, const char *, int *, ...); #else AstPlot3D *astPlot3DId_( void *, const float [], const double [], const char *, ... ); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstPlot3D *astInitPlot3D_( void *, size_t, int, AstPlot3DVtab *, const char *, AstFrame *, const float *, const double *, int * ); /* Vtab initialiser. */ void astInitPlot3DVtab_( AstPlot3DVtab *, const char *, int * ); /* Loader. */ AstPlot3D *astLoadPlot3D_( void *, size_t, AstPlot3DVtab *, const char *, AstChannel *channel, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitPlot3DGlobals_( AstPlot3DGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ #if defined(astCLASS) /* Protected */ int astGetRootCorner_( AstPlot3D *, int * ); int astTestRootCorner_( AstPlot3D *, int * ); void astSetRootCorner_( AstPlot3D *, int, int * ); void astClearRootCorner_( AstPlot3D *, int * ); double astGetNorm_( AstPlot3D *, int, int * ); int astTestNorm_( AstPlot3D *, int, int * ); void astSetNorm_( AstPlot3D *, int, double, int * ); void astClearNorm_( AstPlot3D *, int, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckPlot3D(this) astINVOKE_CHECK(Plot3D,this,0) #define astVerifyPlot3D(this) astINVOKE_CHECK(Plot3D,this,1) /* Test class membership. */ #define astIsAPlot3D(this) astINVOKE_ISA(Plot3D,this) /* Constructor. */ #if defined(astCLASS) /* Protected */ #define astPlot3D astINVOKE(F,astPlot3D_) #else #define astPlot3D astINVOKE(F,astPlot3DId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitPlot3D(mem,size,init,vtab,name,frame,graph,base) \ astINVOKE(O,astInitPlot3D_(mem,size,init,vtab,name,frame,graph,base,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitPlot3DVtab(vtab,name) astINVOKE(V,astInitPlot3DVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadPlot3D(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadPlot3D_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Interfaces to protected member functions. */ /* ----------------------------------------- */ /* Here we make use of astCheckPlot3D to validate Plot3D pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #if defined(astCLASS) /* Protected */ #define astGetRootCorner(this) astINVOKE(V,astGetRootCorner_(astCheckPlot3D(this),STATUS_PTR)) #define astTestRootCorner(this) astINVOKE(V,astTestRootCorner_(astCheckPlot3D(this),STATUS_PTR)) #define astClearRootCorner(this) astINVOKE(V,astClearRootCorner_(astCheckPlot3D(this),STATUS_PTR)) #define astSetRootCorner(this,value) astINVOKE(V,astSetRootCorner_(astCheckPlot3D(this),value,STATUS_PTR)) #define astGetNorm(this,axis) astINVOKE(V,astGetNorm_(astCheckPlot3D(this),axis,STATUS_PTR)) #define astTestNorm(this,axis) astINVOKE(V,astTestNorm_(astCheckPlot3D(this),axis,STATUS_PTR)) #define astClearNorm(this,axis) astINVOKE(V,astClearNorm_(astCheckPlot3D(this),axis,STATUS_PTR)) #define astSetNorm(this,axis,value) astINVOKE(V,astSetNorm_(astCheckPlot3D(this),axis,value,STATUS_PTR)) #endif #endif ./ast-7.3.3/fdsbspecframe.c0000644000175000017500000000574712262533650014127 0ustar olesoles/* *+ * Name: * fdsbspecframe.c * Purpose: * Define a FORTRAN 77 interface to the AST DSBSpecFrame class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the DSBSpecFrame class. * Routines Defined: * AST_ISADSBSPECFRAME * AST_DSBSPECFRAME * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David S. Berry (Starlink) * History: * 5-AUG-2004 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "dsbspecframe.h" /* C interface to the DSBSpecFrame class */ F77_LOGICAL_FUNCTION(ast_isadsbspecframe)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISADSBSPECFRAME", NULL, 0 ); astWatchSTATUS( RESULT = astIsADSBSpecFrame( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_dsbspecframe)( CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); int i; char *options; astAt( "AST_DSBSPECFRAME", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astDSBSpecFrame( "%s", options ) ); astFree( options ); ) return RESULT; } ./ast-7.3.3/skyaxis.h0000644000175000017500000003620412262533650013013 0ustar olesoles#if !defined( SKYAXIS_INCLUDED ) /* Include this file only once */ #define SKYAXIS_INCLUDED /* *+ * Name: * skyaxis.h * Type: * C include file. * Purpose: * Define the interface to the SkyAxis class. * Invocation: * #include "skyaxis.h" * Description: * This include file defines the interface to the SkyAxis class and * provides the type definitions, function prototypes and macros, * etc. needed to use this class. * * The SkyAxis class extends the Axis class to represent angles on * the sky measured in radians. It provides alternative formatting * facilities for representing these coordinate values either as * angles (in degrees) or as time (in hours) using sexagesimal * notation. It also provides alternative defaults for certain * attributes and adds new attributes and methods of its own which * are needed to manipulate angular coordinates on the sky. * Inheritance: * The SkyAxis class inherits from the Axis class. * Attributes Over-Ridden: * Format (string) * The SkyAxis class defines a new syntax for this string. * Label (string) * The SkyAxis class defines new default values. These may * depend on other attribute settings. * Symbol (string) * The SkyAxis class defines new default values. These may * depend on other attribute settings. * Unit (string) * The SkyAxis class defines new default values. These may * depend on other attribute settings. * New Attributes Defined: * AsTime (integer) * A boolean value which indicates whether SkyAxis coordinate * values should be formatted for display as times (instead of * angles). It is used to determine the default format to use if * no explicit value has been set for the Format attribute. * CentreZero (integer) * A boolean value which indicates whether a SkyAxis value should * be normalised into the range [-PI,+PI] or [0,2.PI] when astNorm * is used. * IsLatitude (integer) * A boolean value which indicates whether a SkyAxis is a * latitude axis (as opposed to a longitude axis). It is used to * determine default axis labels and symbols. It also determines the * default value for the "AsTime" attribute (since longitudes on * the sky are usually expressed as times). * Methods Over-Ridden: * Public: * astAxisFormat * Format a coordinate value for a SkyAxis. * astAxisNorm * Normalise a SkyAxis coordinate value. * astAxisUnformat * Read a formatted coordinate value for a SkyAxis. * Protected: * astAxisAbbrev * Abbreviate a formatted SkyAxis value by skipping leading fields. * astAxisDistance * Find the distance between two SkyAxis values. * astAxisGap * Find a "nice" gap for tabulating SkyAxis values. * astClearAxisFormat * Clear the Format attribute for a SkyAxis. * astGetAxisDirection * Obtain the value of the Direction attribute for a SkyAxis. * astGetAxisFormat * Obtain a pointer to the Format attribute for a SkyAxis. * astGetAxisLabel * Obtain a pointer to the Label attribute for a SkyAxis. * astGetAxisSymbol * Obtain a pointer to the Symbol attribute for a SkyAxis. * astGetAxisUnit * Obtain a pointer to the Unit attribute for a SkyAxis. * astSetAxisFormat * Set a value for the Format attribute of a SkyAxis. * astTestAxisFormat * Test if a value has been set for the Format attribute of a SkyAxis. * astAxisOffset * Add an increment onto a supplied SkyAxis value. * astAxisOverlay * Overlay the attributes of a template SkyAxis on to another Axis. * astSetAttrib * Set an attribute value for a SkyAxis. * New Methods Defined: * Public: * None. * Protected: * astClearAxisAsTime * Clear the AsTime attribute for a SkyAxis. * astClearAxisCentreZero * Clear the CentreZero attribute for a SkyAxis. * astClearAxisIsLatitude * Clear the IsLatitude attribute for a SkyAxis. * astGetAxisAsTime * Obtain the value of the AsTime attribute for a SkyAxis. * astGetAxisIsLatitude * Obtain the value of the IsLatitude attribute for a SkyAxis. * astGetAxisCentreZero * Obtain the value of the CentreZero attribute for a SkyAxis. * astSetAxisAsTime * Set a value for the AsTime attribute of a SkyAxis. * astSetAxisIsLatitude * Set a value for the IsLatitude attribute of a SkyAxis. * astSetAxisCentreZero * Set a value for the CentreZero attribute of a SkyAxis. * astTestAxisAsTime * Test if a value has been set for the AsTime attribute of a SkyAxis. * astTestAxisIsLatitude * Test if a value has been set for the IsLatitude attribute of a * SkyAxis. * astTestAxisCentreZero * Test if a value has been set for the CentreZero attribute of a * SkyAxis. * Other Class Functions: * Public: * astIsASkyAxis * Test class membership. * astSkyAxis * Create an SkyAxis. * Protected: * astCheckSkyAxis * Validate class membership. * astInitSkyAxis * Initialise an SkyAxis. * Macros: * None. * Type Definitions: * Public: * AstSkyAxis * SkyAxis object type. * Protected: * AstSkyAxisVtab * SkyAxis virtual function table type. * Feature Test Macros: * astCLASS * If the astCLASS macro is undefined, only public symbols are * made available, otherwise protected symbols (for use in other * class implementations) are defined. This macro also affects * the reporting of error context information, which is only * provided for external calls to the AST library. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * RFWS: R.F. Warren-Smith (Starlink) * History: * 29-MAR-1996 (RFWS): * Original version. * 25-APR-1996 (RFWS): * Made all attribute access functions protected. * 13-MAY-1996 (RFWS): * Documented over-riding of the astGetAxisDirection method. * 26-FEB-1998 (RFWS): * Over-ride the astAxisUnformat method. * 8-JAN-2003 (DSB): * Added protected astInitSkyAxisVtab method. *- */ /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "axis.h" /* Coordinate axes (parent class) */ /* Macros */ /* ====== */ /* Define constants used to size global arrays in this module. */ /* Define numerical constants for use in thie module. */ #define AST__SKYAXIS_GETAXISFORMAT_BUFF_LEN 50 #define AST__SKYAXIS_DHMSFORMAT_BUFF_LEN 70 #define AST__SKYAXIS_DHMSUNIT_BUFF_LEN 17 #define AST__SKYAXIS_GETATTRIB_BUFF_LEN 50 /* Define a dummy __attribute__ macro for use on non-GNU compilers. */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif /* Type Definitions. */ /* ================= */ /* SkyAxis structure. */ /* ------------------ */ /* This structure contains all information that is unique to each object in the class (e.g. its instance variables). */ typedef struct AstSkyAxis { /* Attributes inherited from the parent class. */ AstAxis axis; /* Parent class structure */ /* Attributes specific to objects in this class. */ char *skyformat; /* Pointer to sky format string */ int as_time; /* Format angles as time (hours)? */ int is_latitude; /* SkyAxis is a latitude axis? */ int centrezero; /* Normalised range is zero-centred? */ } AstSkyAxis; /* Virtual function table. */ /* ----------------------- */ /* This table contains all information that is the same for all objects in the class (e.g. pointers to its virtual functions). */ #if defined(astCLASS) /* Protected */ typedef struct AstSkyAxisVtab { /* Properties (e.g. methods) inherited from the parent class. */ AstAxisVtab axis_vtab; /* Parent class virtual function table */ /* A Unique identifier to determine class membership. */ AstClassIdentifier id; /* Properties (e.g. methods) specific to this class. */ int (* GetAxisAsTime)( AstSkyAxis *, int * ); int (* GetAxisIsLatitude)( AstSkyAxis *, int * ); int (* GetAxisCentreZero)( AstSkyAxis *, int * ); int (* TestAxisAsTime)( AstSkyAxis *, int * ); int (* TestAxisIsLatitude)( AstSkyAxis *, int * ); int (* TestAxisCentreZero)( AstSkyAxis *, int * ); void (* ClearAxisAsTime)( AstSkyAxis *, int * ); void (* ClearAxisIsLatitude)( AstSkyAxis *, int * ); void (* ClearAxisCentreZero)( AstSkyAxis *, int * ); void (* SetAxisAsTime)( AstSkyAxis *, int, int * ); void (* SetAxisIsLatitude)( AstSkyAxis *, int, int * ); void (* SetAxisCentreZero)( AstSkyAxis *, int, int * ); } AstSkyAxisVtab; #if defined(THREAD_SAFE) /* Define a structure holding all data items that are global within this class. */ typedef struct AstSkyAxisGlobals { AstSkyAxisVtab Class_Vtab; int Class_Init; char DHmsFormat_Buff[ AST__SKYAXIS_DHMSFORMAT_BUFF_LEN + 1 ]; char DHmsUnit_Buff[ AST__SKYAXIS_DHMSUNIT_BUFF_LEN + 1 ]; char GetAttrib_Buff[ AST__SKYAXIS_GETATTRIB_BUFF_LEN + 1 ]; char GetAxisFormat_Buff[ AST__SKYAXIS_GETAXISFORMAT_BUFF_LEN + 1 ]; char *GhDelim; char *GmDelim; char *GsDelim; char *GdDelim; char *GamDelim; char *GasDelim; } AstSkyAxisGlobals; #endif #endif /* Function prototypes. */ /* ==================== */ /* Prototypes for standard class functions. */ /* ---------------------------------------- */ astPROTO_CHECK(SkyAxis) /* Check class membership */ astPROTO_ISA(SkyAxis) /* Test class membership */ /* Constructor. */ #if defined(astCLASS) /* Protected. */ AstSkyAxis *astSkyAxis_( const char *, int *, ...); #else AstSkyAxis *astSkyAxisId_( const char *, ... )__attribute__((format(printf,1,2))); #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ AstSkyAxis *astInitSkyAxis_( void *, size_t, int, AstSkyAxisVtab *, const char *, int * ); /* Vtab initialiser. */ void astInitSkyAxisVtab_( AstSkyAxisVtab *, const char *, int * ); /* Loader. */ AstSkyAxis *astLoadSkyAxis_( void *, size_t, AstSkyAxisVtab *, const char *, AstChannel *, int * ); /* Thread-safe initialiser for all global data used by this module. */ #if defined(THREAD_SAFE) void astInitSkyAxisGlobals_( AstSkyAxisGlobals * ); #endif #endif /* Prototypes for member functions. */ /* -------------------------------- */ #if defined(astCLASS) /* Protected */ int astGetAxisAsTime_( AstSkyAxis *, int * ); int astGetAxisIsLatitude_( AstSkyAxis *, int * ); int astGetAxisCentreZero_( AstSkyAxis *, int * ); int astTestAxisAsTime_( AstSkyAxis *, int * ); int astTestAxisIsLatitude_( AstSkyAxis *, int * ); int astTestAxisCentreZero_( AstSkyAxis *, int * ); void astClearAxisAsTime_( AstSkyAxis *, int * ); void astClearAxisIsLatitude_( AstSkyAxis *, int * ); void astClearAxisCentreZero_( AstSkyAxis *, int * ); void astSetAxisAsTime_( AstSkyAxis *, int, int * ); void astSetAxisIsLatitude_( AstSkyAxis *, int, int * ); void astSetAxisCentreZero_( AstSkyAxis *, int, int * ); #endif /* Function interfaces. */ /* ==================== */ /* These macros are wrap-ups for the functions defined by this class to make them easier to invoke (e.g. to avoid type mis-matches when passing pointers to objects from derived classes). */ /* Interfaces to standard class functions. */ /* --------------------------------------- */ /* Some of these functions provide validation, so we cannot use them to validate their own arguments. We must use a cast when passing object pointers (so that they can accept objects from derived classes). */ /* Check class membership. */ #define astCheckSkyAxis(this) astINVOKE_CHECK(SkyAxis,this,0) #define astVerifySkyAxis(this) astINVOKE_CHECK(SkyAxis,this,1) /* Test class membership. */ #define astIsASkyAxis(this) astINVOKE_ISA(SkyAxis,this) /* Constructor. */ #if defined(astCLASS) /* Protected. */ #define astSkyAxis astINVOKE(F,astSkyAxis_) #else #define astSkyAxis astINVOKE(F,astSkyAxisId_) #endif #if defined(astCLASS) /* Protected */ /* Initialiser. */ #define astInitSkyAxis(mem,size,init,vtab,name) \ astINVOKE(O,astInitSkyAxis_(mem,size,init,vtab,name,STATUS_PTR)) /* Vtab Initialiser. */ #define astInitSkyAxisVtab(vtab,name) astINVOKE(V,astInitSkyAxisVtab_(vtab,name,STATUS_PTR)) /* Loader. */ #define astLoadSkyAxis(mem,size,vtab,name,channel) \ astINVOKE(O,astLoadSkyAxis_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PTR)) #endif /* Interfaces to public member functions. */ /* -------------------------------------- */ /* Here we make use of astCheckSkyAxis to validate SkyAxis pointers before use. This provides a contextual error report if a pointer to the wrong sort of object is supplied. */ #if defined(astCLASS) /* Protected */ #define astClearAxisAsTime(this) \ astINVOKE(V,astClearAxisAsTime_(astCheckSkyAxis(this),STATUS_PTR)) #define astClearAxisIsLatitude(this) \ astINVOKE(V,astClearAxisIsLatitude_(astCheckSkyAxis(this),STATUS_PTR)) #define astGetAxisAsTime(this) \ astINVOKE(V,astGetAxisAsTime_(astCheckSkyAxis(this),STATUS_PTR)) #define astGetAxisIsLatitude(this) \ astINVOKE(V,astGetAxisIsLatitude_(astCheckSkyAxis(this),STATUS_PTR)) #define astSetAxisAsTime(this,value) \ astINVOKE(V,astSetAxisAsTime_(astCheckSkyAxis(this),value,STATUS_PTR)) #define astSetAxisIsLatitude(this,value) \ astINVOKE(V,astSetAxisIsLatitude_(astCheckSkyAxis(this),value,STATUS_PTR)) #define astTestAxisAsTime(this) \ astINVOKE(V,astTestAxisAsTime_(astCheckSkyAxis(this),STATUS_PTR)) #define astTestAxisIsLatitude(this) \ astINVOKE(V,astTestAxisIsLatitude_(astCheckSkyAxis(this),STATUS_PTR)) #define astClearAxisCentreZero(this) \ astINVOKE(V,astClearAxisCentreZero_(astCheckSkyAxis(this),STATUS_PTR)) #define astGetAxisCentreZero(this) \ astINVOKE(V,astGetAxisCentreZero_(astCheckSkyAxis(this),STATUS_PTR)) #define astSetAxisCentreZero(this,value) \ astINVOKE(V,astSetAxisCentreZero_(astCheckSkyAxis(this),value,STATUS_PTR)) #define astTestAxisCentreZero(this) \ astINVOKE(V,astTestAxisCentreZero_(astCheckSkyAxis(this),STATUS_PTR)) #endif #endif ./ast-7.3.3/fpolymap.c0000644000175000017500000001053112262533650013135 0ustar olesoles/* *+ * Name: * fpolymap.c * Purpose: * Define a FORTRAN 77 interface to the AST PolyMap class. * Type of Module: * C source file. * Description: * This file defines FORTRAN 77-callable C functions which provide * a public FORTRAN 77 interface to the PolyMap class. * Routines Defined: * AST_ISAPOLYMAP * AST_POLYMAP * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: D.S. Berry (Starlink) * History: * 27-SEP-2003 (DSB): * Original version. */ /* Define the astFORTRAN77 macro which prevents error messages from AST C functions from reporting the file and line number where the error occurred (since these would refer to this file, they would not be useful). */ #define astFORTRAN77 /* Header files. */ /* ============= */ #include "f77.h" /* FORTRAN <-> C interface macros (SUN/209) */ #include "c2f77.h" /* F77 <-> C support functions/macros */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory handling facilities */ #include "polymap.h" /* C interface to the PolyMap class */ F77_LOGICAL_FUNCTION(ast_isapolymap)( INTEGER(THIS), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) F77_LOGICAL_TYPE(RESULT); astAt( "AST_ISAPOLYMAP", NULL, 0 ); astWatchSTATUS( RESULT = astIsAPolyMap( astI2P( *THIS ) ) ? F77_TRUE : F77_FALSE; ) return RESULT; } F77_INTEGER_FUNCTION(ast_polymap)( INTEGER(NIN), INTEGER(NOUT), INTEGER(NCOEFF_F), DOUBLE_ARRAY(COEFF_F), INTEGER(NCOEFF_I), DOUBLE_ARRAY(COEFF_I), CHARACTER(OPTIONS), INTEGER(STATUS) TRAIL(OPTIONS) ) { GENPTR_INTEGER(NIN) GENPTR_INTEGER(NOUT) GENPTR_INTEGER(NCOEFF_F) GENPTR_DOUBLE_ARRAY(COEFF_F) GENPTR_INTEGER(NCOEFF_I) GENPTR_DOUBLE_ARRAY(COEFF_I) GENPTR_CHARACTER(OPTIONS) F77_INTEGER_TYPE(RESULT); char *options; int i; astAt( "AST_POLYMAP", NULL, 0 ); astWatchSTATUS( options = astString( OPTIONS, OPTIONS_length ); /* Change ',' to '\n' (see AST_SET in fobject.c for why). */ if ( astOK ) { for ( i = 0; options[ i ]; i++ ) { if ( options[ i ] == ',' ) options[ i ] = '\n'; } } RESULT = astP2I( astPolyMap( *NIN, *NOUT, *NCOEFF_F, COEFF_F, *NCOEFF_I, COEFF_I, "%s", options ) ); astFree( options ); ) return RESULT; } F77_INTEGER_FUNCTION(ast_polytran)( INTEGER(THIS), LOGICAL(FORWARD), DOUBLE(ACC), DOUBLE(MAXACC), INTEGER(MAXORDER), DOUBLE_ARRAY(LBND), DOUBLE_ARRAY(UBND), INTEGER(STATUS) ) { GENPTR_INTEGER(THIS) GENPTR_LOGICAL(FORWARD) GENPTR_DOUBLE(ACC) GENPTR_DOUBLE(MAXACC) GENPTR_INTEGER(MAXORDER) GENPTR_DOUBLE_ARRAY(LBND) GENPTR_DOUBLE_ARRAY(UBND) F77_INTEGER_TYPE(RESULT); astAt( "AST_POLYTRAN", NULL, 0 ); astWatchSTATUS( RESULT = astP2I( astPolyTran( astI2P( *THIS ), F77_ISTRUE( *FORWARD ), *ACC, *MAXACC, *MAXORDER, LBND, UBND ) ); ) return RESULT; } ./ast-7.3.3/sphmap.c0000644000175000017500000021174312262533650012606 0ustar olesoles/* *class++ * Name: * SphMap * Purpose: * Map 3-d Cartesian to 2-d spherical coordinates * Constructor Function: c astSphMap f AST_SPHMAP * Description: * A SphMap is a Mapping which transforms points from a * 3-dimensional Cartesian coordinate system into a 2-dimensional * spherical coordinate system (longitude and latitude on a unit * sphere centred at the origin). It works by regarding the input * coordinates as position vectors and finding their intersection * with the sphere surface. The inverse transformation always * produces points which are a unit distance from the origin * (i.e. unit vectors). * Inheritance: * The SphMap class inherits from the Mapping class. * Attributes: * In addition to those attributes common to all Mappings, every * SphMap also has the following attributes: * * - UnitRadius: SphMap input vectors lie on a unit sphere? * - PolarLong: The longitude value to assign to either pole * Functions: c The SphMap class does not define any new functions beyond those f The SphMap class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * RFWS: R.F. Warren-Smith (Starlink) * History: * 24-OCT-1996 (DSB): * Original version. * 5-MAR-1997 (RFWS): * Tidied public prologues. * 24-MAR-1998 (RFWS): * Override the astMapMerge method. * 4-SEP-1998 (DSB): * Added UnitRadius attribute. * 8-JAN-2003 (DSB): * Changed private InitVtab method to protected astInitSphMapVtab * method. * 11-JUN-2003 (DSB): * Added PolarLong attribute. * 10-MAY-2006 (DSB): * Override astEqual. * 5-NOV-2013 (DSB): * Modify MapMerge so that it can spot and simplify an * (inverted SphMap,MatrixMap,SphMap) sequence in which the * MatrixMap just magnifies or reflects the radius vector. *class-- */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS SphMap /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory management facilities */ #include "globals.h" /* Thread-safe global data access */ #include "object.h" /* Base Object class */ #include "pointset.h" /* Sets of points/coordinates */ #include "mapping.h" /* Coordinate mappings (parent class) */ #include "channel.h" /* I/O channels */ #include "unitmap.h" /* Unit (identity) Mappings */ #include "sphmap.h" /* Interface definition for this class */ #include "pal.h" /* SLA transformations */ #include "wcsmap.h" /* For the AST__DPIBY2 (etc) constants */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static AstPointSet *(* parent_transform)( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->GetAttrib_Buff[ 0 ] = 0; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(SphMap) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(SphMap,Class_Init) #define class_vtab astGLOBAL(SphMap,Class_Vtab) #define getattrib_buff astGLOBAL(SphMap,GetAttrib_Buff) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else static char getattrib_buff[ 101 ]; /* Define the class virtual function table and its initialisation flag as static variables. */ static AstSphMapVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstSphMap *astSphMapId_( const char *, ...); /* Prototypes for Private Member Functions. */ /* ======================================== */ static int GetUnitRadius( AstSphMap *, int * ); static int TestUnitRadius( AstSphMap *, int * ); static void ClearUnitRadius( AstSphMap *, int * ); static void SetUnitRadius( AstSphMap *, int, int * ); static double GetPolarLong( AstSphMap *, int * ); static int TestPolarLong( AstSphMap *, int * ); static void ClearPolarLong( AstSphMap *, int * ); static void SetPolarLong( AstSphMap *, double, int * ); static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static int Equal( AstObject *, AstObject *, int * ); static int MapMerge( AstMapping *, int, int, int *, AstMapping ***, int **, int * ); static int TestAttrib( AstObject *, const char *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void SetAttrib( AstObject *, const char *, int * ); /* Member functions. */ /* ================= */ static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * ClearAttrib * Purpose: * Clear an attribute value for a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * void ClearAttrib( AstObject *this, const char *attrib, int *status, int *status ) * Class Membership: * SphMap member function (over-rides the astClearAttrib protected * method inherited from the Mapping class). * Description: * This function clears the value of a specified attribute for a * SphMap, so that the default value will subsequently be used. * Parameters: * this * Pointer to the SphMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSphMap *this; /* Pointer to the SphMap structure */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SphMap structure. */ this = (AstSphMap *) this_object; /* UnitRadius */ /* ---------- */ if ( !strcmp( attrib, "unitradius" ) ) { astClearUnitRadius( this ); /* PolarLong */ /* --------- */ } else if ( !strcmp( attrib, "polarlong" ) ) { astClearPolarLong( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_clearattrib)( this_object, attrib, status ); } } static int Equal( AstObject *this_object, AstObject *that_object, int *status ) { /* * Name: * Equal * Purpose: * Test if two SphMaps are equivalent. * Type: * Private function. * Synopsis: * #include "sphmap.h" * int Equal( AstObject *this, AstObject *that, int *status, int *status ) * Class Membership: * SphMap member function (over-rides the astEqual protected * method inherited from the astMapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * two SphMaps are equivalent. * Parameters: * this * Pointer to the first Object (a SphMap). * that * Pointer to the second Object. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Returned Value: * One if the SphMaps are equivalent, zero otherwise. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSphMap *that; AstSphMap *this; int nin; int nout; int result; /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain pointers to the two SphMap structures. */ this = (AstSphMap *) this_object; that = (AstSphMap *) that_object; /* Check the second object is a SphMap. We know the first is a SphMap since we have arrived at this implementation of the virtual function. */ if( astIsASphMap( that ) ) { /* Get the number of inputs and outputs and check they are the same for both. */ nin = astGetNin( this ); nout = astGetNout( this ); if( astGetNin( that ) == nin && astGetNout( that ) == nout ) { /* If the Invert flags for the two SphMaps differ, it may still be possible for them to be equivalent. First compare the SphMaps if their Invert flags are the same. In this case all the attributes of the two SphMaps must be identical. */ if( astGetInvert( this ) == astGetInvert( that ) ) { if( astEQUAL( this->polarlong, that->polarlong ) && this->unitradius == that->unitradius ){ result = 1; } /* If the Invert flags for the two SphMaps differ, the attributes of the two SphMaps must be inversely related to each other. */ } else { /* In the specific case of a SphMap, Invert flags must be equal. */ result = 0; } } } /* If an error occurred, clear the result value. */ if ( !astOK ) result = 0; /* Return the result, */ return result; } static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * GetAttrib * Purpose: * Get the value of a specified attribute for a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * const char *GetAttrib( AstObject *this, const char *attrib, int *status, int *status ) * Class Membership: * SphMap member function (over-rides the protected astGetAttrib * method inherited from the Mapping class). * Description: * This function returns a pointer to the value of a specified * attribute for a SphMap, formatted as a character string. * Parameters: * this * Pointer to the SphMap. * attrib * Pointer to a null-terminated string containing the name of * the attribute whose value is required. This name should be in * lower case, with all white space removed. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Returned Value: * - Pointer to a null-terminated string containing the attribute * value. * Notes: * - The returned string pointer may point at memory allocated * within the SphMap, or at static memory. The contents of the * string may be over-written or the pointer may become invalid * following a further invocation of the same function or any * modification of the SphMap. A copy of the string should * therefore be made if necessary. * - A NULL pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSphMap *this; /* Pointer to the SphMap structure */ const char *result; /* Pointer value to return */ double dval; /* Double precision attribute value */ int ival; /* Int attribute value */ /* Initialise. */ result = NULL; /* Check the global error status. */ if ( !astOK ) return result; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(this_object); /* Obtain a pointer to the SphMap structure. */ this = (AstSphMap *) this_object; /* UnitRadius. */ /* ----------- */ if ( !strcmp( attrib, "unitradius" ) ) { ival = astGetUnitRadius( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%d", ival ); result = getattrib_buff; } /* PolarLong */ /* --------- */ } else if ( !strcmp( attrib, "polarlong" ) ) { dval = astGetPolarLong( this ); if ( astOK ) { (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval ); result = getattrib_buff; } /* If the attribute name was not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_getattrib)( this_object, attrib, status ); } /* Return the result. */ return result; } void astInitSphMapVtab_( AstSphMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSphMapVtab * Purpose: * Initialise a virtual function table for a SphMap. * Type: * Protected function. * Synopsis: * #include "sphmap.h" * void astInitSphMapVtab( AstSphMapVtab *vtab, const char *name ) * Class Membership: * SphMap vtab initialiser. * Description: * This function initialises the component of a virtual function * table which is used by the SphMap class. * Parameters: * vtab * Pointer to the virtual function table. The components used by * all ancestral classes will be initialised if they have not already * been initialised. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the virtual function table belongs (it * is this pointer value that will subsequently be returned by the Object * astClass function). *- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstObjectVtab *object; /* Pointer to Object component of Vtab */ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */ /* Check the local error status. */ if ( !astOK ) return; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Initialize the component of the virtual function table used by the parent class. */ astInitMappingVtab( (AstMappingVtab *) vtab, name ); /* Store a unique "magic" value in the virtual function table. This will be used (by astIsASphMap) to determine if an object belongs to this class. We can conveniently use the address of the (static) class_check variable to generate this unique value. */ vtab->id.check = &class_check; vtab->id.parent = &(((AstMappingVtab *) vtab)->id); /* Initialise member function pointers. */ /* ------------------------------------ */ /* Store pointers to the member functions (implemented here) that provide virtual methods for this class. */ vtab->ClearUnitRadius = ClearUnitRadius; vtab->SetUnitRadius = SetUnitRadius; vtab->GetUnitRadius = GetUnitRadius; vtab->TestUnitRadius = TestUnitRadius; vtab->ClearPolarLong = ClearPolarLong; vtab->SetPolarLong = SetPolarLong; vtab->GetPolarLong = GetPolarLong; vtab->TestPolarLong = TestPolarLong; /* Save the inherited pointers to methods that will be extended, and replace them with pointers to the new member functions. */ object = (AstObjectVtab *) vtab; mapping = (AstMappingVtab *) vtab; parent_clearattrib = object->ClearAttrib; object->ClearAttrib = ClearAttrib; parent_getattrib = object->GetAttrib; object->GetAttrib = GetAttrib; parent_setattrib = object->SetAttrib; object->SetAttrib = SetAttrib; parent_testattrib = object->TestAttrib; object->TestAttrib = TestAttrib; parent_transform = mapping->Transform; mapping->Transform = Transform; /* Store replacement pointers for methods which will be over-ridden by new member functions implemented here. */ object->Equal = Equal; mapping->MapMerge = MapMerge; /* Declare the class dump, copy and delete functions.*/ astSetDump( vtab, Dump, "SphMap", "Cartesian to Spherical mapping" ); astSetCopy( (AstObjectVtab *) vtab, Copy ); astSetDelete( (AstObjectVtab *) vtab, Delete ); /* If we have just initialised the vtab for the current class, indicate that the vtab is now initialised, and store a pointer to the class identifier in the base "object" level of the vtab. */ if( vtab == &class_vtab ) { class_init = 1; astSetVtabClassIdentifier( vtab, &(vtab->id) ); } } static int MapMerge( AstMapping *this, int where, int series, int *nmap, AstMapping ***map_list, int **invert_list, int *status ) { /* * Name: * MapMerge * Purpose: * Simplify a sequence of Mappings containing a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * int MapMerge( AstMapping *this, int where, int series, int *nmap, * AstMapping ***map_list, int **invert_list, int *status, int *status ) * Class Membership: * SphMap method (over-rides the protected astMapMerge method * inherited from the Mapping class). * Description: * This function attempts to simplify a sequence of Mappings by * merging a nominated SphMap in the sequence with its neighbours, * so as to shorten the sequence if possible. * * In many cases, simplification will not be possible and the * function will return -1 to indicate this, without further * action. * * In most cases of interest, however, this function will either * attempt to replace the nominated SphMap with one which it * considers simpler, or to merge it with the Mappings which * immediately precede it or follow it in the sequence (both will * normally be considered). This is sufficient to ensure the * eventual simplification of most Mapping sequences by repeated * application of this function. * * In some cases, the function may attempt more elaborate * simplification, involving any number of other Mappings in the * sequence. It is not restricted in the type or scope of * simplification it may perform, but will normally only attempt * elaborate simplification in cases where a more straightforward * approach is not adequate. * Parameters: * this * Pointer to the nominated SphMap which is to be merged with * its neighbours. This should be a cloned copy of the SphMap * pointer contained in the array element "(*map_list)[where]" * (see below). This pointer will not be annulled, and the * SphMap it identifies will not be modified by this function. * where * Index in the "*map_list" array (below) at which the pointer * to the nominated SphMap resides. * series * A non-zero value indicates that the sequence of Mappings to * be simplified will be applied in series (i.e. one after the * other), whereas a zero value indicates that they will be * applied in parallel (i.e. on successive sub-sets of the * input/output coordinates). * nmap * Address of an int which counts the number of Mappings in the * sequence. On entry this should be set to the initial number * of Mappings. On exit it will be updated to record the number * of Mappings remaining after simplification. * map_list * Address of a pointer to a dynamically allocated array of * Mapping pointers (produced, for example, by the astMapList * method) which identifies the sequence of Mappings. On entry, * the initial sequence of Mappings to be simplified should be * supplied. * * On exit, the contents of this array will be modified to * reflect any simplification carried out. Any form of * simplification may be performed. This may involve any of: (a) * removing Mappings by annulling any of the pointers supplied, * (b) replacing them with pointers to new Mappings, (c) * inserting additional Mappings and (d) changing their order. * * The intention is to reduce the number of Mappings in the * sequence, if possible, and any reduction will be reflected in * the value of "*nmap" returned. However, simplifications which * do not reduce the length of the sequence (but improve its * execution time, for example) may also be performed, and the * sequence might conceivably increase in length (but normally * only in order to split up a Mapping into pieces that can be * more easily merged with their neighbours on subsequent * invocations of this function). * * If Mappings are removed from the sequence, any gaps that * remain will be closed up, by moving subsequent Mapping * pointers along in the array, so that vacated elements occur * at the end. If the sequence increases in length, the array * will be extended (and its pointer updated) if necessary to * accommodate any new elements. * * Note that any (or all) of the Mapping pointers supplied in * this array may be annulled by this function, but the Mappings * to which they refer are not modified in any way (although * they may, of course, be deleted if the annulled pointer is * the final one). * invert_list * Address of a pointer to a dynamically allocated array which, * on entry, should contain values to be assigned to the Invert * attributes of the Mappings identified in the "*map_list" * array before they are applied (this array might have been * produced, for example, by the astMapList method). These * values will be used by this function instead of the actual * Invert attributes of the Mappings supplied, which are * ignored. * * On exit, the contents of this array will be updated to * correspond with the possibly modified contents of the * "*map_list" array. If the Mapping sequence increases in * length, the "*invert_list" array will be extended (and its * pointer updated) if necessary to accommodate any new * elements. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Returned Value: * If simplification was possible, the function returns the index * in the "map_list" array of the first element which was * modified. Otherwise, it returns -1 (and makes no changes to the * arrays supplied). * Notes: * - A value of -1 will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. */ /* Local Variables: */ AstMapping *new; /* Pointer to replacement Mapping */ AstMatrixMap *mm; /* Pointer to MatrixMap */ AstWinMap *wm; /* The new WinMap */ const char *class; /* Pointer to Mapping class string */ double absval; /* Absolute value fo each diagonal element */ double diag[ 3 ]; /* The diagonal matrix elements */ double polarlong; /* Value of PolarLong attribute */ int imap1; /* Index of first SphMap */ int imap2; /* Index of second SphMap */ int imap; /* Loop counter for Mappings */ int result; /* Result value to return */ int simpler; /* Mappings simplified? */ /* Initialise the returned result. */ result = -1; /* Check the global error status. */ if ( !astOK ) return result; /* Further initialisation. */ new = NULL; simpler = 0; /* We will only handle the case of SphMaps in series and will consider merging the nominated SphMap with the Mapping which follows it. Check that there is such a Mapping. */ if ( series && ( ( where + 1 ) < *nmap ) ) { /* Obtain the indices of the two potential SphMaps to be merged. */ imap1 = where; imap2 = where + 1; /* Obtain the Class string of the second Mapping and determine if it is a SphMap. */ class = astGetClass( ( *map_list )[ imap2 ] ); if ( astOK && !strcmp( class, "SphMap" ) ) { /* Check if the first SphMap is applied in the inverse direction and the second in the forward direction. This combination can be simplified if the PolarLongitude attributes are equal.. */ if( ( *invert_list )[ imap1 ] && !( *invert_list )[ imap2 ] ) { simpler = astEQUAL( astGetPolarLong( ( *map_list )[ imap1 ] ), astGetPolarLong( ( *map_list )[ imap2 ] ) ); /* If the first SphMap is applied in the forward direction and the second in the inverse direction, the combination can only be simplified if the input vectors to the first SphMap all have unit length (as indicated by the UnitRadius attribute). */ } else if( !( *invert_list )[ imap1 ] && ( *invert_list )[ imap2 ] ) { simpler = astGetUnitRadius( ( *map_list )[ imap1 ] ); } } /* If the two SphMaps can be simplified, create a UnitMap to replace them. */ if ( simpler ) { new = (AstMapping *) astUnitMap( 2, "", status ); /* Annul the pointers to the SphMaps. */ if ( astOK ) { ( *map_list )[ imap1 ] = astAnnul( ( *map_list )[ imap1 ] ); ( *map_list )[ imap2 ] = astAnnul( ( *map_list )[ imap2 ] ); /* Insert the pointer to the replacement Mapping and initialise its invert flag. */ ( *map_list )[ imap1 ] = new; ( *invert_list )[ imap1 ] = 0; /* Loop to close the resulting gap by moving subsequent elements down in the arrays. */ for ( imap = imap2 + 1; imap < *nmap; imap++ ) { ( *map_list )[ imap - 1 ] = ( *map_list )[ imap ]; ( *invert_list )[ imap - 1 ] = ( *invert_list )[ imap ]; } /* Clear the vacated elements at the end. */ ( *map_list )[ *nmap - 1 ] = NULL; ( *invert_list )[ *nmap - 1 ] = 0; /* Decrement the Mapping count and return the index of the first modified element. */ ( *nmap )--; result = imap1; } } } /* Another possible simplification is if the nominated Mapping is an inverted SphMap followed in series by a ZoomMap or diagonal MatrixMap that has diagonal elements of equal magnitude, which is then followed by a non-inverted SphMap. This is equivalent to a 3D rotation of a pair of (longitude,latitude) angles. The MatrixMap/ZoomMap may magnify the radius vector, but this will not alter the angles. Any difference in signs amongst the diagonal elements will cause a reflection or reversal of the corresponbding angles, which can be represented by a WinMap. We do not need to consider the other possibility (that the nominated SphMap is the *last* Mapping in such a sequence of three), since we will already have discovered such a sequence on an earlier invocation of this function. */ if( series && !simpler && ( *invert_list )[ where ] && where + 2 < *nmap ) { /* Check the third Mapping is a non-inverted SphMap. */ class = astGetClass( ( *map_list )[ where + 2 ] ); if( astOK && !strcmp( class, "SphMap" ) && !( *invert_list )[ where + 2 ] ) { /* Check the second Mapping is a ZoomMap, or a diagonal MatrixMap that has diagonal elements of equal magnitude. Since the Mapping is sandwiched between the two SphMaps, we know it must have 3 inputs and 3 outputs. Record the corresponding diagonal values. The state of the Invert flag does not matter since it will only affect the degree to which the radius vector is magnified - it will not change the signs of any diagonal elements. */ class = astGetClass( ( *map_list )[ where + 1 ] ); if( astOK && !strcmp( class, "ZoomMap" ) ) { diag[ 0 ] = astGetZoom( ( *map_list )[ where + 1 ] ); if( diag[ 0 ] != 0.0 ) { diag[ 1 ] = diag[ 0 ]; diag[ 2 ] = diag[ 0 ]; } else { class = NULL; } } else if( astOK && !strcmp( class, "MatrixMap" ) ) { mm = (AstMatrixMap *) ( *map_list )[ where + 1 ]; if( mm->form == 1 && mm->f_matrix ) { diag[ 0 ] = mm->f_matrix[ 0 ]; if( diag[ 0 ] != 0.0 ) { diag[ 1 ] = mm->f_matrix[ 1 ]; diag[ 2 ] = mm->f_matrix[ 2 ]; absval = fabs( diag[ 0 ] ); if( !astEQUAL( fabs( diag[ 1 ] ), absval ) || !astEQUAL( fabs( diag[ 2 ] ), absval ) ) { class = NULL; } } else { class = NULL; } } else { class = NULL; } } else { class = NULL; } } else { class = NULL; } /* We can only make changes if above conditions were met. */ if( class ) { /* Create a WinMap that modifies the (longitude,latitude) values, initially with undefined corners. */ wm = astWinMap( 2, NULL, NULL, NULL, NULL, "", status ); /* Store appropriate scales and offsets in the WinMap. These just depend on the signs of the matrix diagonal elements since we know the magnitudes of these elements are all equal. */ if( diag[ 0 ] < 0.0 ) { if( diag[ 1 ] < 0.0 ) { wm->a[ 0 ] = AST__DPI; wm->b[ 0 ] = -1.0; } else { wm->a[ 0 ] = AST__DPI; wm->b[ 0 ] = 1.0; } } else { if( diag[ 1 ] < 0.0 ) { wm->a[ 0 ] = 0.0; wm->b[ 0 ] = -1.0; } else { wm->a[ 0 ] = 0.0; wm->b[ 0 ] = 1.0; } } if( diag[ 2 ] < 0.0 ) { wm->a[ 1 ] = 0.0; wm->b[ 1 ] = -1.0; } else { wm->a[ 1 ] = 0.0; wm->b[ 1 ] = 1.0; } /* We are aiming to replace the supplied (SphMap,MatrixMap,SphMap) combination with (WinMap,SphMap,SphMap), leaving us with an inverted and non-inverted SphMap side by side. This is on the understanding that a subsequent call to this function will combine these two adjacent SphMaps into a UnitMap. But this will only happen if the adjacent SphMaps have equal values for their PolarLong attributes. The change of (SphMap,MatrixMap) to (WinMap,SphMap) will change the value of the PolarLong attribute in the first SphMap, so we need to work out this changed value and check that it is the same as the PolarLong value of the second SphMap. If they are different, there is no point making any changes since the two SphMaps cannot be merged into a UnitMap. So get the PolarLong value from the supplied first SphMap. */ polarlong = astGetPolarLong( ( *map_list )[ where ] ); /* Modified the PolarLong value to take account of the change from (SphMap,MatrixMap) to (WinMap,SphMap). */ polarlong = wm->a[ 0 ] + wm->b[ 0 ]*polarlong; /* Check this is the same as the PolarLong value in the second SphMap. */ if( astEQUAL( polarlong, astGetPolarLong( ( *map_list )[ where + 2 ] ) ) ) { /* All is good, so we can now change the supplied Mappings list. First change the PolarLong value in the first SphMap. */ astSetPolarLong( ( *map_list )[ where ], polarlong ); /* Annul The MatrixMap or ZoomMap. */ (void) astAnnul( ( *map_list )[ where + 1 ] ); /* Move the first SphMap to the slot left vacant by the annulled MatrixMap or ZoomMap. */ ( *map_list )[ where + 1 ] = ( *map_list )[ where ]; ( *invert_list )[ where + 1 ] = ( *invert_list )[ where ]; /* Store the new WinMap in the place of the SphMap. */ ( *map_list )[ where ] = astClone( wm ); ( *invert_list )[ where ] = 0; /* Return the index of the first modified element. */ result = where; } /* Free resources. */ wm = astAnnul( wm ); } } /* If an error occurred, clear the returned result. */ if ( !astOK ) result = -1; /* Return the result. */ return result; } static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { /* * Name: * SetAttrib * Purpose: * Set an attribute value for a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * void SetAttrib( AstObject *this, const char *setting ) * Class Membership: * SphMap member function (over-rides the astSetAttrib protected * method inherited from the Mapping class). * Description: * This function assigns an attribute value for a SphMap, the * attribute and its value being specified by means of a string of * the form: * * "attribute= value " * * Here, "attribute" specifies the attribute name and should be in * lower case with no white space present. The value to the right * of the "=" should be a suitable textual representation of the * value to be assigned and this will be interpreted according to * the attribute's data type. White space surrounding the value is * only significant for string attributes. * Parameters: * this * Pointer to the SphMap. * setting * Pointer to a null-terminated string specifying the new attribute * value. */ /* Local Variables: */ AstSphMap *this; /* Pointer to the SphMap structure */ double dval; /* Double precision attribute value */ int len; /* Length of setting string */ int ival; /* Int attribute value */ int nc; /* Number of characters read by astSscanf */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SphMap structure. */ this = (AstSphMap *) this_object; /* Obtain the length of the setting string. */ len = (int) strlen( setting ); /* UnitRadius */ /* ---------- */ if ( nc = 0, ( 1 == astSscanf( setting, "unitradius= %d %n", &ival, &nc ) ) && ( nc >= len ) ) { astSetUnitRadius( this, ival ); /* PolarLong */ /* --------- */ } else if ( nc = 0, ( 1 == astSscanf( setting, "polarlong= %lf %n", &dval, &nc ) ) && ( nc >= len ) ) { astSetPolarLong( this, dval ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { (*parent_setattrib)( this_object, setting, status ); } } static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { /* * Name: * TestAttrib * Purpose: * Test if a specified attribute value is set for a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * int TestAttrib( AstObject *this, const char *attrib, int *status, int *status ) * Class Membership: * SphMap member function (over-rides the astTestAttrib protected * method inherited from the Mapping class). * Description: * This function returns a boolean result (0 or 1) to indicate whether * a value has been set for one of a SphMap's attributes. * Parameters: * this * Pointer to the SphMap. * attrib * Pointer to a null-terminated string specifying the attribute * name. This should be in lower case with no surrounding white * space. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Returned Value: * One if a value has been set, otherwise zero. * Notes: * - A value of zero will be returned if this function is invoked * with the global status set, or if it should fail for any reason. */ /* Local Variables: */ AstSphMap *this; /* Pointer to the SphMap structure */ int result; /* Result value to return */ /* Initialise. */ result = 0; /* Check the global error status. */ if ( !astOK ) return result; /* Obtain a pointer to the SphMap structure. */ this = (AstSphMap *) this_object; /* UnitRadius */ /* ---------- */ if ( !strcmp( attrib, "unitradius" ) ) { result = astTestUnitRadius( this ); /* PolarLong */ /* --------- */ } else if ( !strcmp( attrib, "polarlong" ) ) { result = astTestPolarLong( this ); /* If the attribute is still not recognised, pass it on to the parent method for further interpretation. */ } else { result = (*parent_testattrib)( this_object, attrib, status ); } /* Return the result, */ return result; } static AstPointSet *Transform( AstMapping *this, AstPointSet *in, int forward, AstPointSet *out, int *status ) { /* * Name: * Transform * Purpose: * Apply a SphMap to transform a set of points. * Type: * Private function. * Synopsis: * #include "sphmap.h" * AstPointSet *Transform( AstMapping *this, AstPointSet *in, * int forward, AstPointSet *out, int *status, int *status ) * Class Membership: * SphMap member function (over-rides the astTransform protected * method inherited from the Mapping class). * Description: * This function takes a SphMap and a set of points encapsulated in a * PointSet and transforms the points from Cartesian coordinates to * spherical coordinates. * Parameters: * this * Pointer to the SphMap. * in * Pointer to the PointSet holding the input coordinate data. * forward * A non-zero value indicates that the forward coordinate transformation * should be applied, while a zero value requests the inverse * transformation. * out * Pointer to a PointSet which will hold the transformed (output) * coordinate values. A NULL value may also be given, in which case a * new PointSet will be created by this function. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Returned Value: * Pointer to the output (possibly new) PointSet. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. * - The number of coordinate values per point in the input PointSet must * match the number of coordinates for the SphMap being applied. * - If an output PointSet is supplied, it must have space for sufficient * number of points and coordinate values per point to accommodate the * result. Any excess space will be ignored. */ /* Local Variables: */ AstPointSet *result; /* Pointer to output PointSet */ AstSphMap *map; /* Pointer to SphMap to be applied */ double **ptr_in; /* Pointer to input coordinate data */ double **ptr_out; /* Pointer to output coordinate data */ int npoint; /* Number of points */ int point; /* Loop counter for points */ double *p0; /* Pointer to x axis value */ double *p1; /* Pointer to y axis value */ double *p2; /* Pointer to z axis value */ double *q0; /* Pointer to longitude value */ double *q1; /* Pointer to latitude value */ double mxerr; /* Largest value which is effectively zero */ double polarlong; /* Longitude at either pole */ double v[3]; /* Vector for a single point */ /* Check the global error status. */ if ( !astOK ) return NULL; /* Obtain a pointer to the SphMap. */ map = (AstSphMap *) this; /* Apply the parent mapping using the stored pointer to the Transform member function inherited from the parent Mapping class. This function validates all arguments and generates an output PointSet if necessary, but does not actually transform any coordinate values. */ result = (*parent_transform)( this, in, forward, out, status ); /* We will now extend the parent astTransform method by performing the calculations needed to generate the output coordinate values. */ /* Determine the numbers of points and coordinates per point from the input PointSet and obtain pointers for accessing the input and output coordinate values. */ npoint = astGetNpoint( in ); ptr_in = astGetPoints( in ); ptr_out = astGetPoints( result ); /* Determine whether to apply the forward or inverse mapping, according to the direction specified and whether the mapping has been inverted. */ if ( astGetInvert( map ) ) forward = !forward; /* Perform coordinate arithmetic. */ /* ------------------------------ */ if( astOK ){ /* First deal with forward mappings from Cartesian to Spherical. */ if( forward ){ /* Get the longitude to return at either pole. */ polarlong = astGetPolarLong( this ); /* Store pointers to the input Cartesian axes. */ p0 = ptr_in[ 0 ]; p1 = ptr_in[ 1 ]; p2 = ptr_in[ 2 ]; /* Store pointers to the output Spherical axes. */ q0 = ptr_out[ 0 ]; q1 = ptr_out[ 1 ]; /* Apply the mapping to every point. */ for( point = 0; point < npoint; point++ ){ if( *p0 != AST__BAD && *p1 != AST__BAD && *p2 != AST__BAD ){ v[0] = *p0; v[1] = *p1; v[2] = *p2; /* At either pole, return the longitude equal to PolarLong attribute. */ mxerr = fabs( 1000.0*v[ 2 ] )*DBL_EPSILON; if( fabs( v[ 0 ] ) < mxerr && fabs( v[ 1 ] ) < mxerr ) { if( v[ 2 ] < 0.0 ) { *(q0++) = polarlong; *(q1++) = -AST__DPIBY2; } else if( v[ 2 ] > 0.0 ) { *(q0++) = polarlong; *(q1++) = AST__DPIBY2; } else { *(q0++) = AST__BAD; *(q1++) = AST__BAD; } /* Otherwise use a SLALIB function to do the conversion (SLALIB always returns zero at either pole which is why we make the above check). */ } else { palDcc2s( v, q0++, q1++ ); } } else { *(q0++) = AST__BAD; *(q1++) = AST__BAD; } p0++; p1++; p2++; } /* Now deal with inverse mappings from Spherical to Cartesian. */ } else { /* Store pointers to the input Spherical axes. */ q0 = ptr_in[ 0 ]; q1 = ptr_in[ 1 ]; /* Store pointers to the output Cartesian axes. */ p0 = ptr_out[ 0 ]; p1 = ptr_out[ 1 ]; p2 = ptr_out[ 2 ]; /* Apply the mapping to every point. */ for( point = 0; point < npoint; point++ ){ if( *q0 != AST__BAD && *q1 != AST__BAD ){ palDcs2c( *q0, *q1, v ); *(p0++) = v[ 0 ]; *(p1++) = v[ 1 ]; *(p2++) = v[ 2 ]; } else { *(p0++) = AST__BAD; *(p1++) = AST__BAD; *(p2++) = AST__BAD; } q0++; q1++; } } } /* Return a pointer to the output PointSet. */ return result; } /* Functions which access class attributes. */ /* ---------------------------------------- */ /* Implement member functions to access the attributes associated with this class using the macros defined for this purpose in the "object.h" file. For a description of each attribute, see the class interface (in the associated .h file). */ /* UnitRadius */ /* ---------- */ /* *att++ * Name: * UnitRadius * Purpose: * SphMap input vectors lie on a unit sphere? * Type: * Public attribute. * Synopsis: * Integer (boolean). * Description: * This is a boolean attribute which indicates whether the * 3-dimensional vectors which are supplied as input to a SphMap * are known to always have unit length, so that they lie on a unit * sphere centred on the origin. * c If this condition is true (indicated by setting UnitRadius c non-zero), it implies that a CmpMap which is composed of a c SphMap applied in the forward direction followed by a similar c SphMap applied in the inverse direction may be simplified c (e.g. by astSimplify) to become a UnitMap. This is because the c input and output vectors will both have unit length and will c therefore have the same coordinate values. f If this condition is true (indicated by setting UnitRadius f non-zero), it implies that a CmpMap which is composed of a f SphMap applied in the forward direction followed by a similar f SphMap applied in the inverse direction may be simplified f (e.g. by AST_SIMPLIFY) to become a UnitMap. This is because the f input and output vectors will both have unit length and will f therefore have the same coordinate values. * * If UnitRadius is zero (the default), then although the output * vector produced by the CmpMap (above) will still have unit * length, the input vector may not have. This will, in general, * change the coordinate values, so it prevents the pair of SphMaps * being simplified. * Notes: * - This attribute is intended mainly for use when SphMaps are * involved in a sequence of Mappings which project (e.g.) a * dataset on to the celestial sphere. By regarding the celestial * sphere as a unit sphere (and setting UnitRadius to be non-zero) * it becomes possible to cancel the SphMaps present, along with * associated sky projections, when two datasets are aligned using * celestial coordinates. This often considerably improves * performance. * - Such a situations often arises when interpreting FITS data and * is handled automatically by the FitsChan class. * - The value of the UnitRadius attribute is used only to control * the simplification of Mappings and has no effect on the value of * the coordinates transformed by a SphMap. The lengths of the * input 3-dimensional Cartesian vectors supplied are always * ignored, even if UnitRadius is non-zero. * Applicability: * SphMap * All SphMaps have this attribute. *att-- */ astMAKE_CLEAR(SphMap,UnitRadius,unitradius,-1) astMAKE_GET(SphMap,UnitRadius,int,0,(this->unitradius == -1 ? 0 : this->unitradius)) astMAKE_SET(SphMap,UnitRadius,int,unitradius,( value ? 1 : 0 )) astMAKE_TEST(SphMap,UnitRadius,( this->unitradius != -1 )) /* PolarLong */ /* --------- */ /* *att++ * Name: * PolarLong * Purpose: * The longitude value to assign to either pole * Type: * Public attribute. * Synopsis: * Double precision. * Description: * This attribute holds the longitude value, in radians, to be * returned when a Cartesian position corresponding to either the north * or south pole is transformed into spherical coordinates. The * default value is zero. * Applicability: * SphMap * All SphMaps have this attribute. *att-- */ astMAKE_CLEAR(SphMap,PolarLong,polarlong,AST__BAD) astMAKE_GET(SphMap,PolarLong,double,0.0,(this->polarlong == AST__BAD ? 0.0 : this->polarlong)) astMAKE_SET(SphMap,PolarLong,double,polarlong,value) astMAKE_TEST(SphMap,PolarLong,( this->polarlong != AST__BAD )) /* Copy constructor. */ /* ----------------- */ static void Copy( const AstObject *objin, AstObject *objout, int *status ) { /* * Name: * Copy * Purpose: * Copy constructor for SphMap objects. * Type: * Private function. * Synopsis: * void Copy( const AstObject *objin, AstObject *objout, int *status, int *status, int *status ) * Description: * This function implements the copy constructor for SphMap objects. * Parameters: * objin * Pointer to the SphMap to be copied. * objout * Pointer to the SphMap being constructed. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. */ } /* Destructor. */ /* ----------- */ static void Delete( AstObject *obj, int *status ) { /* * Name: * Delete * Purpose: * Destructor for SphMap objects. * Type: * Private function. * Synopsis: * void Delete( AstObject *obj, int *status, int *status ) * Description: * This function implements the destructor for SphMap objects. * Parameters: * obj * Pointer to the SphMap to be deleted. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * Notes: * - This destructor does nothing and exists only to maintain a * one-to-one correspondence between destructors and copy * constructors. */ } /* Dump function. */ /* -------------- */ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { /* * Name: * Dump * Purpose: * Dump function for SphMap objects. * Type: * Private function. * Synopsis: * void Dump( AstObject *this, AstChannel *channel, int *status, int *status, int *status, int *status ) * Description: * This function implements the Dump function which writes out data * for the SphMap class to an output Channel. * Parameters: * this * Pointer to the SphMap whose data are being written. * channel * Pointer to the Channel to which the data are being written. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. * status * Pointer to the inherited status variable. */ /* Local Variables: */ AstSphMap *this; /* Pointer to the SphMap structure */ double dval; /* Double precision attribute value */ int ival; /* Integer value */ int set; /* Attribute value set? */ /* Check the global error status. */ if ( !astOK ) return; /* Obtain a pointer to the SphMap structure. */ this = (AstSphMap *) this_object; /* Write out values representing the instance variables for the SphMap class. Accompany these with appropriate comment strings, possibly depending on the values being written.*/ /* In the case of attributes, we first use the appropriate (private) Test... member function to see if they are set. If so, we then use the (private) Get... function to obtain the value to be written out. For attributes which are not set, we use the astGet... method to obtain the value instead. This will supply a default value (possibly provided by a derived class which over-rides this method) which is more useful to a human reader as it corresponds to the actual default attribute value. Since "set" will be zero, these values are for information only and will not be read back. */ /* UnitRadius. */ /* ------- */ set = TestUnitRadius( this, status ); ival = set ? GetUnitRadius( this, status ) : astGetUnitRadius( this ); if( ival ) { astWriteInt( channel, "UntRd", set, 0, ival, "All input vectors have unit length" ); } else { astWriteInt( channel, "UntRd", set, 0, ival, "Input vectors do not all have unit length" ); } /* PolarLong. */ /* ---------- */ set = TestPolarLong( this, status ); dval = set ? GetPolarLong( this, status ) : astGetPolarLong( this ); astWriteDouble( channel, "PlrLg", set, 1, dval, "Polar longitude (rad.s)" ); } /* Standard class functions. */ /* ========================= */ /* Implement the astIsASphMap and astCheckSphMap functions using the macros defined for this purpose in the "object.h" header file. */ astMAKE_ISA(SphMap,Mapping) astMAKE_CHECK(SphMap) AstSphMap *astSphMap_( const char *options, int *status, ...) { /* *++ * Name: c astSphMap f AST_SPHMAP * Purpose: * Create a SphMap. * Type: * Public function. * Synopsis: c #include "sphmap.h" c AstSphMap *astSphMap( const char *options, ... ) f RESULT = AST_SPHMAP( OPTIONS, STATUS ) * Class Membership: * SphMap constructor. * Description: * This function creates a new SphMap and optionally initialises * its attributes. * * A SphMap is a Mapping which transforms points from a * 3-dimensional Cartesian coordinate system into a 2-dimensional * spherical coordinate system (longitude and latitude on a unit * sphere centred at the origin). It works by regarding the input * coordinates as position vectors and finding their intersection * with the sphere surface. The inverse transformation always * produces points which are a unit distance from the origin * (i.e. unit vectors). * Parameters: c options f OPTIONS = CHARACTER * ( * ) (Given) c Pointer to a null-terminated string containing an optional c comma-separated list of attribute assignments to be used for c initialising the new SphMap. The syntax used is identical to c that for the astSet function and may include "printf" format c specifiers identified by "%" symbols in the normal way. f A character string containing an optional comma-separated f list of attribute assignments to be used for initialising the f new SphMap. The syntax used is identical to that for the f AST_SET routine. c ... c If the "options" string contains "%" format specifiers, then c an optional list of additional arguments may follow it in c order to supply values to be substituted for these c specifiers. The rules for supplying these are identical to c those for the astSet function (and for the C "printf" c function). f STATUS = INTEGER (Given and Returned) f The global status. * Returned Value: c astSphMap() f AST_SPHMAP = INTEGER * A pointer to the new SphMap. * Notes: * - The spherical coordinates are longitude (positive * anti-clockwise looking from the positive latitude pole) and * latitude. The Cartesian coordinates are right-handed, with the x * axis (axis 1) at zero longitude and latitude, and the z axis * (axis 3) at the positive latitude pole. * - At either pole, the longitude is set to the value of the * PolarLong attribute. * - If the Cartesian coordinates are all zero, then the longitude * and latitude are set to the value AST__BAD. * - A null Object pointer (AST__NULL) will be returned if this c function is invoked with the AST error status set, or if it f function is invoked with STATUS set to an error value, or if it * should fail for any reason. * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". * Status Handling: * The protected interface to this function includes an extra * parameter at the end of the parameter list descirbed above. This * parameter is a pointer to the integer inherited status * variable: "int *status". *-- */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSphMap *new; /* Pointer to new SphMap */ va_list args; /* Variable argument list */ /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SphMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSphMap( NULL, sizeof( AstSphMap ), !class_init, &class_vtab, "SphMap" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SphMap's attributes. */ va_start( args, status ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return a pointer to the new SphMap. */ return new; } AstSphMap *astSphMapId_( const char *options, ...) { /* * Name: * astSphMapId_ * Purpose: * Create a SphMap. * Type: * Private function. * Synopsis: * #include "sphmap.h" * AstSphMap *astSphMapId_( const char *options, ... ) * Class Membership: * SphMap constructor. * Description: * This function implements the external (public) interface to the * astSphMap constructor function. It returns an ID value (instead * of a true C pointer) to external users, and must be provided * because astSphMap_ has a variable argument list which cannot be * encapsulated in a macro (where this conversion would otherwise * occur). * * The variable argument list also prevents this function from * invoking astSphMap_ directly, so it must be a re-implementation * of it in all respects, except for the final conversion of the * result to an ID value. * Parameters: * As for astSphMap_. * Returned Value: * The ID value associated with the new SphMap. */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSphMap *new; /* Pointer to new SphMap */ va_list args; /* Variable argument list */ int *status; /* Pointer to inherited status value */ /* Get a pointer to the inherited status value. */ status = astGetStatusPtr; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(NULL); /* Check the global status. */ if ( !astOK ) return NULL; /* Initialise the SphMap, allocating memory and initialising the virtual function table as well if necessary. */ new = astInitSphMap( NULL, sizeof( AstSphMap ), !class_init, &class_vtab, "SphMap" ); /* If successful, note that the virtual function table has been initialised. */ if ( astOK ) { class_init = 1; /* Obtain the variable argument list and pass it along with the options string to the astVSet method to initialise the new SphMap's attributes. */ va_start( args, options ); astVSet( new, options, NULL, args ); va_end( args ); /* If an error occurred, clean up by deleting the new object. */ if ( !astOK ) new = astDelete( new ); } /* Return an ID value for the new SphMap. */ return astMakeId( new ); } AstSphMap *astInitSphMap_( void *mem, size_t size, int init, AstSphMapVtab *vtab, const char *name, int *status ) { /* *+ * Name: * astInitSphMap * Purpose: * Initialise a SphMap. * Type: * Protected function. * Synopsis: * #include "sphmap.h" * AstSphMap *astInitSphMap( void *mem, size_t size, int init, * AstSphMapVtab *vtab, const char *name ) * Class Membership: * SphMap initialiser. * Description: * This function is provided for use by class implementations to initialise * a new SphMap object. It allocates memory (if necessary) to accommodate * the SphMap plus any additional data associated with the derived class. * It then initialises a SphMap structure at the start of this memory. If * the "init" flag is set, it also initialises the contents of a virtual * function table for a SphMap at the start of the memory passed via the * "vtab" parameter. * Parameters: * mem * A pointer to the memory in which the SphMap is to be initialised. * This must be of sufficient size to accommodate the SphMap data * (sizeof(SphMap)) plus any data used by the derived class. If a value * of NULL is given, this function will allocate the memory itself using * the "size" parameter to determine its size. * size * The amount of memory used by the SphMap (plus derived class data). * This will be used to allocate memory if a value of NULL is given for * the "mem" parameter. This value is also stored in the SphMap * structure, so a valid value must be supplied even if not required for * allocating memory. * init * A logical flag indicating if the SphMap's virtual function table is * to be initialised. If this value is non-zero, the virtual function * table will be initialised by this function. * vtab * Pointer to the start of the virtual function table to be associated * with the new SphMap. * name * Pointer to a constant null-terminated character string which contains * the name of the class to which the new object belongs (it is this * pointer value that will subsequently be returned by the astGetClass * method). * Returned Value: * A pointer to the new SphMap. * Notes: * - A null pointer will be returned if this function is invoked with the * global error status set, or if it should fail for any reason. *- */ /* Local Variables: */ AstSphMap *new; /* Pointer to new SphMap */ /* Check the global status. */ if ( !astOK ) return NULL; /* If necessary, initialise the virtual function table. */ if ( init ) astInitSphMapVtab( vtab, name ); /* Initialise. */ new = NULL; /* Initialise a Mapping structure (the parent class) as the first component within the SphMap structure, allocating memory if necessary. Specify that the Mapping should be defined in both the forward and inverse directions. */ new = (AstSphMap *) astInitMapping( mem, size, 0, (AstMappingVtab *) vtab, name, 3, 2, 1, 1 ); if ( astOK ) { /* Initialise the SphMap data. */ /* --------------------------- */ /* Are all input vectors of unit length? Store a value of -1 to indicate that no value has yet been set. This will cause a default value of 0 (no, i.e. input vectors are not all of unit length) to be used. */ new->unitradius = -1; new->polarlong = AST__BAD; } /* Return a pointer to the new SphMap. */ return new; } AstSphMap *astLoadSphMap_( void *mem, size_t size, AstSphMapVtab *vtab, const char *name, AstChannel *channel, int *status ) { /* *+ * Name: * astLoadSphMap * Purpose: * Load a SphMap. * Type: * Protected function. * Synopsis: * #include "sphmap.h" * AstSphMap *astLoadSphMap( void *mem, size_t size, * AstSphMapVtab *vtab, const char *name, * AstChannel *channel ) * Class Membership: * SphMap loader. * Description: * This function is provided to load a new SphMap using data read * from a Channel. It first loads the data used by the parent class * (which allocates memory if necessary) and then initialises a * SphMap structure in this memory, using data read from the input * Channel. * * If the "init" flag is set, it also initialises the contents of a * virtual function table for a SphMap at the start of the memory * passed via the "vtab" parameter. * Parameters: * mem * A pointer to the memory into which the SphMap is to be * loaded. This must be of sufficient size to accommodate the * SphMap data (sizeof(SphMap)) plus any data used by derived * classes. If a value of NULL is given, this function will * allocate the memory itself using the "size" parameter to * determine its size. * size * The amount of memory used by the SphMap (plus derived class * data). This will be used to allocate memory if a value of * NULL is given for the "mem" parameter. This value is also * stored in the SphMap structure, so a valid value must be * supplied even if not required for allocating memory. * * If the "vtab" parameter is NULL, the "size" value is ignored * and sizeof(AstSphMap) is used instead. * vtab * Pointer to the start of the virtual function table to be * associated with the new SphMap. If this is NULL, a pointer * to the (static) virtual function table for the SphMap class * is used instead. * name * Pointer to a constant null-terminated character string which * contains the name of the class to which the new object * belongs (it is this pointer value that will subsequently be * returned by the astGetClass method). * * If the "vtab" parameter is NULL, the "name" value is ignored * and a pointer to the string "SphMap" is used instead. * Returned Value: * A pointer to the new SphMap. * Notes: * - A null pointer will be returned if this function is invoked * with the global error status set, or if it should fail for any * reason. *- */ #define KEY_LEN 50 /* Maximum length of a keyword */ /* Local Variables: */ astDECLARE_GLOBALS /* Pointer to thread-specific global data */ AstSphMap *new; /* Pointer to the new SphMap */ /* Initialise. */ new = NULL; /* Check the global error status. */ if( !astOK ) return new; /* Get a pointer to the thread specific global data structure. */ astGET_GLOBALS(channel); /* If a NULL virtual function table has been supplied, then this is the first loader to be invoked for this SphMap. In this case the SphMap belongs to this class, so supply appropriate values to be passed to the parent class loader (and its parent, etc.). */ if ( !vtab ) { size = sizeof( AstSphMap ); vtab = &class_vtab; name = "SphMap"; /* If required, initialise the virtual function table for this class. */ if ( !class_init ) { astInitSphMapVtab( vtab, name ); class_init = 1; } } /* Invoke the parent class loader to load data for all the ancestral classes of the current one, returning a pointer to the resulting partly-built SphMap. */ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name, channel ); if ( astOK ) { /* Read input data. */ /* ================ */ /* Request the input Channel to read all the input data appropriate to this class into the internal "values list". */ astReadClassData( channel, "SphMap" ); /* Now read each individual data item from this list and use it to initialise the appropriate instance variable(s) for this class. */ /* In the case of attributes, we first read the "raw" input value, supplying the "unset" value as the default. If a "set" value is obtained, we then use the appropriate (private) Set... member function to validate and set the value properly. */ /* UnitRadius. */ /* ----------- */ new->unitradius = astReadInt( channel, "untrd", -1 ); if ( TestUnitRadius( new, status ) ) SetUnitRadius( new, new->unitradius, status ); /* PolarLong. */ /* ---------- */ new->polarlong = astReadDouble( channel, "plrlg", AST__BAD ); if ( TestPolarLong( new, status ) ) SetPolarLong( new, new->polarlong, status ); } /* If an error occurred, clean up by deleting the new SphMap. */ if ( !astOK ) new = astDelete( new ); /* Return the new SphMap pointer. */ return new; } /* Virtual function interfaces. */ /* ============================ */ /* These provide the external interface to the virtual functions defined by this class. Each simply checks the global error status and then locates and executes the appropriate member function, using the function pointer stored in the object's virtual function table (this pointer is located using the astMEMBER macro defined in "object.h"). Note that the member function may not be the one defined here, as it may have been over-ridden by a derived class. However, it should still have the same interface. */ ./ast-7.3.3/xmlchan.c0000644000175000017500000170374212262533650012756 0ustar olesoles/* *class++ * Name: * XmlChan * Purpose: * I/O Channel using XML to represent Objects. * Constructor Function: c astXmlChan f AST_XMLCHAN * Description: * A XmlChan is a specialised form of Channel which supports XML I/O * operations. Writing an Object to an XmlChan (using c astWrite) will, if the Object is suitable, generate an f AST_WRITE) will, if the Object is suitable, generate an * XML description of that Object, and reading from an XmlChan will * create a new Object from its XML description. * * Normally, when you use an XmlChan, you should provide "source" c and "sink" functions which connect it to an external data store c by reading and writing the resulting XML text. These functions f and "sink" routines which connect it to an external data store f by reading and writing the resulting XML text. These routines * should perform any conversions needed between external character c encodings and the internal ASCII encoding. If no such functions f encodings and the internal ASCII encoding. If no such routines * are supplied, a Channel will read from standard input and write * to standard output. * * Alternatively, an XmlChan can be told to read or write from * specific text files using the SinkFile and SourceFile attributes, * in which case no sink or source function need be supplied. * Inheritance: * The XmlChan class inherits from the Channel class. * Attributes: * In addition to those attributes common to all Channels, every * XmlChan also has the following attributes: * * - XmlFormat: System for formatting Objects as XML * - XmlLength: Controls output buffer length * - XmlPrefix: The namespace prefix to use when writing * Functions: c The XmlChan class does not define any new functions beyond those f The XmlChan class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 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 General Public Licence as * published by the Free Software Foundation; either version 2 of * the Licence, 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 General Public Licence for more details. * * You should have received a copy of the GNU General Public Licence * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (Starlink) * History: * 10-OCT-2003 (DSB): * Original version. * 6-FEB-2004 (DSB): * Added XmlPrefix and XmlFormat attributes. * 10-FEB-2004 (DSB): * - Added debug conditional code to keep track of memory leaks. * - Fixed bug which prevented more than 1 object being read from * an XmlChan. * 7-DEC-2005 (DSB): * Free memory allocated by calls to astReadString. * 12-FEB-2010 (DSB): * Represent AST__BAD externally using the string "". *class-- * Further STC work: * - Speed up general STC processing (a lot of time seems to be spent * simplifying things) * - Document (including a complete description of what is and is not * supported in the reference docs for the XmlFormat attribute). * - Produce a schema describing the format which can in fact be read by * AST. * - Look at Jonathan McDowell's mini-STC schema (also STC stuff in * spectral data model) * - Web services. Read only: test STCs for overlap, test points for * inclusion/exclusion, plot a mask over an image, verification (can AST * read it & does it generate warnings?). Read/Write: convert FITS to STC, * transform STC into a new coord system. * - Add support for writing as well as reading * - Modify Stc... constructors to check that the supplied Frame is suitable. * - What about multiple AstroCoordFrames and AstroCoordAreas in a STC? * - Add support for generic CoordFrames * - What should be done with pixel coords info within STC? * - Extend coverage (e.g. to 3D space frames, etc) */ /* Module Macros. */ /* ============== */ /* Set the name of the class we are implementing. This indicates to the header files that define class interfaces that they should make "protected" symbols available. */ #define astCLASS XmlChan /* The XML element name used to store an AST attribute setting */ #define ATTR "_attribute" /* The XML element name used for an AST "isa" element */ #define ISA "_isa" /* The XML attribute name which holds the name of the AST class which defines the item contained in the element. */ #define DEFINEDBY "definedby" /* The XML attribute name which holds the name of the AST attribute */ #define NAME "name" /* The XML attribute name which holds the value of the AST attribute */ #define VALUE "value" /* The XML attribute name which indicates if the AST attribute value is a default value. */ #define DEFAULT "default" /* The XML attribute name which indicates if the AST attribute value was originally a string value. */ #define QUOTED "quoted" /* The XML attribute name which holds a description of the AST attribute. */ #define DESC "desc" /* The XML attribute name which holds the label associated with an AST Object (if any). */ #define LABEL "label" /* A string used to indicate atrue attribute value */ #define TRUE "true" /* Format identifiers and strings */ #define UNKNOWN_FORMAT -1 #define NATIVE_FORMAT 0 #define QUOTED_FORMAT 1 #define IVOA_FORMAT 2 #define MAX_FORMAT 2 #define UNKNOWN_STRING "UNKNOWN" #define NATIVE_STRING "NATIVE" #define QUOTED_STRING "QUOTED" #define IVOA_STRING "IVOA" /* Values representing message severities. */ #define WARNING 0 #define FAILURE 1 #define RESET 2 /* Known IVOA namespaces. When a new name is added, update the FindIVOAClass function. */ #define STC_URI "urn:nvo-stc" /* Known IVOA Classes and attributes. When a new name is added, it may be necessary to update the FindIVOAClass function. */ #define STC_RESOURCE_PROFILE "STCResourceProfile" #define SEARCH_LOCATION "SearchLocation" #define OBSERVATION_LOCATION "ObservationLocation" #define OBSERVATORY_LOCATION "ObservatoryLocation" #define CATALOG_ENTRY_LOCATION "CatalogEntryLocation" #define OBS_DATA_LOCATION "ObsDataLocation" #define ASTRO_COORD_SYSTEM "AstroCoordSystem" #define ASTRO_COORD_AREA "AstroCoordArea" #define ASTRO_COORDS "AstroCoords" #define TIME_FRAME "TimeFrame" #define SPACE_FRAME "SpaceFrame" #define SPECTRAL_FRAME "SpectralFrame" #define REDSHIFT_FRAME "RedshiftFrame" #define DOPPLER_DEFINITION "DopplerDefinition" /* Returns string "an" or "a" depending on whether the first character of the supplied string is a vowel or not. */ #define ANA(t) (t?(strchr("AaEeIiOoUu",t[0])?"an":"a"):"") /* String used to represent AST__BAD externally. */ #define BAD_STRING "" /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "frame.h" /* Coordinate Frames */ #include "timeframe.h" /* Time coordinate Frames */ #include "cmpframe.h" /* Coordinate Frames */ #include "skyframe.h" /* Celestial coordinate Frames */ #include "specframe.h" /* Spectral coordinate Frames */ #include "region.h" /* Regions within coordinate Frames */ #include "ellipse.h" /* Ellipses within coordinate Frames */ #include "pointlist.h" /* Points within coordinate Frames */ #include "polygon.h" /* Polygons within coordinate Frames */ #include "circle.h" /* Circles within coordinate Frames */ #include "keymap.h" /* Mapping of keys to values */ #include "channel.h" /* Interface for parent class */ #include "xmlchan.h" /* Interface definition for this class */ #include "loader.h" /* Interface to the global loader */ #include "object.h" /* Base Object class */ #include "wcsmap.h" /* Angular conversion constants */ #include "xml.h" /* AST XML facilities */ #include "sofa.h" /* IAU SOFA functions */ #include "stcresourceprofile.h" /* IVOA StcResourceProfile class */ #include "stcsearchlocation.h" /* IVOA SearchLocation class */ #include "stccatalogentrylocation.h"/* IVOA CatalogEntryLocation class */ #include "stcobsdatalocation.h" /* IVOA ObsDataLocation class */ #include "nullregion.h" /* Null regions */ #include "interval.h" /* Axis intervals */ #include "box.h" /* Box regions */ #include "cmpregion.h" /* Compound regions */ #include "prism.h" /* Prism regions */ #include "unitmap.h" /* Unit Mappings */ #include "unit.h" /* Unit handling utilities */ #include "pal.h" /* slalib functions */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include /* Type Definitions */ /* ================ */ /* A type for functions which read an IVOA element and return a corresponding AST Object. */ typedef AstObject *(*IVOAReader)( AstXmlChan *, AstXmlElement *, int * ); /* A structure to hold the result of scanning the content of an IVOA element.*/ typedef struct IVOAScan { int n; /* Number of element names described by this structure */ int *count; /* Array holding number of each element name found */ AstXmlElement ***el; /* Array holding pointers to each element found */ } IVOAScan; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static int (* parent_getfull)( AstChannel *, int * ); static int (* parent_getcomment)( AstChannel *, int * ); static int (* parent_getindent)( AstChannel *, int * ); /* Text values used to represent XmlFormat values externally. These should be in the order defined by the associated constants above. */ static const char *xformat[3] = { NATIVE_STRING, QUOTED_STRING, IVOA_STRING }; /* Define macros for accessing each item of thread specific global data. */ #ifdef THREAD_SAFE /* Define how to initialise thread-specific globals. */ #define GLOBAL_inits \ globals->Class_Init = 0; \ globals->IsUsable_This = NULL; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->GetNextChar_C = NULL; \ globals->GetNextChar_Buf = NULL; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(XmlChan) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(XmlChan,Class_Init) #define class_vtab astGLOBAL(XmlChan,Class_Vtab) #define isusable_this astGLOBAL(XmlChan,IsUsable_This) #define getattrib_buff astGLOBAL(XmlChan,GetAttrib_Buff) #define getnextchar_c astGLOBAL(XmlChan,GetNextChar_C) #define getnextchar_buf astGLOBAL(XmlChan,GetNextChar_Buf) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* An XmlChan pointer use to communicate with the IsUsable function. */ static AstXmlChan *isusable_this = NULL; /* Buffer returned by GetAttrib. */ static char getattrib_buff[ 51 ]; /* Variables used in GetNextChar */ static char *getnextchar_c = NULL; /* Pointer to next character to read */ static char *getnextchar_buf = NULL; /* Pointer to previously read text */ /* Define the class virtual function table and its initialisation flag as static variables. */ static AstXmlChanVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External Interface Function Prototypes. */ /* ======================================= */ /* The following functions have public prototypes only (i.e. no protected prototypes), so we must provide local prototypes for use within this module. */ AstXmlChan *astXmlChanForId_( const char *(*)( void ), char *(*)( const char *(*)( void ), int * ), void (*)( const char * ), void (*)( void (*)( const char * ), const char *, int * ), const char *, ... ); AstXmlChan *astXmlChanId_( const char *(* source)( void ), void (* sink)( const char * ), const char *options, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstObject *AstroCoordSystemReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *MakeAstFromXml( AstXmlChan *, AstXmlElement *, int * ); static AstObject *ObsDataLocationReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *Read( AstChannel *, int * ); static AstObject *ReadObject( AstChannel *, const char *, AstObject *, int * ); static AstObject *RedshiftFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *SpaceFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *SpectralFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *StcMetadataReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *TimeFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstPointList *ObservatoryLocationReader( AstXmlChan *, AstXmlElement *, AstStcObsDataLocation *, int * ); static AstRegion *AllSkyReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *AstroCoordAreaReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstRegion *[4], int, AstKeyMap **, int * ); static AstRegion *BoxReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *CircleReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *ConstraintReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *ConvexReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *Coord2VecIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *Coord3VecIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *CoordScalarIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *EllipseReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *IntersectionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *NegationReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *PolygonReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *Position2DReader( AstXmlChan *, AstXmlElement *, AstFrame *, double *, AstKeyMap **, int * ); static AstRegion *PositionIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RedshiftIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RedshiftReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstKeyMap **, int * ); static AstRegion *StcRegionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RegionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *SpectralIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *SpectralReader( AstXmlChan *, AstXmlElement *, AstFrame *, double *, AstKeyMap **, int * ); static AstRegion *SphereReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *TimeIntervalReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, int * ); static AstRegion *TimeReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, double *, AstKeyMap **, int * ); static AstRegion *UnionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstSystemType RedshiftSys( AstXmlChan *, AstXmlElement *, char **, int, int * ); static AstSystemType SpecSys( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static AstXmlElement *FindAttribute( AstXmlChan *, const char *, int * ); static AstXmlElement *FindElement( AstXmlChan *, AstXmlElement *, const char *, int * ); static AstXmlElement *FindObject( AstXmlChan *, const char *, int * ); static AstXmlElement *MakePos2D( AstXmlChan *, AstXmlElement *, int * ); static AstXmlElement *ReadXmlText( AstXmlChan *, int * ); static AstXmlElement *Remove( AstXmlChan *, AstXmlElement *, int * ); static IVOAReader FindIVOAClass( AstXmlElement *, int *, int * ); static IVOAScan *FreeIVOAScan( IVOAScan *, int * ); static IVOAScan *ScanIVOAElement( AstXmlChan *, AstXmlElement *, int, const char *[], int[], int[], int * ); static char *ReadString( AstChannel *, const char *, const char *, int * ); static char *SourceWrap( const char *(*)( void ), int * ); static char GetNextChar( void *, int * ); static const char *FindNextIsA( AstXmlElement *, int, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetTag( AstXmlObject *, int, int * ); static double AstronTimeReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, int * ); static double AttrValueD( AstXmlChan *, AstXmlElement *, const char *, double, int * ); static double ElemValueD( AstXmlChan *, AstXmlElement *, double, int * ); static double Error2PAReader( AstXmlChan *, AstXmlElement *, double *, int * ); static double MakeMJD( AstTimeFrame *, double, int * ); static double PosAngleReader( AstXmlChan *, AstXmlElement *, int * ); static double ReadDouble( AstChannel *, const char *, double, int * ); static int AstroCoordsReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstRegion *[4], AstKeyMap **, int * ); static int AttrValueB( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static int AttrValueI( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static int ElemListD( AstXmlChan *, AstXmlElement *, int, double *, int * ); static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * ); static int GetComment( AstChannel *, int * ); static int GetFull( AstChannel *, int * ); static int GetIndent( AstChannel *, int * ); static int IsUsable( AstXmlElement *, int * ); static int ReadInt( AstChannel *, const char *, int, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int Use( AstXmlChan *, int, int, int * ); static int Ustrcmp( const char *, const char *, int * ); static int Ustrncmp( const char *, const char *, size_t, int * ); static int VertexReader( AstXmlChan *, AstXmlElement *, double *, double *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void FillAndLims( AstXmlChan *, AstXmlElement *, AstRegion *, int * ); static void OutputText( AstXmlChan *, const char *, int, int * ); static void ReCentreAnc( AstRegion *, int, AstKeyMap **, int * ); static void ReadClassData( AstChannel *, const char *, int * ); static void Report( AstXmlChan *, AstXmlElement *, int, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SinkWrap( void (*)( const char * ), const char *, int * ); static void WriteBegin( AstChannel *, const char *, const char *, int * ); static void WriteDouble( AstChannel *, const char *, int, int, double, const char *, int * ); static void WriteEnd( AstChannel *, const char *, int * ); static void WriteInt( AstChannel *, const char *, int, int, int, const char *, int * ); static void WriteIsA( AstChannel *, const char *, const char *, int * ); static void WriteObject( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); static void WriteString( AstChannel *, const char *, int, int, const char *, const char *, int * ); static AstTimeScaleType TimeScaleReader( AstXmlChan *, AstXmlElement *, int * ); static int TestXmlLength( AstXmlChan *, int * ); static void ClearXmlLength( AstXmlChan *, int * ); static void SetXmlLength( AstXmlChan *, int, int * ); static int GetXmlLength( AstXmlChan *, int * ); static int TestXmlFormat( AstXmlChan *, int * ); static void ClearXmlFormat( AstXmlChan *, int * ); static void SetXmlFormat( AstXmlChan *, int, int * ); static int GetXmlFormat( AstXmlChan *, int * ); static int TestXmlPrefix( AstXmlChan *, int * ); static void ClearXmlPrefix( AstXmlChan *, int * ); static void SetXmlPrefix( AstXmlChan *, const char *, int * ); static const char * GetXmlPrefix( AstXmlChan *, int * ); /* Member functions. */ /* ================= */ static AstRegion *AllSkyReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, int *status ){ /* * Name: * AllSkyReader * Purpose: * Make an AST Region from an IVOA AllSky element. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * AstRegion *AllSkyReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, int *status ) * Class Membership: * XmlChan member function. * Description: * This function makes a new AST Region from the supplied IVOA * AllSky element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AllSky element. * frm * Pointer to the 2D Frame in which the returned Region should be * defined. If the Unit attribute is not set, this function will * set it to the value supplied in "unit" before returning. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new Region. */ /* Local Variables: */ AstRegion *new; /* Pointer to returned Region */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Create a negated NullRegion (this is a boundless Region which includes all points in the Frame). */ new = (AstRegion *) astNullRegion( frm, NULL, "negated=1", status ); /* Get any fill factor from the element and assign to the returned Region. */ FillAndLims( this, elem, new, status ); /* Annul any returned Frame if an error has occurred. */ if( !astOK ) new = astAnnul( new ); /* Return the pointer to the new Region. */ return new; } static AstRegion *AstroCoordAreaReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, AstRegion *uncs[4], int nanc, AstKeyMap **ancs, int *status ) { /* * Name: * AstroCoordAreaReader * Purpose: * Make an AST Region from an IVOA AstroCoordArea element. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * AstRegion *AstroCoordAreaReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, AstRegion *uncs[4], * int nanc, AstKeyMap **ancs, int *status ) * Class Membership: * XmlChan member function. * Description: * This function makes a new AST Region from the supplied IVOA * AstroCoordArea element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AstroCoordArea element. May be NULL, in * which case a NullRegion is returned. * frm * The Frame in which the returned Region is to be defined. If * Units or reference values (Epoch, RestFreq, RefRA, etc) are not set * for any axes, then they will be set by this function if possible. * uncs * Array holding pointers to the uncertainty Regions to be associated * with each of the four STC domains (space, time, spectral, redshift). * NULL should be suppied in any element for which no uncertainty is * available. * nanc * Number of KeyMap pointers stored in "ancs" * ancs * Pointer to an array of "nanc" elements, each being a pointer to * a KeyMap. Each one describes the ancilary information in an * AstroCoords element associated with the AstroCoordsArea decribed * by "region". Each KeyMap has elements with keys AST__STCERROR, * AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE each of * which holds a pointer to a Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new Region. */ /* Local Variables: */ AstRegion *r; AstFrame *cfrm; AstFrame *fr; AstFrame *pfrm; AstFrame *red_frame; AstFrame *space_frame; AstFrame *spec_frame; AstFrameSet *fs; AstMapping *map; AstObject *o; AstRegion **red_list; AstRegion **spec_list; AstRegion **space_list; AstRegion **time_list; AstRegion *new; AstRegion *reg; AstRegion *rred; AstRegion *rspec; AstRegion *rspace; AstRegion *rtime; AstRegion *sum; AstRegion *tmp; AstTimeFrame *time_frame; IVOAScan *scan; char *decset; char *raset; char buff[ DBL_DIG + 30 ]; char setting[ 100 ]; const char *dom; const char *id; const char *names[4]; const char *name; const char *old_units; const char *text; double decref; double lbnd[2]; double raref; double space_val[2]; double spec_val; double time_val; double ubnd[2]; int i; int ianc; int ired; int ispace; int ispec; int itime; int k; int l; int max[4]; int min[4]; int nax; int nred; int nspace; int nspec; int ntime; int paxis; static const char *key[ 5 ] = { AST__STCERROR, AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE }; /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If null AstroCoordArea element has been supplied, return a NullRegion. */ if( !elem ) { new = (AstRegion *) astNullRegion( frm, NULL, "", status ); /* Otherwise, create a Region of suitable class. */ } else { /* First identify the individual Frames within the supplied Frame. Current implementation for spatial axes is limited to celestial longitude and latitude. */ space_frame = NULL; spec_frame = NULL; red_frame = NULL; time_frame = NULL; nax = astGetNaxes( frm ); for( i = 0; i < nax; i++ ) { astPrimaryFrame( frm, i, &pfrm, &paxis ); dom = astGetDomain( pfrm ); if( !strcmp( dom, "SKY" ) ) { if( !space_frame ) { space_frame = astClone( pfrm ); } else if( pfrm != space_frame) { Report( this, elem, FAILURE, "contains more than 2 spatial axes", status ); } } else if( !strcmp( dom, "TIME" ) ) { if( !time_frame ) { if( astIsATimeFrame( pfrm ) ) { time_frame = (AstTimeFrame *) astClone( pfrm ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( pfrm ) ); } } else { Report( this, elem, FAILURE, "contains more than 1 time axis", status ); } } else if( !strcmp( dom, "SPECTRUM" ) ) { if( !spec_frame ) { spec_frame = astClone( pfrm ); } else { Report( this, elem, FAILURE, "contains more than 1 spectral axis", status ); } } else if( !strcmp( dom, "REDSHIFT" ) ) { if( !red_frame ) { red_frame = astClone( pfrm ); } else { Report( this, elem, FAILURE, "contains more than 1 redshift axis", status ); } } else { Report( this, elem, FAILURE, "contains axes for an unsupported domain", status ); } pfrm = astAnnul( pfrm ); } /* Search the supplied element for the required sub-elements. */ names[ 0 ] = "Sphere|PositionInterval|Region"; names[ 1 ] = "TimeInterval"; names[ 2 ] = "SpectralInterval"; names[ 3 ] = "RedshiftInterval"; min[ 0 ] = 0; min[ 1 ] = 0; min[ 2 ] = 0; min[ 3 ] = 0; max[ 0 ] = INT_MAX; max[ 1 ] = INT_MAX; max[ 2 ] = INT_MAX; max[ 3 ] = INT_MAX; scan = ScanIVOAElement( this, elem, 4, names, min, max, status ); /* If succesfull.. */ if( scan ) { /* Create Regions for all the SpatialIntervals found in the supplied element. */ space_val[ 0 ] = AST__BAD; space_val[ 1 ] = AST__BAD; nspace = scan->count[ 0 ]; space_list = astMalloc( sizeof(AstRegion *)*(size_t)nspace ); if( space_list ) { for( ispace = 0; ispace < nspace; ispace++ ) { name = astXmlGetName( scan->el[ 0 ][ ispace ] ); if( !strcmp( name, "Sphere" ) ) { space_list[ ispace ] = SphereReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( !strcmp( name, "PositionInterval" ) ) { space_list[ ispace ] = PositionIntervalReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( !strcmp( name, "Region" ) ) { space_list[ ispace ] = StcRegionReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): " "SpatialInterval type %s not yet supported " "(AST internal programming error).", status, name ); break; } /* Store any uncertainty region.*/ if( uncs[ 0 ] ) astSetUnc( space_list[ ispace ], uncs[ 0 ] ); } /* If the spatial region is a single point we will use the point as the reference position for any SpecFrames which are created. If there is just one spatial interval, and if it is bounded. and if the bounds are equal on both axes, note the mean position. */ if( nspace == 1 ){ if( astGetBounded( space_list[ 0 ] ) ) { astGetRegionBounds( space_list[ 0 ], lbnd, ubnd ); if( astEQUAL( lbnd[ 0 ], ubnd[ 0 ] ) && astEQUAL( lbnd[ 1 ], ubnd[ 1 ] ) ) { space_val[ 0 ] = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); space_val[ 1 ] = 0.5*( lbnd[ 1 ] + ubnd[ 1 ] ); } } } } /* Create Regions for all the TimeIntervals found in the supplied element. */ time_val = AST__BAD; ntime = scan->count[ 1 ]; time_list = astMalloc( sizeof(AstRegion *)*(size_t)ntime ); if( time_list ) { for( itime = 0; itime < ntime; itime++ ) { time_list[ itime ] = TimeIntervalReader( this, scan->el[ 1 ][ itime ], time_frame, status ); /* Store any uncertainty region. Transfer the System and TimeOrigin values from the time region to the time uncertainty, if set. */ if( uncs[ 1 ] ) { if( astTestSystem( time_frame ) && astTestTimeOrigin( time_frame ) ) { sprintf( setting, "System=%s", astGetC( time_frame, "System" ) ); astRegSetAttrib( uncs[ 1 ], setting, NULL ); if( astTestUnit( time_frame, 0 ) ) { old_units = astGetUnit( time_frame, 0 ); old_units = astStore( NULL, old_units, strlen( old_units ) + 1 ); } else { old_units = NULL; } astSetUnit( time_frame, 0, astGetUnit( uncs[ 1 ], 0 ) ); sprintf( setting, "TimeOrigin=%s", astGetC( time_frame, "TimeOrigin" ) ); astRegSetAttrib( uncs[ 1 ], setting, NULL ); if( old_units ) { astSetUnit( time_frame, 0, old_units ); old_units = astFree( (void *) old_units ); } else { astClearUnit( time_frame, 0 ); } } astSetUnc( time_list[ itime ], uncs[ 1 ] ); } } /* Use the mid point as the Epoch for all Frames which are created. If either limit is not specified, use the specified limit. */ if( ntime > 0 ){ astGetRegionBounds( time_list[ 0 ], lbnd, ubnd ); if( fabs( lbnd[ 0 ] ) != DBL_MAX && lbnd[ 0 ] != AST__BAD ){ if( fabs( ubnd[ 0 ] ) != DBL_MAX && ubnd[ 0 ] != AST__BAD ){ time_val = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); } else { time_val = lbnd[ 0 ]; } } else if( fabs( ubnd[ 0 ] ) != DBL_MAX && ubnd[ 0 ] != AST__BAD ){ time_val = ubnd[ 0 ]; } } } /* Create Regions for all the SpectralIntervals found in the supplied element. */ spec_val = AST__BAD; nspec = scan->count[ 2 ]; spec_list = astMalloc( sizeof(AstRegion *)*(size_t)nspec ); if( spec_list ) { for( ispec = 0; ispec < nspec; ispec++ ) { spec_list[ ispec ] = SpectralIntervalReader( this, scan->el[ 2 ][ ispec ], spec_frame, status ); /* Store any uncertainty region.*/ if( uncs[ 2 ] ) astSetUnc( spec_list[ ispec ], uncs[ 2 ] ); } /* If the spectral region is a single point we will use the point as the rest frequency for all RedShift Frames which are created. If there is just one spectral interval, and if it is bounded. and if the bounds are equal, note the mean spectral value. */ if( nspec == 1 ){ if( astGetBounded( spec_list[ 0 ] ) ) { astGetRegionBounds( spec_list[ 0 ], lbnd, ubnd ); if( astEQUAL( lbnd[ 0 ], ubnd[ 0 ] ) ) { spec_val = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); } } } } /* Create Regions for all the RedshiftIntervals found in the supplied element. */ nred = scan->count[ 3 ]; red_list = astMalloc( sizeof(AstRegion *)*(size_t)nred ); if( red_list ) { for( ired = 0; ired < nred; ired++ ) { red_list[ ired ] = RedshiftIntervalReader( this, scan->el[ 3 ][ ired ], red_frame, status ); /* Store any uncertainty region.*/ if( uncs[ 3 ] ) astSetUnc( red_list[ ired ], uncs[ 3 ] ); } } /* Free the can result structure.*/ scan = FreeIVOAScan( scan, status ); /* If the spatial regions cover only a single point, convert it to FK5 J2000 and use it as the reference position for any SpecFrames (spectral or redshift) unless values were inherited from the supplied Frame. If the supplied Frame did not contain set values for these attributes, set them now. Use astRegSetAttrib which applies the attribute setting to both base and current Frame of the Region's FrameSet, and avoids re-mapping the current Frame. */ if( astOK ) { if( space_val[ 0 ] != AST__BAD && space_val[ 1 ] != AST__BAD ) { /* First need to convert to FK5 J2000 and format into a string for use with astRegSetAttrib. Need to ensure that the Format and Digits attributes are set to values which will result in no loss of precision in the formatting and unformatting steps. */ fr = astCopy( space_frame ); astClear( fr, "Format(1),Format(2),Digits(1),Digits(2)" ); astSet( fr, "digits=%d,system=FK5,equinox=J2000", status, DBL_DIG); fs = astConvert( space_frame, fr, "" ); fr = astAnnul( fr ); if( fs ) { astTran2( fs, 1, space_val, space_val + 1, 1, &raref, &decref ); text = astFormat( fs, raref, 0 ); l = text ? strlen( text ) : 0; raset = astMalloc( l + 10 ); if( raset ) sprintf( raset, "refra=%s", text ); text = astFormat( fs, decref, 1 ); l = text ? strlen( text ) : 0; decset = astMalloc( l + 10 ); if( decset ) sprintf( decset, "refdec=%s", text ); fs = astAnnul( fs ); /* Now set the FK5 J2000 values in the required Frames and Regions. */ if( !spec_frame || !astTestRefRA( spec_frame ) || !astTestRefDec( spec_frame ) ) { for( ispec = 0; ispec < nspec; ispec++ ) { astRegSetAttrib( spec_list[ ispec ], raset, NULL ); astRegSetAttrib( spec_list[ ispec ], decset, NULL ); } if( spec_frame ) { astSetRefRA( (AstSpecFrame *) spec_frame, raref ); astSetRefDec( (AstSpecFrame *) spec_frame, decref ); } } if( !red_frame || !astTestRefRA( red_frame ) || !astTestRefDec( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], raset, NULL ); astRegSetAttrib( red_list[ ired ], decset, NULL ); } if( red_frame ) { astSetRefRA( (AstSpecFrame *) red_frame, raref ); astSetRefDec( (AstSpecFrame *) red_frame, decref ); } } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, raset, NULL ); astRegSetAttrib( r, decset, NULL ); r = astAnnul( r ); } } } /* Free resources. */ if( raset ) raset = astFree( raset ); if( decset ) decset = astFree( decset ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan):" " Cannot convert spatial position to FK5 J2000" , status); } } /* If a time region was specified, use a typical value as the epoch for all Frames. Call MakeMJD to convert "time_val" from the system of the TimeFrame to an MJD (as required by the Frame Epoch attribute). Set the value in both the returned Region and the supplied Frame. */ if( time_val != AST__BAD ) { fr = astRegFrame( time_list[ 0 ] ); if( astIsATimeFrame( fr ) ) { time_val = MakeMJD( (AstTimeFrame *) fr, time_val, status ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( fr ) ); } fr = astAnnul( fr ); sprintf( buff, "epoch= MJD %.*g", DBL_DIG, time_val ); if( !space_frame || !astTestEpoch( space_frame ) ) { for( ispace = 0; ispace < nspace; ispace++ ) { astRegSetAttrib( space_list[ ispace ], buff, NULL ); } if( space_frame ) astSetEpoch( space_frame, time_val ); } if( !spec_frame || !astTestEpoch( spec_frame ) ) { for( ispec = 0; ispec < nspec; ispec++ ) { astRegSetAttrib( spec_list[ ispec ], buff, NULL ); } if( spec_frame ) astSetEpoch( spec_frame, time_val ); } if( !red_frame || !astTestEpoch( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], buff, NULL ); } if( red_frame ) astSetEpoch( red_frame, time_val ); } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, buff, NULL ); r = astAnnul( r ); } } } } /* If the spectral regions cover only a single point, format it with its units so that the astSetAttrib function can convert it to Hz and use it as the rest frequency for any redshift Frames. */ if( spec_val != AST__BAD && nred > 0 ) { text = astGetUnit( spec_frame, 0 ); if( text ) sprintf( buff, "restfreq= %.*g %s", DBL_DIG, spec_val, text ); if( !red_frame || !astTestRestFreq( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], buff, NULL ); } if( red_frame ) astSetAttrib( red_frame, buff ); } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, buff, NULL ); r = astAnnul( r ); } } } } /* Create Regions corresponding to every possible combination of interval on each axis type, and assemble the union of these into a CmpRegion (if there is more than one). */ sum = NULL; /* Initialise indices of the sub-Frame intervals to use. */ ispace = 0; itime = 0; ispec = 0; ired = 0; /* Loop over all possible combinations of time+space+spec+red intervals. */ while( 1 ) { rspace = ( ispace < nspace ) ? space_list[ ispace ] : NULL; rtime = ( itime < ntime ) ? time_list[ itime ] : NULL; rspec = ( ispec < nspec ) ? spec_list[ ispec ] : NULL; rred = ( ired < nred ) ? red_list[ ired ] : NULL; /* Prism Regions extrude a Region into higher dimensions, and the extrusion is defined by an Interval. Spatial Regions are not restricted to Intervals and so any spatial Region must be the first Region to be included in the Prism (all the other axis types *are* restricted to Intervals and so can be used to extrude the spatial region). */ reg = rspace ? astClone( rspace ) : NULL; /* Now extrude this region (if any) into the time axis. */ if( rtime ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rtime, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rtime ); } } /* Now extrude this region (if any) into the spectral axis. */ if( rspec ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rspec, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rspec ); } } /* Now extrude this region (if any) into the redshift axis. */ if( rred ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rred, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rred ); } } /* If a Prism was created, add it into the CmpRegion which holds the running sum of the union of all Prisms created so far. */ if( reg ) { if( !sum ) { sum = astClone( reg ); } else { tmp = (AstRegion *) astCmpRegion( sum, reg, AST__OR, "", status ); (void) astAnnul( sum ); sum = tmp; } reg = astAnnul( reg ); } /* Increment the indices of the next set of sub-Frame Intervals to use. Leave the while loop when all combinations have been done. */ if( ++ired >= nred ) { ired = 0; if( ++ispec >= nspec ) { ispec = 0; if( ++itime >= ntime ) { itime = 0; if( ++ispace >= nspace ) break; } } } } /* Simplify the total sum Region. */ tmp = astSimplify( sum ); (void) astAnnul( sum ); sum = tmp; /* The axes in this sum Region may not be in the correct order or units (i.e in the order and units specified in the supplied Frame). So use astConvert to get a Mapping from the Frame represented by the sum Region to the supplied Frame. */ fs = astConvert( sum, frm, "" ); if( fs ) { /* Unless the Mapping is a UnitMap, remap the sum Region into the supplied Frame using this Mapping. */ map = astGetMapping( fs, AST__BASE, AST__CURRENT ); if( !astIsAUnitMap( map ) ) { new = astMapRegion( sum, map, frm ); } else { new = astClone( sum ); } map = astAnnul( map ); fs = astAnnul( fs ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(%s): Cannot " "convert from supplied Frame to internal Frame (AST " "internal programming error).", status, astGetClass( this ) ); } /* Transfer selected properties from the supplied Frame to the current Frame of the returned Region. */ cfrm = astRegFrame( new ); if( astTestIdent( frm ) ) astSetIdent( cfrm, astGetIdent( frm ) ); if( astTestTitle( frm ) ) astSetTitle( cfrm, astGetTitle( frm ) ); /* Ensure the Epoch is set correctly in the Region */ if( time_val != AST__BAD ) { sprintf( buff, "epoch= MJD %.*g", DBL_DIG, time_val ); astRegSetAttrib( new, buff, NULL ); } /* Free resources. */ cfrm = astAnnul( cfrm ); sum = astAnnul( sum ); } if( space_list ) { for( i = 0; i < nspace; i++ ) space_list[ i ] = astAnnul( space_list[ i ] ); space_list = astFree( space_list ); } if( time_list ) { for( i = 0; i < ntime; i++ ) time_list[ i ] = astAnnul( time_list[ i ] ); time_list = astFree( time_list ); } if( spec_list ) { for( i = 0; i < nspec; i++ ) spec_list[ i ] = astAnnul( spec_list[ i ] ); spec_list = astFree( spec_list ); } if( red_list ) { for( i = 0; i < nred; i++ ) red_list[ i ] = astAnnul( red_list[ i ] ); red_list = astFree( red_list ); } } if( space_frame ) space_frame = astAnnul( space_frame ); if( time_frame ) time_frame = astAnnul( time_frame ); if( spec_frame ) spec_frame = astAnnul( spec_frame ); if( red_frame ) red_frame = astAnnul( red_frame ); /* Get the ID attribute from the AstroCoordArea element and store in the returned Region. */ id = astXmlGetAttributeValue( elem, "ID" ); if( id ) astSetIdent( new, id ); } /* If an error has occurred,annul the returned pointer. */ if( !astOK ) new = astAnnul( new ); /* Return the pointer to the new Region. */ return new; } static int AstroCoordsReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, AstRegion *uncs[4], AstKeyMap **anc, int *status ) { /* * Name: * AstroCoordsReader * Purpose: * Modify a Frame to take account of an IVOA AstroCoords element, and * return an coordinate uncertainties. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * int AstroCoordsReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, AstRegion *uncs[4], * AstKeyMap **anc, int *status ) * Class Membership: * XmlChan member function. * Description: * This function modifies the supplied Frame object to incorporate the * effects of the supplied AstroCoords element. It may also return * Regions representing the bounds of the uncertainties in the four * component coordinate Frames, depending on the contents of the * AstroCoords element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AstroCoords element. * frm * The Frame object to modify. * uncs * Array in which to return pointers to the uncertainty Regions to * be associated with each of the four STC domains (space, time, * spectral, redshift). NULL is returned in any element for which * no uncertainty is specified within the supplied AstroCoords element. * anc * Address of a location at which to store the pointer to a newly * created KeyMap holding ancillary information describing the * AstroCoords element in the form required by constructors of AST * Stc objects. A NULL pointer is returned if no usable ancillary * information is found in the AstroCoords. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if any non-NULL values have been returned in the "uncs" * array. Zero otherwise. */ /* Local Variables: */ AstFrame *afrm; /* Pointer to axis Frame */ AstFrame *gfrm; /* Pointer to generic Frame */ AstFrame *pfrm; /* Pointer to position Frame */ AstFrame *rfrm; /* Pointer to redshift Frame */ AstFrame *sfrm; /* Pointer to spectral Frame */ AstTimeFrame *tfrm; /* Pointer to time Frame */ AstKeyMap *panc; /* KeyMap holding spatial ancillary data */ AstKeyMap *ranc; /* KeyMap holding redshift ancillary data */ AstKeyMap *sanc; /* KeyMap holding spectral ancillary data */ AstKeyMap *tanc; /* KeyMap holding temporal ancillary data */ AstObject *o; /* Pointer to object retrieved from KeyMap */ AstRegion *r; /* Individual ancillary Region */ AstRegion *t; /* Total extruded ancillary Region */ AstRegion *tt; /* Temporary Region pointer */ AstXmlElement *el; /* Pointer to Position2D element */ IVOAScan *scan; /* Structure holding scan results */ char **anames; /* Pointer to list of ancillary name pointers */ const char *dom; /* Pointer to Domain attribute value */ const char *nam; /* Pointer to ancillary Name string */ const char *names[4]; /* Names of the subelements to be searched for */ char buff[100]; /* Message buffer */ double epoch; /* Epoch */ double hi; /* High limit for zero-width interval */ double lo; /* Low limit for zero-width interval */ double pos[2]; /* Reference spatial position */ double rf; /* Rest frequency */ int axes[2]; /* Indices of position axes */ int axis; /* Index of next axis to use */ int empty; /* Is returned KeyMap empty? */ int i; /* Loop count */ int isearth; /* Does the SkyFrame represent terrestrial lon/lat? */ int junk; /* Unused integer value */ int max[4]; /* Max allowed occurrences of each name */ int min[4]; /* Min allowed occurrences of each name */ int nax; /* Number of axes in supplied Frame */ int unc; /* Any uncertainty Regions found? */ int use; /* Use ancillary information? */ static const char *key[ 5 ] = { AST__STCERROR, AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE }; /* Initialise */ unc = 0; uncs[ 0 ] = NULL; uncs[ 1 ] = NULL; uncs[ 2 ] = NULL; uncs[ 3 ] = NULL; *anc = NULL; /* Check the global error status. */ if ( !astOK ) return unc; /* Search the supplied element for the required sub-elements. */ names[ 0 ] = "Position2D|Position3D"; names[ 1 ] = "Time"; names[ 2 ] = "Spectral"; names[ 3 ] = "Redshift"; min[ 0 ] = 0; min[ 1 ] = 0; min[ 2 ] = 0; min[ 3 ] = 0; max[ 0 ] = 1; max[ 1 ] = 1; max[ 2 ] = 1; max[ 3 ] = 1; scan = ScanIVOAElement( this, elem, 4, names, min, max, status ); /* If succesfull.. */ if( scan ) { /* Initialise pointers to component Frames */ pfrm = NULL; tfrm = NULL; sfrm = NULL; rfrm = NULL; /* Initialise pointers to KeyMaps holding ancillary data. */ panc = NULL; tanc = NULL; sanc = NULL; ranc = NULL; /* Allocate storage for an array of pointers to strings holding the Name value for each axis. Initialise them to a null string. */ nax = astGetNaxes( frm ); anames = astMalloc( sizeof( char * )*(size_t)nax ); for( i = 0; i < nax; i++ ) anames[ i ] = NULL; /* Initialise the index of the next Frame axis to use. */ axis = 0; /* Check to see if the next 2 axes describe positions on the sky or earth (see SpaceFrameReader). */ axes[ 0 ] = 0; axes[ 1 ] = 1; afrm = astPickAxes( frm, 2, axes, NULL ); dom = astGetDomain( afrm ); isearth = dom && ( !strcmp( dom, "GEO_D" ) || !strcmp( dom, "GEO_C" ) ); if( isearth || ( dom && !strcmp( dom, "SKY" ) ) ){ astPrimaryFrame( frm, axis, &pfrm, &junk ); if( scan->count[ 0 ] ) { /* We currently also use SkyFrames to represent geographical long/lat used to describe observatory positions. These may have 3D positions, in which case we convert the 3D position to a 2D position by ignoring the 3rd axis value (height). See SpaceFrameReader. */ el = MakePos2D( this, scan->el[ 0 ][ 0 ], status ); /* Use the Position2D to create a Region describing the uncertainty in the space axes of the Frame. Also create a KeyMap holding Regions describing any ancillary information stored in the Position2D. */ uncs[ 0 ] = Position2DReader( this, el, pfrm, pos, &panc, status ); if( uncs[ 0 ] ) unc = 1; el = astXmlDelete( el ); /* If ancillary information was returned, extract the Name element, and store it twice (once for each axis) in the "names" array. */ if( panc && astMapGet0C( panc, AST__STCNAME, &nam ) ) { anames[ axis ] = astStore( NULL, nam, strlen( nam ) + 1 ); anames[ axis + 1 ] = astStore( NULL, nam, strlen( nam ) + 1 ); nam = astFree( (void *) nam ); } } /* Increment the axis index. */ axis += 2; /* If the supplied Frame has no sky frame, but we found a Position2D, then report a warning and ignore the Position2D. */ } else if( scan->count[ 0 ] ) { sprintf( buff, "contains a <%s> which is not being used.", astXmlGetName( scan->el[ 0 ][ 0 ] ) ); Report( this, elem, WARNING, buff, status ); } afrm = astAnnul( afrm ); /* Indicate we do not yet have an epoch to use. */ epoch = AST__BAD; /* Check to see if the Frame contains a time frame. It will be the next axis if it does. */ afrm = astPickAxes( frm, 1, &axis, NULL ); dom = astGetDomain( afrm ); if( dom && !strcmp( dom, "TIME" ) ){ astPrimaryFrame( frm, axis, &gfrm, &junk ); /* Report an error if it is not an AST TimeFrame. */ if( !astIsATimeFrame( gfrm ) && astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( pfrm ) ); } else { tfrm = (AstTimeFrame *) gfrm; } /* Use any Time element to create a Region describing the uncertainty in the time axis of the Frame. Also create a KeyMap holding Regions describing any ancillary information stored in the Time element. */ if( scan->count[ 1 ] ) { uncs[ 1 ] = TimeReader( this, scan->el[ 1 ][ 0 ], tfrm, &epoch, &tanc, status ); if( uncs[ 1 ] ) unc = 1; /* If ancillary information was returned, extract the Name element, and store it in the "names" array. */ if( tanc && astMapGet0C( tanc, AST__STCNAME, &nam ) ) { anames[ axis ] = astStore( NULL, nam, strlen( nam ) + 1 ); nam = astFree( (void *) nam ); } } /* Increment the index of the next axis to use. */ axis++; /* If the supplied Frame has no time frame, but we found a Time element, then report a warning and ignore the Time element. */ } else if( scan->count[ 1 ] ) { Report( this, elem, WARNING, "contains a